Bukan Algoritmanya. Tapi Encoding-nya.
Selama beberapa hari, saya yakin sistem saya punya bug yang dalam dan misterius. Log saya keluar sebagai sampah. Sebuah langkah konversi data menghasilkan berkas yang keluar dengan kesalahan yang halus. Sebuah subprocess mengembalikan omong kosong alih-alih keluaran yang saya harapkan. Saya pergi memburu cacat dalam logika saya, di suatu tempat di bagian sistem yang cerdik.
Tidak ada cacat dalam logikanya. Bug-nya adalah bahwa komputer saya dan saya tidak sepakat tentang cara mengeja.
Bug yang tidak ada di dalam kode
Yang membuatnya membuat gila adalah bahwa segalanya tampak benar. Saya bisa membaca kode yang menghasilkan sampah itu dan tidak melihat ada yang salah dengannya. Kegagalannya aneh dan tidak konsisten: sebagian teks lewat dengan baik, sebagian lewat dalam keadaan teracak, sebagian berkas terbuka dengan sempurna dan yang lain rusak secara halus. Tidak ada satu pun pola yang menunjuk ke satu baris yang bisa saya datangi dan perbaiki.
Ketidakkonsistenan itu, yang akan saya pelajari kemudian, adalah petunjuk yang umum. Tapi saat itu hal itu hanya tampak seolah program saya kerasukan.
Apa yang sebenarnya salah: dua program, dua abjad
Inilah hal yang ada di baliknya. Komputer tidak menyimpan teks sebagai huruf. Mereka menyimpannya sebagai angka, dan untuk mengubah angka-angka itu kembali menjadi karakter Anda membutuhkan sebuah tabel yang disepakati — sebuah encoding — yang mengatakan angka mana berarti karakter mana. Jika dua bagian dari suatu sistem memakai tabel yang berbeda, byte yang sama akan berarti hal yang berbeda bagi masing-masing, dan teks yang ditulis oleh yang satu akan disalahbaca oleh yang lain.
Itulah keseluruhan bug saya. Sistem operasi saya secara default memakai sebuah encoding lama yang warisan, sementara perkakas dan berkas yang saya kerjakan mengasumsikan yang modern dan nyaris universal. Segalanya berfungsi selama kedua tabel kebetulan sepakat — yang memang demikian, untuk karakter-karakter yang paling sederhana — dan rusak saat apa pun melangkah keluar dari tumpang tindih itu. Teksnya tidak pernah dikorupsi dengan sengaja. Teks itu hanya dibaca dalam bahasa yang berbeda dari bahasa saat ia ditulis.
Mengapa begitu sulit dilihat
Ketidakcocokan encoding adalah kelas bug yang sangat jahat karena ia sering kali tidak gagal dengan bersih. Alih-alih melemparkan eksepsi yang menunjuk ke masalahnya, sebuah konversi yang permisif bisa menghasilkan keluaran yang nyaris benar, sampai persis pada titik ia bertemu sebuah karakter yang tidak disepakati kedua encoding — dan kemudian ia diam-diam mengacaukan bagian itu saja dan melanjutkan.
Jadi kegagalannya bersifat sesekali dan bergantung pada isi, yang persis merupakan profil yang membuat Anda mencari di tempat yang salah. Bug yang sesekali dan bergantung pada isi terasa seolah ia pasti tinggal di dalam logika Anda, di bagian rumit yang Anda banggakan. Yang ini tinggal di dalam pipa, di sebuah default yang bahkan tidak pernah saya sadari sedang saya andalkan.
Kebenaran yang tak glamor dari pekerjaan jenis ini
Saya telah membayangkan bahwa bagian-bagian sulit dari membangun sebuah sistem pembelajaran akan menjadi bagian-bagian yang menarik — modelnya, matematikanya, strateginya. Sebagian besar yang sungguh-sungguh dari bagian-bagian sulit yang sebenarnya ternyata adalah hal-hal seperti ini. Encoding teks. Akhiran baris. Path berkas yang berarti hal berbeda di mesin yang berbeda. Infrastruktur membosankan di bawah segalanya, di mana satu default yang salah bisa diam-diam memakan seminggu dari hidup Anda sementara Anda menatap kode elegan di atasnya, yakin bahwa masalahnya pasti ada di sana.
Ini merendahkan hati, dengan cara yang berguna. Matematikanya jarang yang paling sering menghentikan saya. Pipanya yang demikian.
Perbaikannya: berhenti memercayai default, paksakan kesepakatan
Perbaikannya tidak halus. Saya berhenti mengandalkan encoding apa pun yang kebetulan menjadi default tiap bagian sistem, dan memaksakan satu secara eksplisit — yang modern dan universal — di tiap batas: tiap pembacaan berkas, tiap penulisan berkas, tiap subprocess yang diluncurkan. Begitu tiap komponen dibuat sepakat, secara tertulis, pada tabel yang sama, sampahnya berhenti.
Berdampingan dengan perbaikan utama itu, saya menambahkan satu kebiasaan defensif yang lebih kecil: menjaga karakter-karakter merepotkan tertentu agar sejak awal tidak masuk ke dalam log saya — bukan sebagai pengganti dari membenarkan encoding-nya, melainkan sebagai jaring pengaman. Log adalah satu tempat yang paling Anda butuhkan untuk bisa dibaca dengan jelas ketika segala yang lain sedang terbakar, dan saya tidak ingin perkakas yang saya andalkan untuk mendiagnosis masalah terus-menerus menjadi korban dari kelas isu yang sama.
Pelajarannya: sebuah default adalah keputusan yang tidak Anda buat
Pelajaran yang lebih dalam hidup lebih lama daripada bug-nya. Setiap “default” dalam tumpukan Anda adalah sebuah keputusan — biasanya dibuat oleh seseorang yang tidak tahu situasi khusus Anda, sering kali bertahun-tahun lalu, dengan alasan yang mungkin tidak lagi berlaku. Sebagian besar waktu keputusan-keputusan warisan itu baik-baik saja, dan Anda tidak pernah harus memikirkannya. Itulah sebagian dari apa yang membuatnya berbahaya. Ketika salah satunya kebetulan diam-diam salah untuk kasus Anda, ia nyaris tak terlihat, karena Anda tidak pernah secara sadar memilihnya — dan hal yang tidak pernah Anda pilih adalah tempat terakhir yang Anda pikirkan untuk dilihat.
Saya kehilangan sebagian besar dari seminggu karena sebuah pilihan yang tidak saya ketahui telah saya buat. Kini, ketika sesuatu gagal dengan cara yang tidak masuk akal secara logika, salah satu dari pertanyaan pertama saya bukan lagi hanya “di mana bug saya?” Tapi juga “apa yang saya asumsikan yang sebenarnya tidak pernah saya putuskan?”
— Tidak ada sinyal, tidak ada imbal hasil, bukan nasihat investasi.