Skip to content

Membalik Default Kolom: Saklar Perilaku untuk Baris Baru

Adityo Guni Waluyo

Mengubah DEFAULT satu kolom tercatat instan dan hanya menyentuh metadata. Yang perlu disiapkan justru jalur-jalur INSERT yang tidak ikut berubah.

Ringkasan

Jadi waktu itu fitur ulasan entitas baru nyala terus, padahal pengembangnya maunya mati dulu. Fixnya gampang banget: satu baris ALTER TABLE buat ubah default kolom rating_enabled jadi 0. Aman pas produksi karena cuma ubah metadata, data lama nggak disentuh, plus ada tes integrasi buat ngunci perilakunya.

Sebuah entitas baru muncul di sistem manajemen konten sebuah proyek portal wilayah dengan fitur ulasan aktif secara default. Tim pengembang sebenarnya menginginkan fitur tersebut nonaktif hingga setiap entitas diaktifkan secara sengaja. Solusinya terletak pada satu baris perubahan di berkas migrasi bernama api/migrations/000072_rating_default_off.up.sql. Perintah yang dijalankan adalah ALTER TABLE entities MODIFY COLUMN rating_enabled TINYINT(1) NOT NULL DEFAULT 0. Sebelumnya, kolom rating_enabled ini memiliki nilai default 1 sejak migrasi 000064.

Asumsi awal yang sering muncul adalah perintah ALTER TABLE akan mengunci tabel dan menyebabkan waktu henti pada layanan produksi. Namun, mengubah hanya nilai default sebuah kolom adalah operasi yang hanya memodifikasi metadata. Proses ini bersifat instan, tidak membangun ulang tabel, dan mengizinkan operasi manipulasi data berjalan secara bersamaan tanpa hambatan [7].

Hal ini masuk akal karena nilai default dibaca pada saat perintah INSERT dieksekusi, sehingga tidak ada penulisan ulang data yang diperlukan pada baris yang sudah ada [6].

Mekanisme Perubahan Metadata

Sistem manajemen basis data relasional menyediakan dua jalur untuk mengubah nilai default. Jalur pertama adalah ALTER [COLUMN] col SET DEFAULT literal. Jalur kedua adalah MODIFY COLUMN col yang menyertakan definisi kolom penuh [5]. Klausa DEFAULT menentukan nilai yang dipakai oleh perintah INSERT yang tidak menyertakan kolom tersebut, yang dapat berupa nilai literal atau ekspresi tertentu mulai versi 8.0.13 [6].

Alat migrasi skema seperti golang-migrate mengelola perubahan berbasis versi melalui berkas naik dan turun secara terstruktur [8]. Dua sintaks tersedia dan pilihannya bukan soal selera. ALTER COLUMN ... SET DEFAULT menyentuh bagian default saja, sementara MODIFY COLUMN menuliskan ulang definisi kolom secara utuh, termasuk tipe dan sifat NOT NULL [5]. Definisi penuh memberi ruang salah ketik yang mengubah tipe tanpa sengaja; kalau tujuannya cuma membalik default, jalur yang sempit lebih sulit tersasar. Dalam konteks ini, membalik nilai default kolom merupakan saklar perilaku paling murah untuk baris baru. Konsekuensinya justru terletak pada jalur-jalur yang tidak ikut berubah.

Penambahan kolom baru dengan nilai default pun kini tercatat instan pada tabel operasi DDL daring [7]. Keistimewaan membalik default memang bukan soal bebas rebuild semata, melainkan karena tidak ada satu baris data pun yang disentuh. Inilah alasan operasi ini aman dijalankan pada lingkungan produksi yang sibuk.

Konsekuensi pada Data dan Pengujian

Perubahan metadata ini membawa beberapa konsekuensi langsung yang tercatat dalam riwayat commit. Pertama, baris yang sudah ada sebelumnya tetap mempertahankan nilainya. Tidak ada proses pengisian ulang data, sesuai dengan desain yang tertulis dalam komentar migrasi bahwa entitas lama tetap pada keadaan semula.

Kedua, jalur INSERT yang secara eksplisit menyertakan kolom tersebut tidak terpengaruh. Itulah sebabnya utilitas pengujian menetapkan nilai rating_enabled=1 secara eksplisit agar fixture pengujian tetap menguji jalur aktif. Nilai default pada formulir wisata-editor.tsx juga dibalik dalam commit yang sama agar entitas yang dibuat melalui panel admin sesuai dengan harapan.

Ketiga, migrasi turun hanya mengembalikan nilai default menjadi 1 tanpa memulihkan data, karena migrasi naik tidak pernah menyentuh data sama sekali. Keduanya simetris berdasarkan konstruksi. Keempat, pengujian integrasi TestNewEntityDefaultsRatingOff yang terdiri dari 106 baris mengunci perilaku baru ini. Sebuah entitas baru tanpa penyertaan kolom akan dimulai dengan fitur ulasan dalam keadaan nonaktif.

Pengujian integrasi memainkan peran penting di sini. Tanpa uji yang mengunci perilaku baru, perubahan nilai default mudah lolos tak terdeteksi sampai anomali muncul di produksi. Uji sepanjang 106 baris itu mencakup validasi keadaan awal entitas baru dan respons sistem terhadap permintaan pembuatan data.

Saklar yang dimatikan secara default mencerminkan postur deny-by-default, di mana catatan baru harus memilih untuk ikut serta alih-alih memilih untuk keluar [1].

Baris lama tidak ikut berubah, dan itu keputusan yang disadari: entitas dengan ulasan aktif tetap aktif, tanpa backfill. Saklar ini hanya mengikat bagi entitas yang belum lahir. Jalur yang memang butuh perilaku lama, seperti seed pengujian atau alur impor, menetapkan nilai secara eksplisit. Ketika skema hanya butuh perubahan perilaku untuk data baru, mengganti DEFAULT adalah langkah pertama yang patut diambil sebelum menulis migrasi yang lebih berat.

Sumber

[1] Broken_Access_Control/index.html — OWASP Top 10:2021 A01 Broken Access Control

[5] table.html — MySQL 8.0 Reference Manual 15.1.9 ALTER TABLE Statement

[6] type-defaults.html — MySQL 8.0 Reference Manual 13.6 Data Type Default Values

[7] 8.0-en/innodb-online-ddl-operations.html — MySQL 8.0 Reference Manual 17.12.1 Online DDL Operations (Oracle mirror)

[8] migrate/migrate — golang-migrate/migrate: Database migrations. CLI and Golang library

Artikel terkait