Debugging checklist adalah urutan langkah yang selalu sama setiap kali ketemu bug, supaya kamu gak lompat-lompat menebak. Bayangin montir yang menangani motor mogok. Montir yang baik gak langsung bongkar mesin. Dia nyalakan dulu motornya untuk merasakan gejalanya, lalu cek bensin, busi, dan aki satu per satu, dari yang paling murah dicek, sampai ketemu biangnya. Setelah diperbaiki, dia tes jalan sekali lagi.
🧪 Tebakan cepat:
subtotalbernilai105000(number), danongkirdari API bernilai"10000"(string).subtotal + ongkirhasilnya115000, atau sesuatu yang lain? Tebak dulu, jawabannya ada di bagian "Langkah 4: periksa nilai dan tipenya".
Bug yang kita kejar
Di Lab, tombol Bayar menampilkan Total: Rp10500010000, padahal harusnya Rp115.000 (Buku 45.000 x 2, Pensil 5.000 x 3, ongkir 10.000).
const keranjang = [
{ nama: "Buku", harga: 45000, qty: 2 },
{ nama: "Pensil", harga: 5000, qty: 3 },
];
async function hitungBayar() {
const subtotal = keranjang.reduce((sum, item) => sum + item.harga * item.qty, 0);
const res = await fetch("/api/ongkir?kota=bandung");
const { ongkir } = await res.json();
return subtotal + ongkir;
}
Kita ikuti checklist-nya dari langkah pertama.
Langkah 1 sampai 3: reproduksi, Console, Network
- Reproduksi. Catat langkah persisnya, hasil yang diharapkan, dan hasil yang terjadi. Di sini: buka keranjang, klik Bayar; diharapkan Rp115.000, yang muncul Rp10500010000, dan terjadi setiap kali. Bug yang bisa dimunculkan lagi kapan saja jauh lebih mudah diburu. Kalau cuma kadang-kadang, catat kondisinya: browser, ukuran layar, user yang login, data tertentu.
- Baca Console. Ada error merah? Kalau ada, baca jenis, pesan, dan stack trace-nya (pelajaran Membaca Error Messages). Di bug ini Console bersih. Itu juga petunjuk: kodenya gak crash, jadi masalahnya di logika atau data.
- Cek Network. Filter Fetch/XHR, klik request-nya, lalu periksa status dan tab Response. Di sini
GET /api/ongkir?kota=bandungberstatus200, dan response-nya{"ongkir":"10000"}. Perhatikan tanda kutipnya: ongkir dikirim sebagai teks, bukan angka.
Langkah 4: periksa nilai dan tipenya
Jangan cuma mencetak nilainya; cetak juga tipenya. console.log(ongkir) mencetak 10000, sama persis dengan angka. Helper kecil dari latihan membedakannya:
debugValue("subtotal", subtotal); // [subtotal] type:number val:105000
debugValue("ongkir", ongkir); // [ongkir] type:string val:10000
Ketemu: ongkir itu string. Di JavaScript, + dengan salah satu sisi berupa string bukan penjumlahan, tapi penyambungan teks: 105000 + "10000" menjadi "10500010000". Jadi hasilnya bukan 115000. Itu jawaban tebakannya.
Cara lain untuk langkah ini: console.log({ ongkir }) mencetak nama dan nilainya sekaligus (string tampil dengan tanda kutip), atau pasang breakpoint dan baca Scope (pelajaran Breakpoints & Stepping).
Langkah 5 sampai 7: isolasi, perbaiki, kunci dengan test
- Isolasi. Kecilkan masalahnya sampai tinggal intinya. Satu baris
console.log(105000 + "10000")sudah memunculkan bug yang sama, tanpa keranjang, tanpa fetch. Kalau belum tahu bagian mana yang salah, matikan separuh kode atau pindahkan separuh data, lalu cek apakah bug-nya masih ada. - Perbaiki di sumbernya. Ubah teks jadi angka sebelum dijumlah:
return subtotal + Number(ongkir);. Hasilnya115000. Lebih baik lagi, minta API mengirimongkirsebagai number. - Kunci dengan regression test. Tulis tes yang gagal kalau bug yang sama muncul lagi. Langkah ini paling sering dilewatkan, padahal tanpa tes, perubahan kecil bulan depan bisa diam-diam mengembalikan bug yang sama.
function hitungTotal(subtotal, ongkir) {
return subtotal + Number(ongkir);
}
console.assert(hitungTotal(105000, "10000") === 115000, "ongkir string harus dijumlah sebagai angka");
console.assert(kondisi, pesan) diam saja kalau kondisinya true, dan mencetak Assertion failed: pesan kalau false.
Kalau masih buntu: rubber duck dan minta bantuan
- Rubber duck debugging: jelaskan kodemu baris demi baris, keras-keras, ke bebek karet atau siapa pun. Saat menjelaskan, kamu dipaksa memeriksa ulang tiap asumsi, dan bug yang tadinya gak terlihat sering muncul sendiri ("ongkir-nya angka... eh, tunggu, dari mana asalnya?").
- Istirahat sebentar. Setelah 30 menit buntu, jalan sebentar sering lebih cepat dari 30 menit berikutnya.
- Minta bantuan dengan jelas: apa yang ingin dicapai, apa yang terjadi (pesan error persis), apa yang sudah dicoba, dan kode minimal yang memunculkan bug-nya.
Latihan: helper debugValue
Di latihan kamu menulis debugValue(label, value): mencetak keterangan nilai beserta tipenya, lalu mengembalikan value apa adanya.
| Panggilan | Yang dicetak |
|---|---|
debugValue("user", null) |
[user] NULL |
debugValue("config", undefined) |
[config] UNDEFINED |
debugValue("items", [1, 2, 3]) |
[items] Array(3) |
debugValue("data", { a: 1, b: 2, c: 3 }) |
[data] Object{3} |
debugValue("count", 42) |
[count] type:number val:42 |
debugValue("name", "Budi") |
[name] type:string val:Budi |
Urutan pengecekannya menentukan hasil:
typeof nullhasilnya"object", kesalahan lama JavaScript yang gak pernah diperbaiki. Jadi cekvalue === nullpaling awal.- Array juga bertipe
"object". PakaiArray.isArray(value)sebelum cek object, dan tampilkanvalue.length. - Untuk object biasa,
Object.keys(value).lengthmemberi jumlah key-nya. - Sisanya (number, string, boolean) dicetak dengan
typeof valuedan nilainya. return valuedi akhir membuat helper ini bisa disisipkan di tengah ekspresi:const total = debugValue("total", hitungTotal(a, b));.
🎯 Pohon keputusan singkat
Ada error merah di Console?
ya -> baca jenis, pesan, dan baris paling atas stack trace
gak -> cek Network: ada request gagal (4xx/5xx) atau response aneh?
ya -> periksa URL, method, header, dan body-nya
gak -> data benar tapi tampilan salah? cek Elements dan CSS
data salah? periksa nilai dan tipenya, telusuri dari sumbernya
Bug cuma kadang-kadang?
-> curigai urutan async (await yang lupa), cache (hard reload), atau data tertentu
⚠️ Jebakan yang sering ketemu
- Langsung mengubah kode sebelum bisa mereproduksi. Kamu gak akan tahu apakah perubahanmu memperbaikinya.
- Mengira Console bersih berarti kodenya benar. Bug logika dan data sering gak pernah melempar error.
- Mencetak nilai tanpa tipenya.
10000dan"10000"terlihat sama diconsole.logbiasa. - Selesai setelah bug hilang. Tanpa regression test, bug yang sama bisa kembali tanpa ketahuan.
- Di latihan: cek object sebelum null atau array.
nulldan[1, 2, 3]sama-sama bertipe"object", jadi tangkap mereka lebih dulu, dan jangan lupareturn value.
TL;DR: Ikuti urutan yang sama tiap kali: reproduksi (langkah, harapan, kenyataan), baca Console, cek Network (status dan response), periksa nilai beserta tipenya, isolasi sampai sekecil mungkin, perbaiki di sumbernya, lalu kunci dengan regression test supaya bug-nya gak kembali. Di contoh, Console bersih, Network menunjukkan "ongkir":"10000" sebagai string, dan 105000 + "10000" menyambung teks jadi "10500010000"; Number(ongkir) memperbaikinya jadi 115000. Kalau buntu, jelaskan kodemu ke bebek karet (rubber duck debugging). debugValue mencetak [label] NULL, [label] UNDEFINED, [label] Array(N), [label] Object{N}, atau [label] type:X val:Y, mengecek null dan array sebelum object, dan mengembalikan nilainya.