Bug Paling Mahal Biasanya Bukan Bug yang Paling Sulit
Bug mahal biasanya lahir dari asumsi kecil yang tidak pernah diuji—bukan dari algoritma rumit.
0xNN · · 7 min read
Bug yang paling lama gue ingat bukan bug concurrency atau memory leak. Itu bug kecil di proses pembayaran: sistem menganggap semua transaksi gagal pasti aman untuk dicoba lagi. Di kondisi tertentu, retry justru membuat pengguna ditagih dua kali.
Kodenya pendek. Dampaknya tidak.
Bug mahal biasanya berada di batas antar-asumsi: antara frontend dan backend, antara sistem dan manusia, atau antara “gagal” dan “belum selesai”. Unit test bisa hijau karena test-nya ikut mempercayai asumsi yang sama.
Cari asumsi, bukan hanya baris yang salah
Saat incident, jangan langsung bertanya “file mana yang rusak?”. Tanyakan:
• status apa saja yang sebenarnya mungkin terjadi;
• siapa yang memiliki keputusan terakhir;
• apakah operasi boleh diulang;
• apa yang dilihat pengguna ketika sistem tidak yakin.
Buat state transition sederhana. pending, succeeded, failed, dan unknown sering lebih jujur daripada memaksa semua hal menjadi boolean sukses/gagal.
Observability harus menjawab pertanyaan
Log “something went wrong” tidak membantu. Catat correlation ID, operasi, state sebelum dan sesudah, serta alasan keputusan—tanpa memasukkan token atau data sensitif. Metric juga harus dekat dengan dampak: duplicate charge, retry rate, dan waktu pemulihan.
Perbaikan yang baik bukan sekadar menambah if. Tambahkan test untuk kondisi yang pernah terjadi, dokumentasikan asumsi, dan buat alarm yang bisa memberi tahu tim sebelum pengguna menemukannya.
Bug sulit tidak selalu mahal. Bug sederhana yang menyentuh uang, kepercayaan, atau data pribadi biasanya jauh lebih mahal.
---
Bug bisnis lebih berbahaya daripada bug algoritma
Bug algoritma biasanya punya input dan output yang mudah dibandingkan. Bug bisnis lebih licin karena sistem bisa berjalan normal sambil membuat keputusan yang salah. Diskon diterapkan dua kali, akun yang sudah dihapus masih menerima email, atau laporan bulanan memakai timezone yang berbeda. Tidak ada stack trace yang berteriak.
Untuk mencari bug seperti ini, gue menulis contoh dari sudut pandang pengguna, bukan hanya dari fungsi. “Seorang pelanggan menekan bayar dua kali ketika jaringan lambat” lebih berguna daripada test bernama should_process_payment. Skenario memaksa kita memikirkan idempotency key, timeout, dan apa yang harus terlihat di UI.
Jangan lupa menguji waktu. Banyak bug muncul di batas hari, akhir bulan, daylight saving time, atau ketika job terlambat. Gunakan clock yang bisa dikontrol dalam test. Jangan membuat test bergantung pada Date.now() yang kebetulan dijalankan pada jam tertentu.
Saat incident selesai, hindari kalimat “developer kurang teliti”. Cari kondisi sistem yang membuat kesalahan itu mudah terjadi: nama status yang ambigu, API yang menerima retry tanpa idempotency, atau dashboard yang tidak menampilkan ketidakpastian. Perbaikan terbaik biasanya gabungan dari perubahan kode, test regresi, metric, dan runbook.
Kita tidak bisa menghapus semua bug. Tetapi kita bisa membuat bug yang sama lebih sulit dibuat dan lebih cepat terlihat.
Sumber
• https://sre.google/sre-book/monitoring-distributed-systems/
• https://martinfowler.com/articles/practical-test-pyramid.html
• https://owasp.org/www-project-top-ten/