
Bayangkan Oracle DBA. Dia sudah lebih dari tiga puluh tahun, dia sedikit kelebihan berat badan, mengenakan rompi, dia memiliki tanda akses rahasia ke semua pangkalan yang tergantung di lehernya, dan dalam ringkasan setengah halaman dari sertifikasi yang dia lewati. Sabtu Hari rilis besar. Klimaks. Saatnya melempar perubahan ke basis data. Dia mengetik sqlplus, menekan ENTER, dan suatu tempat layar hitam ke dalam kekosongan, kilometer dari perintah SQL terburu-buru. Sama seperti dalam perang bintang. Lima menit kemudian, semuanya sudah siap. Satu jam kemudian, rilisnya selesai. Pekerjaan selesai, hari itu sukses. Sekarang Anda dapat memiliki beberapa gelas bir.
Hal lain adalah hari Senin. Ternyata beberapa perintah tidak dieksekusi karena kesalahan, yang, bagaimanapun, tidak menghentikan skrip dalam mengejar kekosongan hitam yang tak terkendali. Tugas yang sudah sulit untuk mencari tahu apa yang rusak adalah rumit oleh beberapa tekanan dari kepemimpinan. Secara umum, Senin tidak berhasil.
Tentu saja, ini adalah cerita fiksi. Ini tidak pernah terjadi pada siapa pun. Setidaknya, itu tidak akan terjadi jika pekerjaan mengubah skema basis data telah diselenggarakan melalui migrasi.
Apa itu alat migrasi basis data?
Gagasan mengelola perubahan skema database melalui migrasi sangat sederhana:
- Setiap perubahan dikeluarkan sebagai file migrasi terpisah.
- File migrasi mencakup perubahan langsung dan mundur.
- Aplikasi migrasi ke database dilakukan oleh utilitas khusus.
Contoh migrasi paling sederhana:
Pendekatan ini memberikan banyak keuntungan dibandingkan mengatur perubahan dalam file SQL yang umum. Tidak adanya konflik penggabungan tidak sia-sia.
Lebih mengejutkan lagi bahwa pendekatan itu sendiri telah mendapatkan popularitas relatif baru-baru ini. Tampaknya kerangka kerja Ruby on Rails, di mana alat migrasi awalnya dibangun, adalah ketenaran utama dari pendekatan, itu adalah akhir tahun 2005. Sedikit lebih awal, Martin Fowler, 2003
menulis tentang pendekatan tersebut. Mungkin, intinya adalah bahwa pengembangan mulai secara aktif mengadaptasi penggunaan sistem kontrol versi hanya pada awal abad ini. Kembali pada tahun 2000, paragraf pertama dari
tes Joel Spolsky adalah
"Apakah Anda menggunakan kontrol sumber?" - ini menunjukkan bahwa tidak semua orang menggunakan sistem kontrol versi pada saat itu. Tapi kami terganggu.
Delapan tahun dengan Migrasi MyBatis
Kami di
Wrike mulai menggunakan pendekatan perubahan basis data melalui migrasi pada 2010, 29 Maret, jam setengah dua belas. Sejak itu, kami telah menerapkan 1.440 migrasi, yang mengandung 6.436 perubahan langsung dan 5.015 terbalik. Secara umum, kami telah memperoleh beberapa pengalaman menggunakan alat
Migrasi MyBatis bersama dengan
PostgreSQL .
Singkatnya, kita tidak pernah menyesal. Jika Anda tidak menggunakan Migrasi atau yang serupa, sekarang saatnya untuk memulai. Ya,
Pentium 4 juga ketinggalan jaman.
Tapi itu membosankan untuk berbicara tentang manfaat dari apa pun, mari kita langsung ke kesulitan.
Spesifikasi postgreSQL
Mungkin tidak ada kesulitan dengan menulis migrasi untuk Postgres, mungkin, kecuali dua:
- Anda tidak dapat membuat indeks,
- Anda tidak dapat menambahkan kolom NOT NULL.
Tidak, sebenarnya itu mungkin, hanya saja tidak dengan cara yang sepenuhnya jelas. Saat membuat indeks, Anda harus selalu menentukan
CREATE INDEX CONCURRENTLY , jika tidak Anda akan merusak produksi, karena Postgres akan mengunci tabel selama durasi pembuatan indeks, dan ini bisa memakan waktu yang cukup lama. Tentu saja, pengembang melupakannya sekali, Anda harus selalu mengingat kehalusan ini. Di sini orang bisa menulis tes. Tapi ini hanya sedikit ketidaknyamanan.
Membuat kolom NOT NULL lebih rumit, di sini Anda perlu membuat perubahan dalam empat langkah:
- Buat kolom NULL (di Postgres gratis).
- Setel kolom DEFAULT ke nilai.
- Dalam satu lingkaran, perbarui nilai NULL secara bertahap dalam DEFAULT.
- Setel SET BUKAN NULL.
Tangkapan terbesar di sini adalah di paragraf ketiga. Nilai NULL perlu diperbarui dalam bagian, karena
UPDATE some_table SET some_column='' WHERE some_column IS NULL
; akan memblokir tabel, seperti halnya dengan indeks, dengan konsekuensi yang sama. Dan Migrasi hanya dapat menjalankan perintah SQL, sehingga skrip tersebut harus digulirkan ke dalam produksi dengan tangan. Kesenangan di bawah rata-rata. Sekarang, jika sebuah siklus dapat ditulis dalam Migrasi, tidak akan ada masalah. Mungkin ini diimplementasikan melalui
kait .
Membuat indeks
UNIQUE
dan mengubah
PRIMARY KEY
juga membutuhkan beberapa keterampilan, tetapi operasi ini relatif jarang dipikirkan.
Khusus kluster
Alat manajemen migrasi basis data bagus selama Anda memiliki satu basis data. Lebih menyenangkan jika Anda memiliki beberapa pangkalan. Terutama jika Anda memiliki beberapa jenis database, yang masing-masing memiliki beberapa contoh.
Akibatnya, setelah
git pull
pengembang harus memutar perubahan ke instance pertama dari database pertama, kemudian ke instance kedua, lalu ke instance pertama dari database kedua dan seterusnya - prinsip seperti itu. Di sini tepat untuk menulis utilitas untuk mengelola utilitas manajemen migrasi basis data. Otomatisasi total.
Juggling peran
Bukan rahasia lagi bahwa peran sebagai entitas tidak hidup di tingkat basis data yang terpisah, tetapi di tingkat seluruh server basis data, setidaknya di Postgres. Dalam hal ini, Anda mungkin perlu menentukan
REVOKE INSERT ON some_table FROM some_role
; Masih mungkin untuk mengharapkan peran yang telah dikonfigurasikan sebelumnya dalam produksi, tetapi untuk dev atau pementasan ini sudah sulit. Pada saat yang sama, dalam pengembangan, tentu saja, semua database ada di server lokal yang sama, jadi Anda tidak dapat menulis
CREATE ROLE
dalam migrasi, dan
IF NOT EXISTS
tidak didukung. Semuanya diselesaikan dengan mudah:
DO $$ BEGIN IF NOT EXISTS (SELECT * FROM pg_roles WHERE rolname = 'some_role') THEN CREATE ROLE "some_role" NOLOGIN; END IF; END; $$;
Lihat itu! Saya menangkap dan melemparkannya, menangkap dan melempar, itu sangat sederhana.
Sedikit realitas pembangunan
Pengembang membuat kesalahan, dan bahkan dalam migrasi SQL, ini terjadi. Biasanya kesalahan bisa dilihat dalam ulasan, tetapi bisa juga tidak biasa. Jika kita berbicara tentang perubahan langsung, maka tiang tembok di sana masih belum mencapai produksi - terlalu banyak tahapan verifikasi. Tetapi dengan perubahan sebaliknya, insiden dapat muncul. Untuk menghindari kesalahan dalam migrasi UNDO, saat menguji migrasi, Anda harus melakukan tidak hanya
./migrate up
, tapi
./migrate up
, lalu
./migrate down
, lalu lagi
./migrate up
. Ini tidak rumit, Anda hanya perlu memastikan bahwa empat puluh pengembang selalu melakukan ini. Dengan cara yang baik, utilitas dapat melakukan kombo seperti itu untuk lingkungan pengembang secara otomatis.
Lingkungan uji
Jika lingkungan pengujian berumur pendek: misalkan Anda membuat sebuah wadah, menginisialisasi database dan menjalankan tes integrasi, seharusnya tidak ada masalah. Kami
./migrate bootstrap
, lalu
./migrate up
, dan Anda selesai. Saat itulah jumlah migrasi melebihi seribu, proses ini dapat ditunda. Sayang sekali ketika database diinisialisasi lebih lama dari tes dijalankan. Kita harus menghindar.
Dengan lingkungan yang berumur panjang, itu masih lebih sulit. QA, Anda tahu, mereka tidak ingin melihat database bersih tanpa cela ketika mereka mulai bekerja. Saya tidak tahu mengapa demikian, tetapi fakta adalah fakta. Jadi keadaan basis yang digunakan dalam pengujian manual harus dijaga dalam integritas. Dan ini tidak selalu mudah.
Kehalusannya adalah bahwa jika migrasi diterapkan ke database, pengenal migrasi ditulis ke sana. Dan jika kode migrasi kemudian diubah, basis data tidak akan terpengaruh. Jika perubahan tidak kritis, kode dapat berhasil diproduksi. Sinkronisasi Rss. Tentu saja, ini memalukan. Prinsip pertama bekerja dengan migrasi adalah jangan pernah mengubah migrasi tertulis, tetapi selalu buat yang baru. Tetapi kadang-kadang saya merasa seperti meraba-raba - Saya akan berubah sedikit di sini, tidak ada yang akan rusak, karena kebenarannya. Tentu saja! Silakan!
Jika migrasi ditandatangani setelah peninjauan, akan mungkin untuk melarang penerapan draft untuk pementasan. Dan dimungkinkan untuk menyimpan tidak hanya pengidentifikasi migrasi di
changelog
, tetapi juga
checksum
- juga berguna.
Kembali seperti semula
Belokan berbahaya terjadi ketika tugas dibatalkan: mereka lakukan, lakukan, dan berubah pikiran. Ini situasi normal. Setelah kode tidak lagi diperlukan, cabang harus dihapus. Dan ada migrasi ... dan dia sudah dalam pementasan ... ah, ... oops. Alasan yang bagus untuk memeriksa apakah Anda dapat memulihkan cadangan repositori. Meskipun mengingat bahwa mungkin ada yang lebih mudah.
Pada saat yang sama, migrasi adalah teks. Dan dimungkinkan untuk menyimpan teks ini di sana, di
changelog
. Lalu, jika migrasi dari kode hilang, tidak masalah untuk alasan apa, itu selalu bisa dibatalkan. Dan bahkan secara otomatis.
Lakukan undo lagi
Bagian UNDO pasti dibutuhkan. Tapi mengapa menulisnya? Tentu saja, ada beberapa kasus yang menarik, tetapi sebagian besar perubahannya adalah
CREATE TABLE
atau
ADD COLUMN
atau
CREATE INDEX
. Bagi mereka, utilitas dapat menghasilkan operasi terbalik secara otomatis, langsung menggunakan kode SQL. Tentu saja ada kekhususan.
CREATE TABLE ${name}
- ini adalah tim khusus, tiba-tiba tidak standar. Ya, dan untuk menghasilkan
DROP TABLE ${name}
, Anda harus dapat mengurai ekspresi hingga kata ketiga. Meskipun, secara umum, ini adalah tugas teknis yang sepenuhnya layak. Bisa di luar kotak.
Kesimpulan
Tentu saja, saya menemukan kesalahan. Migrasi MyBatis dipahami sebagai utilitas sederhana dan universal, minimal terkait dengan spesifikasi basis data. Dan dia lebih dari membenarkan dirinya sendiri. Tetapi tampaknya beberapa perbaikan kecil akan membuatnya jauh lebih baik, terutama bila digunakan jarak jauh.
-
Dmitry Mamonov / Wrike