Menambahkan Struktur Database Baru Tanpa Mengganggu Aplikasi yang Berjalan
Anda memiliki tabel users dengan kolom full_name. Tim produk ingin memisahkan nama menjadi first_name dan last_name untuk personalisasi yang lebih baik. Anda perlu melakukan perubahan ini tanpa mematikan aplikasi atau merusak fitur yang sudah ada.
Pendekatan yang umum adalah menghapus full_name, menambahkan dua kolom baru, dan memperbarui semua kode sekaligus. Namun, itu membutuhkan deployment yang terkoordinasi, downtime, dan rencana rollback yang sempurna jika terjadi kesalahan. Dalam praktiknya, perubahan semacam ini sering berujung pada rollback tengah malam dan pengguna yang marah.
Ada cara yang lebih aman: tambahkan struktur baru terlebih dahulu, tanpa menyentuh yang lama. Biarkan yang lama dan baru hidup berdampingan hingga Anda siap untuk beralih sepenuhnya.
Fase Expand: Tambah Tanpa Hapus
Pola expand-contract dimulai dengan langkah yang paling aman. Anda menambahkan kolom, tabel, atau constraint baru ke database sambil membiarkan semua yang sudah ada tetap utuh. Aplikasi lama yang masih berjalan dengan skema lama tidak akan melihat perbedaan apa pun. Kode baru dapat mulai menggunakan struktur baru segera.
Ini adalah inti dari fase expand: Anda memperkenalkan objek database baru tanpa mengubah atau menghapus yang sudah ada. Skema lama tetap berfungsi penuh. Skema baru adalah tambahan, bukan pengganti.
Diagram di bawah menunjukkan kondisi sebelum dan sesudah tabel users selama fase expand, serta bagaimana aplikasi lama dan baru berinteraksi dengan skema.
Contoh Konkret
Ambil tabel users dengan kolom full_name. Dalam fase expand, Anda menambahkan dua kolom baru:
Berikut SQL untuk menambahkan kolom baru:
ALTER TABLE users ADD COLUMN first_name VARCHAR(100) NULL;
ALTER TABLE users ADD COLUMN last_name VARCHAR(100) NULL;
ALTER TABLE users ADD COLUMN first_name VARCHAR(100) NULL;
ALTER TABLE users ADD COLUMN last_name VARCHAR(100) NULL;
Kolom full_name tetap seperti sedia kala. Aplikasi lama yang membaca full_name tetap berfungsi tanpa perubahan kode. Aplikasi baru dapat mulai menulis ke first_name dan last_name sambil tetap membaca full_name untuk kompatibilitas mundur.
Tidak ada downtime. Tidak ada rilis yang terkoordinasi. Tidak ada risiko merusak query yang sudah ada.
Aturan Kritis: Kolom Baru Harus Opsional
Kesalahan paling umum dalam fase expand adalah menambahkan kolom baru dengan NOT NULL tanpa nilai default. Ini langsung merusak aplikasi yang menyisipkan baris tanpa menyertakan kolom baru. Aplikasi lama yang tidak tahu kolom itu ada akan gagal pada setiap insert.
Aturannya sederhana: setiap kolom baru harus nullable atau memiliki nilai default yang masuk akal. Jika Anda membutuhkan constraint NOT NULL, tambahkan kolom sebagai nullable terlebih dahulu, backfill data, lalu tambahkan constraint di fase berikutnya. Jangan paksa semua aplikasi yang ada untuk mengubah pernyataan insert mereka secara bersamaan.
Logika yang sama berlaku untuk tabel baru. Tabel baru tidak mengubah struktur tabel yang sudah ada. Aplikasi lama tidak perlu tahu bahwa tabel itu ada. Aplikasi baru dapat mulai menulis ke tabel tersebut segera. Tidak ada konflik karena tidak ada yang berubah di tabel yang sudah mereka gunakan.
Menangani Constraint dengan Aman
Constraint memerlukan perhatian ekstra selama fase expand. Jika Anda menambahkan constraint UNIQUE pada kolom baru, pastikan data yang ada tidak melanggarnya. Jika Anda menambahkan FOREIGN KEY, pastikan semua baris yang ada merujuk ke baris induk yang valid.
Untuk constraint CHECK, verifikasi bahwa kondisinya tidak bertentangan dengan data yang ada. Beberapa database mendukung opsi NOT VALID yang menerapkan constraint hanya pada baris baru, memungkinkan Anda memvalidasi data yang ada secara terpisah nanti. Ini berguna jika Anda tidak yakin dengan kualitas data di baris lama.
Prinsipnya sama: jangan memperkenalkan constraint yang akan gagal terhadap data yang ada. Jika Anda tidak dapat menjaminnya, tunda constraint tersebut atau tambahkan dengan cara yang tidak memblokir operasi tulis.
Penamaan Itu Penting
Kolom dan tabel baru membutuhkan nama yang jelas yang membedakannya dari struktur lama. Hindari nama seperti name_new, temp_name, atau name_v2. Ini menciptakan kebingungan selama fase contract ketika Anda perlu tahu struktur mana yang kanonik.
Gunakan nama yang mendeskripsikan data sebenarnya. first_name dan last_name lebih baik daripada name_split_1 dan name_split_2. Nama yang baik memudahkan transisi bagi semua orang yang bekerja dengan skema nanti.
Apa yang Tidak Diperlukan oleh Fase Expand
Fase expand tidak memerlukan perubahan kode apa pun di aplikasi lama. Mereka terus menggunakan skema yang sama, query yang sama, dan logika yang sama. Inilah yang membuat fase expand aman untuk dijalankan kapan saja, bahkan selama jam produksi puncak.
Tidak ada downtime. Tidak ada restart aplikasi. Tidak ada query yang tiba-tiba gagal karena kolom menghilang. Satu-satunya perubahan adalah pada skema database, dan perubahan itu murni aditif.
Kapan Fase Expand Selesai
Fase expand selesai ketika struktur baru sudah ada di database dan siap digunakan. Aplikasi lama masih menggunakan struktur lama. Aplikasi baru dapat mulai menggunakan struktur baru. Kedua jalur bekerja secara bersamaan.
Pada titik ini, Anda memiliki database yang mendukung dua versi skema. Ini adalah fondasi untuk langkah berikutnya: secara bertahap memigrasikan aplikasi untuk menggunakan struktur baru tanpa merusak apa pun.
Daftar Periksa Praktis untuk Fase Expand
- Kolom baru nullable atau memiliki nilai default
- Tabel baru tidak mengubah struktur tabel yang sudah ada
- Constraint baru tidak bertentangan dengan data yang ada
- Nama dengan jelas membedakan struktur baru dari yang lama
- Aplikasi lama terus berfungsi tanpa perubahan kode
- Aplikasi baru dapat mulai menggunakan struktur baru segera
Intisari
Fase expand adalah perubahan database teraman yang dapat Anda lakukan karena hanya menambahkan. Tidak ada penghapusan, tidak ada modifikasi, tidak ada risiko merusak aplikasi yang berjalan. Tambahkan kolom baru sebagai nullable, biarkan kolom lama tetap utuh, dan biarkan kedua skema hidup berdampingan. Ini memberi Anda kebebasan untuk memigrasikan aplikasi sesuai kecepatan Anda sendiri, tanpa perlu mengoordinasikan rilis besar-besaran atau menjadwalkan downtime.