











{"author":"Faiq Najib Al-Aziz","body":"\nTiga halaman mengirim _field_ yang sama dengan cara berbeda. Ada yang mengirim angka, ada yang mengirim _string_ kosong kalau nilainya tidak ada, ada juga yang membungkus angka jadi _string_. Kebiasaan ini bertahan bertahun-tahun, sampai penerimanya berubah jadi sistem yang tidak mau menebak.\n\nBegitulah _type chaos_ muncul. Tidak ada yang sengaja bikin, tapi bekasnya masih bisa dihitung di _repo_ kami.\n\n## Dulu, PHP Memaklumi\n\nDulu penerimanya adalah PHP, bahasa yang sangat pemaaf soal tipe data. Kirim `\"123\"`, dibaca sebagai 123. Kirim `\"\"`, dianggap kosong. Kirim `null`, seolah tidak terlihat. Selama bertahun-tahun, halaman-halaman itu tidak perlu memikirkan tipe karena bahasanya tidak mempermasalahkannya.\n\nTiap halaman mengirim dengan gayanya sendiri, _backend_ menerima saja, dan hidup terasa sederhana. Baru belakangan saya sadar, tenang-tenang saja bukan berarti sistemnya sehat. Penerimanya saja yang tidak pernah protes.\n\n## Lalu Go Datang\n\nLalu _backend_-nya pindah ke Go. Pandangannya soal tipe berbeda: **tipe adalah kontrak**. Kalau kontraknya meminta angka, yang dikirim harus angka. _String_ kosong yang mengaku angka ditolak di pintu, lengkap dengan _error decoding_ yang panjang dan sama sekali tidak lucu.\n\nGo tidak menciptakan _chaos_; ia hanya berhenti memaafkannya. Tiga kebiasaan yang sebelumnya tidak bermasalah berubah menjadi pelanggaran:\n\n1. Ada nilainya? Kirim **angka**. Tidak ada nilainya? Kirim **_string_ kosong**.[^2]\n2. Halaman lain untuk fungsi serupa mengirim **_string_**, dari sananya.\n3. Dan tidak ada dua halaman yang pernah duduk bareng menyepakati hal itu.\n\nTidak ada penjahatnya. Setiap halaman konsisten dengan caranya sendiri. _Chaos_ ini muncul pelan-pelan selama bertahun-tahun, bukan karena ada yang sengaja membuatnya.\n\n## Bekasnya Ternyata Bisa Dihitung\n\nYang paling menarik, _chaos_ ini bukan cuma bisa diceritakan. Jumlahnya juga bisa dihitung.\n\nSaat menyisir _repo_ baru, saya menemukan hampir dua ratus pemanggilan `String()` di berbagai halaman, ditambah lebih dari dua puluh `Number()`.[^1] Sebagian memang punya kegunaan sendiri. Sebagian lain adalah **bekas luka** dari era _chaos_: jaring pengaman agar nilai dengan tipe yang tidak pasti tetap bisa diproses.\n\nJaring pengaman itu bukan kesalahan. Mereka membantu transisi tetap berjalan. Tapi jumlahnya juga jadi petunjuk: kalau tipe data bisa dipercaya, mestinya tidak ada begitu banyak tempat yang harus menebak.\n\n## Biar Kontraknya Jelas\n\nSolusi jangka panjangnya bukan menambah jaring pengaman ke-400. Pertanyaannya perlu diubah: bukan lagi _\"nilai ini bentuknya apa hari ini?\"_, melainkan _\"kontraknya bilang apa?\"_\n\nSatu _field_ punya satu tipe yang dijanjikan, lalu semua halaman yang mengirimnya mengikuti kontrak itu. _String_ kosong yang mengaku angka bisa ditolak lebih awal, di tempat yang dapat menjelaskan masalahnya. Daftar kontrak yang sederhana dan tertulis itu mungkin bisa mengakhiri perdebatan yang selama ini dibiarkan _frontend_.\n\n## Yang Saya Catat\n\nSaya jadi ingat: bahasa yang memaklumi tipe bisa menyembunyikan utang sampai penerimanya berubah. Tiap halaman mungkin terasa benar sendiri, tapi sistem keseluruhannya belum tentu rapi. Menurut saya, kontraknya perlu ditulis jelas dan normalisasi dilakukan di satu pintu. Jaring pengaman yang tersebar itu membantu, tapi bukan tujuan akhir.\n\nHampir dua ratus pemanggilan konversi tadi tidak semuanya masalah. Tapi cukup banyak yang memberi petunjuk bahwa tipe datanya belum bisa dipercaya. Di episode berikutnya, saya bahas warisan yang lebih kelihatan: dua _library_ UI dan dua era penamaan dalam satu aplikasi.\n\n[^1]: Pola dan angka dihitung langsung dari _repo_ saat episode ini ditulis; tidak semua pemanggilan konversi adalah bekas luka, dan tidak semua bekas luka tercatat.\n\n[^2]: Detail _endpoint_, nama _field_, dan bentuk _error_ disederhanakan; yang dipertahankan hanya bentuk masalahnya.\n","body_clean":"Tiga halaman mengirim field yang sama dengan cara berbeda. Ada yang mengirim angka, ada yang mengirim string kosong kalau nilainya tidak ada, ada juga yang membungkus angka jadi string. Kebiasaan ini bertahan bertahun-tahun, sampai penerimanya berubah jadi sistem yang tidak mau menebak.\nBegitulah type chaos muncul. Tidak ada yang sengaja bikin, tapi bekasnya masih bisa dihitung di repo kami.\nDulu, PHP Memaklumi #Dulu penerimanya adalah PHP, bahasa yang sangat pemaaf soal tipe data. Kirim \u0026quot;123\u0026quot;, dibaca sebagai 123. Kirim \u0026quot;\u0026quot;, dianggap kosong. Kirim null, seolah tidak terlihat. Selama bertahun-tahun, halaman-halaman itu tidak perlu memikirkan tipe karena bahasanya tidak mempermasalahkannya.\nTiap halaman mengirim dengan gayanya sendiri, backend menerima saja, dan hidup terasa sederhana. Baru belakangan saya sadar, tenang-tenang saja bukan berarti sistemnya sehat. Penerimanya saja yang tidak pernah protes.\nLalu Go Datang #Lalu backend-nya pindah ke Go. Pandangannya soal tipe berbeda: tipe adalah kontrak. Kalau kontraknya meminta angka, yang dikirim harus angka. String kosong yang mengaku angka ditolak di pintu, lengkap dengan error decoding yang panjang dan sama sekali tidak lucu.\nGo tidak menciptakan chaos; ia hanya berhenti memaafkannya. Tiga kebiasaan yang sebelumnya tidak bermasalah berubah menjadi pelanggaran:\nAda nilainya? Kirim angka. Tidak ada nilainya? Kirim string kosong.1 Halaman lain untuk fungsi serupa mengirim string, dari sananya. Dan tidak ada dua halaman yang pernah duduk bareng menyepakati hal itu. Tidak ada penjahatnya. Setiap halaman konsisten dengan caranya sendiri. Chaos ini muncul pelan-pelan selama bertahun-tahun, bukan karena ada yang sengaja membuatnya.\nBekasnya Ternyata Bisa Dihitung #Yang paling menarik, chaos ini bukan cuma bisa diceritakan. Jumlahnya juga bisa dihitung.\nSaat menyisir repo baru, saya menemukan hampir dua ratus pemanggilan String() di berbagai halaman, ditambah lebih dari dua puluh Number().2 Sebagian memang punya kegunaan sendiri. Sebagian lain adalah bekas luka dari era chaos: jaring pengaman agar nilai dengan tipe yang tidak pasti tetap bisa diproses.\nJaring pengaman itu bukan kesalahan. Mereka membantu transisi tetap berjalan. Tapi jumlahnya juga jadi petunjuk: kalau tipe data bisa dipercaya, mestinya tidak ada begitu banyak tempat yang harus menebak.\nBiar Kontraknya Jelas #Solusi jangka panjangnya bukan menambah jaring pengaman ke-400. Pertanyaannya perlu diubah: bukan lagi \u0026ldquo;nilai ini bentuknya apa hari ini?\u0026rdquo;, melainkan \u0026ldquo;kontraknya bilang apa?\u0026rdquo;\nSatu field punya satu tipe yang dijanjikan, lalu semua halaman yang mengirimnya mengikuti kontrak itu. String kosong yang mengaku angka bisa ditolak lebih awal, di tempat yang dapat menjelaskan masalahnya. Daftar kontrak yang sederhana dan tertulis itu mungkin bisa mengakhiri perdebatan yang selama ini dibiarkan frontend.\nYang Saya Catat #Saya jadi ingat: bahasa yang memaklumi tipe bisa menyembunyikan utang sampai penerimanya berubah. Tiap halaman mungkin terasa benar sendiri, tapi sistem keseluruhannya belum tentu rapi. Menurut saya, kontraknya perlu ditulis jelas dan normalisasi dilakukan di satu pintu. Jaring pengaman yang tersebar itu membantu, tapi bukan tujuan akhir.\nHampir dua ratus pemanggilan konversi tadi tidak semuanya masalah. Tapi cukup banyak yang memberi petunjuk bahwa tipe datanya belum bisa dipercaya. Di episode berikutnya, saya bahas warisan yang lebih kelihatan: dua library UI dan dua era penamaan dalam satu aplikasi.\nDetail endpoint, nama field, dan bentuk error disederhanakan; yang dipertahankan hanya bentuk masalahnya.\u0026#160;\u0026#x21a9;\u0026#xfe0e;\nPola dan angka dihitung langsung dari repo saat episode ini ditulis; tidak semua pemanggilan konversi adalah bekas luka, dan tidak semua bekas luka tercatat.\u0026#160;\u0026#x21a9;\u0026#xfe0e;\n","canonical":"https://najib.id/writing/2026/hijrah-frontend-03/","description":"Episode 3 Hijrah Frontend: field yang sama terkirim sebagai angka, string kosong, atau string biasa. PHP dulu memaafkan, Go tidak, dan saya menemukan 194 bekas konversinya.","language":"id","lastmod":"2026-10-29T09:31:17Z","publishedAt":"2026-09-23T09:00:03Z","readingTime":3,"section":"writing","series":"Hijrah Frontend","tags":["frontend","typescript","type-safety","cerita"],"title":"Hijrah Frontend (3): Type Chaos, Angka, String Kosong, dan Halaman yang Berbeda Pendapat","type":"writing","url":"https://najib.id/writing/2026/hijrah-frontend-03/","wordCount":529}
