Saat Migrasi Database Bermasalah: Mengapa Roll Forward Lebih Baik dari Roll Back
Anda baru saja menjalankan migrasi database yang menambahkan kolom phone_number ke tabel users. Migrasi berhasil. Kemudian tim Anda menyadari bahwa kode aplikasi yang menggunakan kolom ini belum di-deploy. Setiap pendaftaran pengguna baru sekarang gagal karena kode lama mencoba melakukan INSERT tanpa menyediakan nilai untuk kolom NOT NULL yang baru.
Sistem produksi Anda rusak. Apa yang Anda lakukan?
Sebagian besar tim secara naluriah akan menjalankan down migration -- skrip yang membalikkan perubahan dan menghapus kolom tersebut. Namun naluri ini bisa menyebabkan lebih banyak kerusakan daripada masalah aslinya. Ada pendekatan yang lebih baik: roll forward.
Masalah dengan Down Migration
Down migration terlihat rapi di atas kertas. Anda menulis up migration yang menambahkan kolom, dan down migration yang menghapusnya. Jika terjadi kesalahan, Anda jalankan down migration dan semuanya kembali seperti semula.
Dalam praktiknya, down migration berbahaya karena beberapa alasan.
Pertama, kehilangan data hampir pasti terjadi. Jika ada baris yang dimasukkan atau diperbarui setelah up migration dijalankan, nilai-nilai tersebut akan hilang saat Anda menghapus kolom. Anda bisa kehilangan data pelanggan yang tidak bisa dipulihkan.
Kedua, down migration menciptakan ketidakcocokan antara kode aplikasi dan skema database. Jika kode aplikasi Anda sudah mengharapkan kolom baru tersebut ada, menghapusnya akan menyebabkan runtime error. Anda perlu men-deploy kode aplikasi lama juga, yang berarti mengoordinasikan beberapa rollback secara bersamaan.
Ketiga, down migration jarang diuji. Tim menulisnya sebagai renungan, seringkali dengan bug yang baru muncul saat keadaan darurat. Menjalankan skrip yang belum teruji di production saat outage adalah resep untuk downtime yang lebih lama.
Apa Itu Roll Forward?
Roll forward adalah strategi di mana Anda tidak pernah membalikkan migrasi. Sebaliknya, ketika migrasi menyebabkan masalah, Anda menulis migrasi baru yang memperbaiki masalah tersebut. Database bergerak maju menuju keadaan yang telah diperbaiki, bukan mundur ke keadaan sebelumnya.
Menggunakan contoh sebelumnya, alih-alih menjalankan down migration untuk menghapus phone_number, Anda menulis migrasi baru yang membuat kolom tersebut menjadi nullable atau menambahkan nilai default. Kolom tetap ada, tetapi constraint yang menyebabkan kegagalan dihapus. Pendaftaran pengguna baru berfungsi kembali, dan data apa pun yang sudah tersimpan di phone_number tetap dipertahankan.
Berikut adalah tampilan migrasi perbaikan tersebut dalam SQL:
-- version_002: perbaiki constraint phone_number
-- Migrasi ini membuat phone_number nullable sehingga kode aplikasi lama
-- dapat memasukkan baris tanpa menyediakan nilai.
ALTER TABLE users
ALTER COLUMN phone_number DROP NOT NULL;
Setiap migrasi menjadi perubahan kumulatif. Migrasi pertama menambahkan kolom. Migrasi kedua memperbaiki constraint kolom. Pelacak migrasi mencatat kedua perubahan secara berurutan, sehingga Anda dapat melihat bahwa version_002 mengoreksi version_001 tanpa menghapus riwayatnya.
Mengapa Tim Lebih Memilih Roll Forward
Keuntungan terbesarnya adalah tidak ada kehilangan data. Jika migrasi pertama Anda menyimpan 500 nomor telepon sebelum Anda menemukan masalahnya, nomor-nomor tersebut tetap ada setelah perbaikan. Down migration akan menghapusnya secara permanen.
Roll forward juga menjaga kode aplikasi dan skema database tetap selaras. Karena kolom masih ada, kode aplikasi apa pun yang membaca phone_number tetap berfungsi. Anda tidak perlu mengoordinasikan rollback kode secara bersamaan. Anda memperbaiki database, lalu memperbaiki kode aplikasi dengan kecepatan Anda sendiri.
Pendekatan ini mencerminkan cara tim menangani bug pada kode aplikasi. Ketika bug mencapai production, Anda tidak mengembalikan seluruh codebase ke versi minggu lalu. Anda mendorong perbaikan. Migrasi database harus bekerja dengan cara yang sama: perbaikannya adalah migrasi baru, bukan pembalikan.
Saat Roll Forward Menjadi Kompleks
Tidak semua perbaikan roll forward sesederhana mengubah constraint kolom. Pertimbangkan migrasi yang mengubah tipe data kolom dari VARCHAR menjadi INTEGER. Jika konversi memotong atau merusak data yang ada, migrasi perbaikan Anda mungkin perlu:
- Menambahkan kolom baru dengan tipe data asli
- Menyalin data dari kolom yang rusak, menerapkan transformasi untuk memulihkan nilai
- Memperbarui referensi kode aplikasi untuk menggunakan kolom baru
- Menghapus kolom yang rusak dalam migrasi selanjutnya
Ini lebih banyak pekerjaan daripada down migration sederhana. Tapi ini juga lebih aman. Anda dapat menjalankan migrasi perbaikan di staging terlebih dahulu, memverifikasi logika pemulihan data, dan baru menerapkannya ke production. Down migration tidak memberikan jaring pengaman seperti itu -- ia hanya menghapus kolom dan berharap yang terbaik.
Poin utamanya adalah roll forward tidak mengharuskan Anda memprediksi setiap kemungkinan kegagalan sebelum deployment. Anda hanya perlu percaya bahwa jika terjadi kesalahan, tim Anda dapat menulis perbaikan. Ini menggeser risiko dari pencegahan (yang tidak mungkin sempurna) ke pemulihan (yang merupakan keterampilan yang bisa Anda latih).
Daftar Periksa Praktis untuk Roll Forward
Sebelum Anda berkomitmen pada roll forward sebagai strategi tim Anda, pastikan praktik-praktik ini sudah diterapkan:
Gunakan diagram keputusan ini ketika migrasi menyebabkan masalah:
- Setiap migrasi harus dapat dibalikkan secara teori, tetapi tidak harus dalam kode. Pahami apa yang akan dilakukan down migration, tetapi jangan menulisnya kecuali Anda memiliki alasan spesifik untuk membutuhkannya.
- Uji migrasi perbaikan Anda di staging terlebih dahulu. Jalankan migrasi asli, perkenalkan skenario kegagalan, lalu terapkan migrasi perbaikan. Verifikasi integritas data setelahnya.
- Jaga pelacak migrasi Anda tetap andal. Jangan pernah memodifikasi atau menghapus catatan migrasi secara manual. Pelacak adalah jejak audit Anda untuk memahami apa yang berubah dan kapan.
- Dokumentasikan mode kegagalan. Saat Anda menulis migrasi perbaikan, tambahkan komentar yang menjelaskan apa yang salah dan mengapa perbaikan berhasil. Ini membantu anggota tim di masa depan yang menghadapi pola serupa.
- Latih skenario roll forward. Jalankan drill triwulanan di mana seseorang sengaja memperkenalkan migrasi yang buruk, dan tim berlatih menulis dan men-deploy perbaikan di bawah tekanan waktu.
Kesimpulan
Down migration adalah jebakan. Mereka menjanjikan kesederhanaan tetapi memberikan kehilangan data, sakit kepala koordinasi, dan skrip darurat yang belum teruji. Roll forward memperlakukan perubahan database seperti perubahan kode: ketika sesuatu rusak, Anda memperbaikinya ke depan, bukan ke belakang.
Lain kali migrasi bermasalah, tahan keinginan untuk membalikkan. Tulislah migrasi perbaikan sebagai gantinya. Data, aplikasi, dan kewarasan tim Anda akan berterima kasih.