Image: AI generated
Muncul Kembali di Tempat yang Sudah Diperbaiki
Saya membangun alat untuk menutup drift.
Tesis yongol sederhana. Keputusan akan hanyut jika tidak tinggal di satu sumber otoritatif tunggal (SSOT). Maka saya menaruh keputusan ke dalam SSOT, dan menjadikan kode sebagai projection sekali pakai yang digambar ulang setiap kali dihasilkan. Drift logika bisnis — di mana kolom yang ditetapkan BIGINT diam-diam berubah kembali menjadi INT setelah satu kali refaktor — ditutup dengan cara ini.
Namun beberapa waktu lalu, ketika menganalisis sekumpulan cacat dalam kode yang dihasilkan yongol, saya melihat sesuatu yang aneh. Cacat-cacat itu mengakui dirinya sendiri dalam struktur kalimat yang sama. “Pengumpulan import terpisah dari ‘apakah handler benar-benar menggunakan time’.” “Inferensi requiredness terpisah dari ‘apakah API target benar-benar memerlukan parameter ini sebagai required’.” Parameter path selalu required, import hanya ketika token benar-benar digunakan. Keputusan-keputusan struktural yang sama tertanam sebagai proksi lokal yang nyaman di dalam kode generator, tanpa tercatat di SSOT mana pun.
Drift tidak menghilang. Ia naik satu lapisan ke atas. Logika bisnis sudah ditutup oleh SSOT, tetapi keputusan struktural generator itu sendiri — yang membaca SSOT dan mencetak kode — tidak memiliki SSOT. Tesis yongol kembali menghantam yongol sendiri. Tepat di titik yang diprediksi oleh teori.
Maka pertanyaannya berubah. Semua orang tahu mengapa drift terjadi. Pertanyaan sesungguhnya adalah ini: Mengapa ia selalu kembali meskipun sudah diperbaiki.
Akar: Keputusan dan Detail Adalah Hal yang Berbeda
Mari kita bangun ulang dari fisika.
Keputusan adalah informasi. Informasi dengan entropi rendah. “Kolom ini harus 64-bit” berarti secara sengaja memilih satu dari sekian banyak keadaan yang mungkin. Alam tidak menyukai entropi rendah. Jika dibiarkan, informasi menyebar dan larut menjadi noise di sekitarnya. Hukum kedua termodinamika berlaku juga pada keputusan.
Rekayasa perangkat lunak telah lama mengamati keruntuhan ini. Hukum evolusi perangkat lunak Lehman menyatakan bahwa kompleksitas sistem E-type meningkat kecuali ada upaya eksplisit untuk menguranginya (1980). Fisika informasi menggali lebih dalam. Landauer menunjukkan pada tahun 1961 bahwa bahkan menghapus 1 bit membutuhkan biaya termodinamis minimum (kT ln 2). Mengubah dan mempertahankan informasi pada prinsipnya tidak gratis. Menjaga keputusan tetap di tempatnya membutuhkan energi yang terus dikeluarkan.
Agar informasi bertahan, dibutuhkan dua hal: penyimpanan otoritatif (authoritative store) dan proyeksi ulang aktif yang terus-menerus menggambar ulang darinya (error correction). Begitulah DNA dalam tubuh kita bekerja, begitu pula bit paritas dalam penyimpanan digital. Simpan sumber asli secara terpisah, dan setiap kali pulihkan berdasarkan sumber tersebut.
Drift terjadi ketika pemulihan ini rusak. Mekanismenya satu. Saya menyebutnya proxy binding. Ketika media tidak mampu membedakan dan menyimpan keputusan secara terpisah dari detail, orang berikutnya (atau agen berikutnya) tidak bisa membaca keputusan dari sumber otoritatif — ia menurunkannya kembali dari sinyal korelasi yang nyaman di sekitarnya. Tebakan seperti “kolom ini timestamptz, jadi saya harus meng-import time.” Biasanya benar. Itulah yang membuatnya berbahaya. Kadang salah, dan ketika salah, keputusan menghilang tanpa suara.
Kode raw adalah media seperti itu. Kode tidak membedakan “ini adalah keputusan” dari “ini kebetulan benar di tempat ini.” Oleh karena itu, model yang lebih besar pun tidak menyelesaikan masalahnya. Ketika media itu sendiri tidak mampu menampung keputusan, tidak ada yang bisa dibaca meskipun pembacanya semakin pintar.
Fenomena ini bukan tanpa nama. Dalam arsitektur perangkat lunak, Perry dan Wolf membedakan antara pelanggaran prinsip sebagai erosi (erosion) dan ketidakpekaan terhadap arsitektur sebagai drift (1992), sementara Cunningham menyebut bunga yang melekat pada kode yang tidak benar sebagai utang teknis (1992). Setiap bidang telah memberi nama gejalanya dengan baik. Yang ingin saya tambahkan adalah mekanisme tunggal di bawahnya (proxy binding), dan struktur di mana mekanisme itu berulang naik ke lapisan atas setiap kali kita menutupnya. Ini bukan soal penamaan, melainkan soal kausalitas.
Mengapa Ia Naik ke Atas
Sampai di sini ceritanya sudah dikenal. Yang baru ada di bagian berikutnya.
Untuk menutup drift, dibutuhkan dua hal: penyimpanan yang menampung keputusan secara otoritatif (SSOT), dan subjek penutup yang membaca penyimpanan tersebut dan mencetak keluaran (generator). Namun subjek penutup itu sendiri juga membuat keputusan. Keputusan struktural seperti “parameter path diperlakukan sebagai required.” Media tempat keputusan itu tinggal — kode generator — juga tidak mampu membedakan keputusan dari detail.
Mekanisme yang sama berulang satu lapisan di atas. Tindakan menutup itu sendiri menciptakan media yang belum tertutup satu lapisan di atasnya. Drift bukan dibasmi — ia pindah rumah. Ke lapisan tanpa otoritas.
Jika ini didorong sampai ujung, kesimpulan yang tidak nyaman muncul. Berikan SSOT pada generator? Maka sesuatu yang membuat SSOT itu akan menyimpan keputusannya sendiri di media yang tidak tertutup. Setiap kali lapisan dinaikkan, luas permukaannya menyusut, tetapi di puncak selalu tersisa lapisan tanpa otoritas. Entah itu manusia, atau generator dari generator. Drift secara asimtotis tidak bisa dibasmi. (Ini lebih merupakan dugaan kuat daripada bukti. Tetapi setiap lapisan yang saya tutup sejauh ini membuka lapisan di atasnya pada saat ditutup.)
Inilah jawaban atas “mengapa ia kembali meskipun sudah diperbaiki.” Ia tidak kembali. Ketika kita menutup satu lapisan, alat penutup itu membuka lapisan berikutnya. Sungai yang sama merembes dari tanggul yang lebih tinggi.
Asimetri Pengobatan: Apa yang Bisa Dideklarasikan, dan Apa yang Hanya Bisa Divalidasi
Lalu bagaimana menutup lapisan atas? Di sinilah asimetri yang menentukan terungkap.
Keputusan logika bisnis biasanya berupa nilai. Kolom 64-bit, akses hanya pemilik, paginasi model kursor. Nilai bisa dideklarasikan. Tulis di DDL, di OpenAPI, di file spesifikasi — itu menjadi SSOT. Tertutup oleh deklarasi.
Keputusan struktural generator berbeda. “Parameter path selalu required”, “import terikat pada referensi token aktual”, “required (kunci ada) dan tidak-kosong adalah hal berbeda.” Ini bukan nilai melainkan properti perilaku fungsi yang berlaku di seluruh masukan. Properti perilaku tidak bisa dienumerasi dalam deklarasi. Karena masukannya tak terbatas. Tidak ada cara untuk menulis di satu baris YAML “transformasi ini harus berperilaku demikian untuk semua kasus.”
Oleh karena itu, keputusan di lapisan ini hanya bisa ditutup melalui validasi, bukan deklarasi. Type checker, property test, compile gate. Bukan menanamkan keputusan sebagai data, melainkan menanamkan gerbang di mana mesin menangkap pelanggaran setiap kali.
Yang saya tulis di artikel lain — “kodifikasi inspeksi manusia” — tepat di titik ini. Beberapa janji bisa dideklarasikan sehingga SSOT yang menjaganya; beberapa janji tidak bisa dideklarasikan sehingga gate yang menjaganya. Apakah kode yang dicetak generator bisa dikompilasi tidak bisa ditulis di SSOT mana pun. Hanya bisa dikonfirmasi dengan menjalankan kompilasi setiap kali. Tanpa gerbang itu, janji “generate berhasil = bisa di-build” mengambang di luar arsitektur, dan validate lolos 0/0 sementara keluaran rusak.
Drift yang bisa dideklarasikan ditutup dengan SSOT, drift yang hanya bisa divalidasi ditutup dengan gate. Jika keduanya dicampuradukkan, kita selamanya menangkap tikus tanah dengan deklarasi.
Sungai yang Sama, Tanggul yang Berbeda
Struktur ini berulang di luar kode.
Dalam pengetahuan, drift adalah hilangnya sumber. Ketika sebuah klaim kehilangan siapa yang mengatakannya, kapan, dan dengan dasar apa, klaim itu menyebar menjadi noise yang disebut “fakta.” Orang berikutnya tidak bisa membaca dari otoritas (sumber asli) dan menurunkannya kembali dari konteks sekitar. Inilah mengapa saya merancang GEUL sebagai bahasa yang memaksa setiap informasi membawa sumber, waktu, dan tingkat kepercayaan. Epistemologi bahwa tidak ada fakta melainkan hanya klaim adalah pengaman untuk mencegah proxy binding di lapisan pengetahuan.
Dalam hukum, drift adalah preseden yang menyimpang dari keputusan asli. Peradaban tidak menyerahkan ini pada hati nurani hakim di setiap kasus, melainkan menutupnya dengan mengodifikasi aturan, mendefinisikan pelanggaran, dan memasang mekanisme penegakan. Hakim yang baik bukan SSOT melainkan proksi. Hukum tertulis yang menjadi SSOT.
Sungai yang sama. Jika keputusan tidak tinggal di tempat yang otoritatif, jika media tidak membedakan keputusan dari detail, ia akan hanyut. Entah itu kode, pengetahuan, atau hukum.
Kesimpulan: Bukan Pemusnahan, Melainkan Mendorong ke Atas
Pertempuran melawan drift tidak bisa bertujuan pemusnahan. Pemusnahan mustahil. Karena alat penutup selalu membuka lapisan berikutnya.
Tujuannya berbeda. Mendorong drift ke lapisan yang lebih tinggi dengan luas permukaan yang lebih kecil, dan mempersenjatai lapisan itu dengan validasi mekanis. Ketika keputusan yang tersebar di puluhan ribu baris kode raw dikumpulkan ke satu SSOT, permukaan yang bisa hanyut menyusut secara dramatis. Permukaan yang tersisa — invarian perilaku generator — ditutup dengan gate. Meski begitu, di puncak selalu tersisa lapisan terakhir yang tidak bisa didelegasikan lagi — penilaian manusia. Di sanalah kita memvalidasi ulang setiap kali dan menanamkan janji sekali lagi.
Inilah ratchet. Ia hanya berputar satu arah. Gigi yang sudah naik tidak tergelincir turun. Entropi berusaha menarik keputusan ke bawah, dan ratchet mengangkatnya kembali satu gerigi setiap kali. Tidak ada keseimbangan. Berhenti berarti hanyut.
Drift tidak pernah mati. Maka kita tidak pernah berhenti. Membangun janji melawan entropi bukan kemenangan sekali jadi, melainkan ratchet yang abadi.
Artikel Terkait
- Ratchet Pattern — Cara Membuat Agen Menyelesaikan Sampai Akhir
- Mengapa Loop Agen Anda Berdiversi
- Reins Engineering — AI dengan Kendali
Bacaan lanjutan (eksternal)
- Lehman’s laws of software evolution — Ikhtisar hukum empiris bahwa perangkat lunak menjadi semakin kompleks jika dibiarkan.
- Landauer’s principle — Biaya termodinamis untuk menghapus informasi.
Referensi
- Perry, D. E. & Wolf, A. L. (1992). Foundations for the Study of Software Architecture. ACM SIGSOFT Software Engineering Notes, 17(4), 40-52. ACM — Pembedaan antara erosi (erosion) dan drift.
- De Silva, L. & Balasubramaniam, D. (2012). Controlling software architecture erosion: A survey. Journal of Systems and Software, 85(1), 132-151. ScienceDirect
- Lehman, M. M. (1980). Programs, Life Cycles, and Laws of Software Evolution. Proceedings of the IEEE, 68(9), 1060-1076. IEEE — Hukum peningkatan kompleksitas dan hukum perubahan berkelanjutan.
- Landauer, R. (1961). Irreversibility and Heat Generation in the Computing Process. IBM Journal of Research and Development, 5(3), 183-191. IBM — Biaya termodinamis minimum untuk menghapus informasi.
- Shannon, C. E. (1948). A Mathematical Theory of Communication. Bell System Technical Journal, 27, 379-423. DOI — Fondasi informasi, entropi, dan error correction.
- Cunningham, W. (1992). The WyCash Portfolio Management System. OOPSLA ‘92 Experience Report. c2.com — Utang teknis dan “bunga dari kode yang tidak benar.”