Mengapa Perubahan Skema Database Perbutuh Disiplin yang Sama Seperti Kode
Bayangkan ini: tim Anda baru saja melakukan deploy fitur baru. Kode aplikasi berjalan dengan baik. Namun lima menit kemudian, error mulai bermunculan. Sebuah kolom yang diharapkan oleh kode baru ternyata belum ada. Atau lebih buruk lagi, sebuah kolom yang sudah dihapus masih di-query oleh layanan lama yang belum diperbarui. Database berada dalam keadaan tidak konsisten, dan tidak ada yang bisa menjelaskan dengan pasti apa yang terjadi atau bagaimana cara memperbaikinya dengan cepat.
Skenario ini lebih umum daripada yang diakui kebanyakan tim. Akar penyebabnya hampir selalu sama: skema database diubah secara manual, tanpa proses yang dapat diulang, dan tanpa koordinasi dengan kode aplikasi yang bergantung padanya.
Perbedaan Mendasar Antara Kode dan Skema
Kode aplikasi bersifat stateless. Saat Anda melakukan deploy versi baru, file lama akan diganti. Jika terjadi kesalahan, Anda dapat melakukan rollback ke versi sebelumnya, dan server kembali ke kondisi yang diketahui. Tidak ada data sisa, tidak ada dependensi tersembunyi.
Database adalah kebalikannya. Mereka bersifat stateful secara alami. Setiap tabel, kolom, indeks, dan constraint menyimpan data yang telah terakumulasi seiring waktu. Saat Anda mengubah skema, Anda tidak hanya mengganti file. Anda mengubah struktur yang menampung data yang sudah ada. Kolom baru mungkin memerlukan nilai default untuk baris yang sudah ada. Kolom yang dihapus mungkin menghilangkan data yang masih diandalkan oleh bagian lain dari sistem. Indeks baru mungkin membutuhkan waktu menit atau jam untuk dibangun pada tabel besar.
Sifat stateful ini membuat perubahan skema secara inheren lebih berisiko daripada perubahan kode. Deployment yang buruk dapat di-rollback dalam hitungan detik. Migrasi yang buruk dapat merusak data, memutus query, atau bahkan melumpuhkan seluruh sistem. Dan karena database digunakan bersama oleh banyak layanan dan lingkungan, radius ledakannya jauh lebih besar.
Cara Lama: Manual, Rapuh, Tidak Dapat Diulang
Untuk waktu yang lama, perubahan database diperlakukan sebagai alur kerja manual yang terpisah. Seorang DBA atau pengembang senior akan login ke server database produksi, menjalankan beberapa perintah SQL, dan menunggu. Jika migrasi berhasil, bagus. Jika gagal, mereka akan mencoba memperbaikinya di tempat, seringkali tanpa catatan yang jelas tentang apa yang telah dilakukan.
Pendekatan ini memiliki beberapa masalah:
- Tidak dapat diulang. Langkah-langkah pastinya tergantung pada siapa yang menjalankannya, apa yang mereka ingat, dan apa yang mereka perhatikan selama eksekusi. Migrasi yang sama mungkin dilakukan secara berbeda oleh dua orang yang berbeda.
- Tidak dapat diaudit. Tidak ada riwayat perubahan, kapan, dan oleh siapa. Jika sesuatu rusak beberapa hari kemudian, melacak penyebabnya hampir tidak mungkin.
- Rapuh. Satu langkah yang terlupakan atau urutan eksekusi yang salah dapat membuat database dalam keadaan tidak konsisten. Pemulihan menjadi latihan manual dengan tekanan tinggi.
- Menghambat kolaborasi. Hanya sedikit orang yang memiliki akses dan pengetahuan untuk menjalankan migrasi. Anggota tim lainnya tidak dapat meninjau, menguji, atau berkontribusi pada perubahan skema.
Seiring pertumbuhan tim dan sistem menjadi lebih kompleks, pendekatan manual ini menjadi hambatan dan risiko. Setiap deployment yang melibatkan perubahan skema menjadi peristiwa yang penuh kecemasan.
Perlakukan Perubahan Skema Seperti Kode
Solusinya sederhana: kelola perubahan skema database dengan disiplin yang sama seperti yang Anda gunakan untuk kode aplikasi. Praktik ini disebut schema migration, dan dibangun di atas beberapa prinsip sederhana.
Tulis setiap perubahan sebagai skrip migrasi. Skrip migrasi adalah file yang berisi perintah SQL yang diperlukan untuk mengubah skema database. Ini bisa menambahkan kolom, membuat tabel, menambahkan indeks, atau mengubah constraint. Setiap skrip mewakili satu perubahan logis.
Sebagai contoh, alih-alih login ke produksi dan menjalankan:
ALTER TABLE users ADD COLUMN phone VARCHAR(20);
Anda akan membuat file migrasi seperti ini:
-- V001__add_phone.sql
-- Forward migration
ALTER TABLE users ADD COLUMN phone VARCHAR(20);
Dan file rollback yang sesuai:
-- V001__add_phone_rollback.sql
-- Rollback migration
ALTER TABLE users DROP COLUMN phone;
File-file ini berada di repositori Anda, ditinjau dalam pull request, dan dieksekusi secara otomatis oleh deployment pipeline Anda. Tidak ada langkah manual, tidak ada perintah yang terlupakan, tidak ada misteri.
Simpan skrip migrasi di repositori yang sama dengan kode aplikasi. Ini memastikan bahwa perubahan skema diberi versi bersama dengan kode yang bergantung padanya. Saat Anda checkout versi kode tertentu, Anda juga memiliki skrip migrasi yang tepat yang digunakan untuk membuat skema untuk versi tersebut.
Jangan pernah mengedit skrip migrasi yang sudah ada. Jika Anda perlu melakukan perubahan, buat skrip baru. Ini menjaga riwayat tetap utuh dan memastikan urutan eksekusi jelas. Alat migrasi biasanya menggunakan nomor versi atau timestamp untuk menentukan skrip mana yang sudah dijalankan dan mana yang masih tertunda.
Jalankan migrasi sebagai bagian dari deployment pipeline. Sama seperti menjalankan tes atau membangun artefak, menerapkan perubahan skema harus menjadi langkah otomatis dalam pipeline CI/CD Anda. Ini menghilangkan ketergantungan pada eksekusi manual dan memastikan bahwa setiap lingkungan mendapatkan perubahan yang sama dalam urutan yang sama.
Tinjau skrip migrasi seperti kode. Sebelum skrip migrasi digabungkan, skrip tersebut harus melalui code review. Anggota tim dapat memeriksa potensi masalah: nilai default yang hilang, operasi yang berjalan lama, atau perubahan yang dapat merusak query yang ada. Ini menangkap masalah sebelum mencapai produksi.
Mengapa Ini Penting dalam Praktik
Ketika perubahan skema dikelola seperti kode, proses deployment menjadi dapat diprediksi. Tim tahu persis apa yang akan terjadi ketika migrasi dijalankan. Mereka dapat mengujinya di lingkungan staging terlebih dahulu. Mereka dapat melakukan rollback jika terjadi kesalahan, karena setiap skrip migrasi memiliki skrip rollback yang sesuai. Mereka dapat melacak setiap perubahan skema kembali ke commit yang memperkenalkannya.
Lebih penting lagi, pendekatan ini mengurangi ketakutan akan deployment. Perubahan skema tidak lagi menjadi aktivitas terpisah yang berisiko tinggi. Mereka menjadi bagian normal dari alur kerja pengembangan, ditinjau dan diuji seperti perubahan kode lainnya. Database tidak lagi menjadi kotak hitam yang hanya bisa disentuh oleh beberapa orang.
Daftar Periksa Praktis untuk Schema Migrations
Sebelum Anda menggabungkan skrip migrasi, jalankan daftar periksa singkat ini:
- Apakah migrasi memiliki skrip rollback yang sesuai?
- Dapatkah migrasi dijalankan beberapa kali tanpa menyebabkan error (idempoten)?
- Apakah migrasi akan mengunci tabel untuk waktu yang lama? Jika ya, pertimbangkan batching atau menggunakan alat perubahan skema online.
- Apakah ada query atau kode yang ada yang mungkin rusak setelah perubahan ini?
- Sudahkah Anda menguji migrasi terhadap salinan data produksi?
- Apakah skrip migrasi telah ditinjau oleh setidaknya satu anggota tim lainnya?
Kesimpulan
Skema database Anda bukanlah artefak statis. Ia berevolusi bersama aplikasi Anda. Memperlakukan perubahan skema sebagai operasi manual satu kali adalah resep untuk insiden produksi dan gesekan tim. Dengan mengelola migrasi skema dengan disiplin yang sama seperti kode, Anda membuat perubahan database dapat diulang, dapat diaudit, dan aman. Database berhenti menjadi sumber ketakutan dan menjadi bagian lain dari sistem yang dapat diubah dengan percaya diri oleh tim Anda.