Program yang gagal tidak selalu menunjukkan penyebabnya pada baris yang memicu error. Debugger adalah alat yang menjalankan program dengan kontrol penuh, yaitu menghentikan eksekusi di titik tertentu, menampilkan nilai setiap variabel, dan melangkah pernyataan demi pernyataan. Topik ini membahas tiga kemampuan inti debugger, yaitu breakpoint, watch, dan navigasi call stack, lalu menutupnya dengan latihan perbaikan program yang sengaja salah. Prosedurnya dijalankan pada editor dengan dukungan debugger seperti Visual Studio, Visual Studio Code, atau Rider.
Breakpoint#
Breakpoint adalah penanda pada satu baris kode yang menghentikan program sebelum baris itu dijalankan. Pada Visual Studio, breakpoint ditempatkan dengan mengeklik pinggiran editor atau menekan F9 pada baris yang dipilih, sedangkan Visual Studio Code menyediakannya melalui pinggiran editor yang sama dalam tampilan Run and Debug. Program kemudian dijalankan dalam mode debugging, misalnya dengan F5 pada Visual Studio, dan bukan melalui dotnet run biasa, karena perintah CLI tidak melekatkan debugger apa pun.
Saat program berhenti, keadaannya disebut break mode, yaitu semua variabel masih hidup dan eksekusi menunggu perintah. Dari titik ini eksekusi dapat dilangkahi dengan dua perintah utama, yaitu step over untuk menjalankan satu baris lalu berhenti lagi di baris berikutnya, serta step into untuk masuk ke dalam metode yang dipanggil pada baris tersebut. Program dapat dilanjutkan sampai breakpoint berikutnya dengan continue. Bila satu baris perlu berhenti hanya pada kondisi tertentu, Visual Studio menyediakan conditional breakpoint melalui menu klik kanan pada breakpoint, misalnya berhenti hanya ketika i == 3.
Selain breakpoint yang dipasang manual, debugger juga berhenti otomatis ketika exception dilempar. Jendela kecil bernama Exception Helper menampilkan jenis exception, pesannya, dan baris pelemparnya, sehingga titik pemeriksaan pertama sering kali tidak perlu dicari.
Watch dan inspeksi variabel#
Saat eksekusi berhenti, arahkan kursor ke variabel mana pun dan editornya menampilkan nilai terkini pada kotak kecil di atasnya. Jendela Locals mendaftar seluruh variabel lokal pada metode yang sedang berjalan beserta nilainya, sedangkan jendela Watch menampung ekspresi yang dipantau sepanjang sesi debugging, misalnya i, data.Length, atau data[i]. Ekspresi pada Watch dievaluasi ulang setiap kali eksekusi berhenti, sehingga perubahan nilainya dapat diikuti langkah demi langkah.
Pemilihan ekspresi yang tepat mempercepat diagnosis. Variabel pengendali perulangan dan panjang koleksi adalah kandidat pertama untuk kejadian indeks di luar batas, sedangkan nilai antara perhitungan berguna untuk hasil yang tidak sesuai harapan. Visual Studio juga menyediakan jendela Autos yang menampilkan variabel pada baris saat ini dan baris sebelumnya secara otomatis.
Navigasi call stack#
Call stack mencatat rantai metode yang sedang berjalan, dari metode utama program di dasar hingga metode yang sedang mengeksekusi kode di puncaknya. Setiap baris pada jendela Call Stack disebut frame, yaitu satu panggilan metode beserta baris berikutnya yang akan dijalankan. Mengeklik dua kali sebuah frame memindahkan konteks pemeriksaan ke metode tersebut, sehingga nilai variabel lokal pada pemanggilnya dapat diperiksa tanpa menghentikan program.
Ketika exception dilempar, jendela Call Stack menampilkan jalur dari baris pelempar hingga metode utama, dan frame paling atas adalah tempat asal kegagalannya. Baris teratas tidak selalu menyatakan akar masalah, karena data yang buruk sering dibuat pada frame yang lebih bawah. Karena itu, navigasi ke bawah beberapa frame menjadi langkah baku setelah debugger berhenti pada exception.
Program berikut memuat rantai pemanggilan dua metode yang akan tampak pada jendela Call Stack. Bila breakpoint ditempatkan pada baris total += nilai dan program dijalankan dalam mode debugging, jendela Call Stack menampilkan tiga frame dari atas ke bawah, yaitu Jumlah, HitungRataRata, dan metode utama program. Struktur inilah yang dibaca dari atas ke bawah setiap kali kegagalan perlu dilacak.
// Rantai pemanggilan yang akan tampak pada jendela call stack saat breakpoint berjalan.
static double HitungRataRata(int[] data) => (double)Jumlah(data) / data.Length;
static int Jumlah(int[] data)
{
int total = 0;
foreach (int nilai in data)
{
total += nilai;
}
return total;
}
int[] nilai = { 80, 90, 100 };
Console.WriteLine($"Rata-rata: {HitungRataRata(nilai)}");Rata-rata: 90Menelusuri program yang salah dengan debugger#
Program berikut menghitung rata-rata tiga nilai ujian, tetapi versi pertamanya sengaja salah dan berakhir dengan exception. Salin programnya ke berkas Program.cs, jalankan dalam mode debugging, lalu ikuti alur latihan pada prosa di bawahnya.
// Program latihan debugging: rata-rata yang salah, lalu versi yang sudah diperbaiki.
int[] nilai = { 80, 90, 100 };
try
{
Console.WriteLine($"Rata-rata versi salah: {RataRataSalah(nilai)}");
}
catch (IndexOutOfRangeException ex)
{
Console.WriteLine($"Berhenti saat debugging: {ex.Message}");
}
Console.WriteLine($"Rata-rata versi benar: {RataRata(nilai)}");
static double RataRataSalah(int[] data)
{
int total = 0;
for (int i = 0; i <= data.Length; i++)
{
total += data[i];
}
return (double)total / data.Length;
}
static double RataRata(int[] data)
{
int total = 0;
for (int i = 0; i < data.Length; i++)
{
total += data[i];
}
return (double)total / data.Length;
}Berhenti saat debugging: Index was outside the bounds of the array.
Rata-rata versi benar: 90Saat dijalankan, Exception Helper berhenti pada baris total += data[i] di dalam RataRataSalah dan melaporkan IndexOutOfRangeException. Tempatkan breakpoint pada baris for, jalankan lagi, lalu tambahkan i dan data.Length ke jendela Watch. Langkahi perulangan dengan step over dan perhatikan i bertambah dari 0 sampai 3, sedangkan data.Length tetap 3. Indeks yang sah untuk array berisi tiga elemen hanyalah 0 sampai 2, sehingga kondisi i <= data.Length keliru dan diganti menjadi i < data.Length.
Setelah kondisi diperbaiki, program menghasilkan rata-rata 90 tanpa exception, sebagaimana baris terakhir keluaran di atas. Nilai 90 sesuai perhitungan manual, yaitu 270 dibagi 3. Alur ini adalah pola kerja debugging yang sama untuk kegagalan lain, yaitu berhenti pada titik kegagalan, memeriksa nilai yang terlibat, merumuskan hipotesis, lalu memverifikasinya dengan menjalankan ulang.
Kesalahan umum#
- Penelusuran hanya mengandalkan
Console.WriteLine. Baris tulis tambahan menyebar di seluruh kode dan harus dibersihkan setelahnya, sedangkan breakpoint memeriksa keadaan tanpa mengubah kode. Gunakan pencetakan hanya untuk catatan yang memang dimaksudkan permanen. - Kode disunting saat break mode tanpa memulai ulang sesi. Fitur hot reload, yaitu penerapan perubahan kode tanpa memulai ulang program, dapat membuat keadaan lama tetap tersimpan dan menyesatkan pemeriksaan. Mulai ulang sesi debugging setelah perubahan diterapkan.
- Baris teratas call stack dianggap pasti penyebabnya. Baris itu hanya tempat exception dilempar, sedangkan penyebabnya sering dibuat pada frame yang lebih bawah. Telusuri frame ke bawah sampai data yang buruk ditemukan.
Ringkasan#
- Breakpoint menghentikan program sebelum baris terpilih dijalankan, dan step over serta step into memandu perjalanan eksekusi setelahnya.
- Jendela Locals, Autos, dan Watch menampilkan nilai variabel dan ekspresi pada setiap langkah eksekusi.
- Call stack menampilkan frame dari metode utama hingga titik kegagalan, dan frame yang lebih bawah sering memuat penyebab sebenarnya.
- Debugger berhenti otomatis pada exception lewat Exception Helper, yang menampilkan jenis, pesan, dan lokasi pelemparnya.
Referensi#
- Overview of the debugger - Visual Studio — Microsoft Learn — Tur fitur debugger, termasuk breakpoint, jendela Watch, dan jendela Call Stack.
- Use the right type of breakpoint - Visual Studio — Microsoft Learn — Jenis-jenis breakpoint, termasuk conditional breakpoint dan langkah penggunaannya.