Skip to content

Ganti Enum Tanpa Naikkan Versi Skema, Saya Kena

Adityo Guni Waluyo

Checker bertemu status yang nggak ada di enum-nya. Ternyata kosakata status diubah tanpa bump versi skema. Pelajaran soal kontrak data.

Ringkasan

File lama ternyata bawa nilai status baru gara-gara ada commit yang ganti kosakata tanpa naikin versi skema. Checker-nya sekarang misahin dua kasus: kalau pembacanya ketinggalan zaman tinggal dikejar, tapi kalau penulisnya nyelip, itu sejarah versi yang dipalsukan. Pelajarannya, ganti enum wajib dianggap ganti skema dan harus bump versi di commit yang sama, kayak aturan Kubernetes.

File transcript yang udah berminggu-minggu nggak disentuh, tiba-tiba dihajar peringatan. Saya lagi jalankan checker ingest di repo my-agent, dan yang bikin nggak nyaman: nilai statusnya transcribed, nilai yang versi pembaca lama nggak pernah tulis. File lama, nilai baru.

Refleks pertama ya itu: mungkin typo di data, mungkin checker-nya yang salah baca. Insting lama bilang tinggal tambah nilai itu ke enum di pembaca, beres sepuluh menit. Tapi makin dipikir makin janggal. Kalau penulis file-nya memang versi lama, dari mana dia dapat nilai yang baru terdaftar di versi dua?

Jawabannya ada di commit 113eb57 di my-agent. Fungsi cmd_check sekarang membedakan dua kelas kegagalan yang dulu kecampur jadi satu.

if sv > 1 and st not in EVENT_STATUSES:
    warn("unknown-status")
elif sv < 2 and st in NEW_STATUSES:
    warn("legacy-enum-status")

Kelas pertama jelas: file berversi bawa nilai yang pembaca sekarang nggak kenal, ditandai unknown-status. Kelas kedua yang licin: file dengan schema_version di bawah 2 tapi membawa salah satu nilai baru, atau status done sambil bawa objek media. Artinya penulisnya pernah mengubah kosakata status tanpa pernah menaikkan versi. File itu kelihatan legasi, padahal isinya udah migrasi diam-diam.

Dua kelas ini beda tanggapannya. Ketemu unknown-status, pembacanya yang ketinggalan zaman dan harus dikejar. Ketemu legacy-enum-status, yang salah bukan pembacanya, tapi penulis yang pernah nyelip: ada commit yang mengganti kosakata tanpa mengganti nomor versinya. Mencari penulis itu jauh lebih berguna daripada diam-diam nambah nilai ke enum, karena masalahnya bukan daftar yang kurang, tapi sejarah yang dipalsukan.

Aturan main dari Kubernetes dan Postgres

Kebiasaan "tambah aja nilainya di enum" akhirnya saya gugurkan setelah lihat cara sistem skala besar main. Kebijakan deprekasi API Kubernetes bilang elemen API, sekali ada di sebuah versi, can not be removed from that version or have its behavior significantly changed. Satu-satunya jalan mengubah maknanya: naikkan versi grup API-nya [1]. Ada juga kontrak round-trip: objek ditulis di satu versi, dibaca sebagai versi lain, dikonversi balik, dan hasilnya identik tanpa informasi yang hilang [1]. Makna yang boleh geser di tempat sama saja membongkar kontrak itu.

Postgres punya aturan yang sering saya pinjam buat mikirin tabrakan nama: dalam satu skema, dua objek dengan tipe sama nggak boleh punya nama identik, tapi nama yang sama di skema berbeda nggak masalah [2]. Kosakata status yang di-scope per versi skema itu ide serupa. Nilai transcribed di skema v1 dan skema v2 nggak akan bertabrakan, asal versinya jujur.

Pembaca toleran, penulis disiplin

Fowler nulis prinsip Tolerant Reader dengan mengutip hukum Postel: be conservative in what you do, be liberal in what you accept from others [3]. Provider layanan harus bisa berevolusi mendukung tuntutan baru dengan kerusakan minimal ke klien yang udah ada [3]. Terapannya di pipeline ini dua arah. Pembaca liberal: nilai asing ditandai, bukan sampai bikin crash. Penulis disiplin: ganti kosakata berarti bump versi, di commit yang sama.

Satu hal yang perlu diakui jujur: checker-nya cuma memperingatkan, nggak menolak apa pun. Yang bikin aturan ini nggak jadi catatan kaki adalah proses review. PR yang menyelipkan nilai baru tanpa bump versi sekarang kelihatan, dan kelihatan itu udah cukup buat bikin orang mikir dua kali sebelum merge.

Sekarang saya menganggap perubahan enum sebagai perubahan skema, tanpa pengecualian. Nggak ada lagi argumen "cuma nambah satu nilai kok". Soalnya file nggak pernah bohong. Yang bohong itu asumsi bahwa angka versi kecil berarti isinya masih lama. Dan checker yang kemarin bunyi ternyata bukan pengganggu. Dia satu-satunya yang ngomong jujur soal kontrak yang nyelip.

Sumber

  1. Kubernetes API deprecation policy
  2. PostgreSQL: Schemas
  3. Martin Fowler: Tolerant Reader

Artikel terkait