Kesalahan pada program MATLAB jarang berdiri sendiri, karena satu nilai yang salah menjalar ke seluruh perhitungan sesudahnya. Topik ini membahas cara menelusurinya secara sistematis: alur debugging di editor dengan breakpoint, perintah setara dbstop dari Command Window, kegagalan awal yang dibangkitkan dengan error dan assert, penangkapan error dengan try/catch, serta penelusuran sederhana dengan cetakan bertingkat. Setelah topik ini, kesalahan dapat dipersempit ke satu fungsi dan satu baris, bukan dikejar dengan menebak.
Alur debugging di editor#
Debugging di editor berjalan sebagai siklus yang tetap: hentikan program pada titik yang dicurigai, periksa keadaan saat itu, jalankan selangkah demi selangkah, lalu ulangi. Titik henti disebut breakpoint, dan pemasangannya dilakukan dengan mengklik tanda putus pada sisi kiri editor di sebelah baris yang dicurigai atau dengan tombol F12 pada Windows dan Linux. Siklus lengkapnya berlangsung sebagai berikut.
- Pasang breakpoint pada baris tempat hasil mulai mencurigakan, biasanya sebelum dan sesudah perhitungan yang dicurigai sebagai penyebab.
- Jalankan berkas dengan tombol Run (F5). Eksekusi berhenti tepat sebelum baris bertanda, dan prompt berubah menjadi
K>>yang menandakan mode debug aktif. - Periksa keadaan program saat berhenti: arahkan kursor ke nama variabel pada editor untuk melihat isinya, atau buka panel Workspace yang memuat seluruh variabel beserta ukurannya.
- Jalankan selangkah: Step (F10) menjalankan satu baris, Step In (F11) masuk ke dalam fungsi yang sedang dipanggil, dan Step Out (Shift+F11) menyelesaikan fungsi saat ini lalu berhenti kembali.
- Lanjutkan dengan Continue (F5) sampai breakpoint berikutnya, lalu perbaiki kode dan jalankan ulang untuk memastikan kesalahan hilang.
Alur ini memerlukan editor interaktif, sehingga tidak direproduksi sebagai keluaran contoh pada jalur ini. Seluruh langkahnya juga tersedia sebagai perintah teks, dan perintah itulah yang memungkinkan debugging berjalan tanpa tetikus.
Gagal awal dengan error dan assert#
Menolak masukan yang tidak sah di awal jauh lebih murah daripada menelusuri akibatnya setelah perhitungan berjalan jauh. Perintah error dengan identifier menghentikan eksekusi sambil membawa dua informasi: identifier penyebab dan pesan yang sudah terformat. Keduanya dapat diperiksa tanpa menghentikan skrip pemanggil karena try/catch menangkap error itu lebih dahulu.
try
error('suhu:diBawahNolMutlak', 'nilai %g berada di bawah nol mutlak', -500);
catch e
fprintf('id : %s\n', e.identifier);
fprintf('pesan : %s\n', e.message);
endid : suhu:diBawahNolMutlak
pesan : nilai -500 berada di bawah nol mutlakPola yang sama dipasang di dalam fungsi supaya validasi terjadi pada batas masukan. Fungsi berikut menolak masukan kosong dan masukan di bawah nol mutlak sebelum menghitung suhu Celsius, dan pemanggilnya tetap mendapat kesempatan menangkap error itu. Keberadaan argumen ditangani paling awal melalui nargin, disusul pemeriksaan jenis data dan rentang nilainya.
function c = konversiSuhu(f)
% KONVERSISUHU mengubah derajat Fahrenheit menjadi derajat Celsius.
% KONVERSISUHU(f) memvalidasi masukan lebih dahulu, lalu menghitungnya.
% Tanpa argumen, contoh 212 derajat Fahrenheit dipakai.
if nargin < 1
f = 212; % titik didih air sebagai contoh bawaan
end
if ~isnumeric(f) || isempty(f)
error('suhu:masukanKosong', 'suhu Fahrenheit wajib berupa angka');
end
if any(f < -459.67)
error('suhu:diBawahNolMutlak', 'nilai %.1f berada di bawah nol mutlak', min(f));
end
c = (f - 32) * 5 / 9;
endtry
konversiSuhu(-500);
catch e
fprintf('id : %s\n', e.identifier);
fprintf('pesan : %s\n', e.message);
end
fprintf('212 F : %.1f C\n', konversiSuhu(212));id : suhu:diBawahNolMutlak
pesan : nilai -500.0 berada di bawah nol mutlak
212 F : 100.0 Cassert menargetkan keadaan yang harus benar, bukan masukan yang harus diolah. Ketika kondisinya bernilai salah, assert membangkitkan error dengan pesan yang diberikan, sehingga cocok untuk janji antar bagian kode, misalnya data tidak boleh kosong. Penangkapan dengan try/catch memperlihatkan pesannya tanpa menghentikan skrip.
dataSuhu = [];
try
assert(numel(dataSuhu) > 0, 'data kosong tidak dapat diproses');
catch e
fprintf('pesan assert: %s\n', e.message);
end
dataSuhu = [21 23 22];
try
assert(numel(dataSuhu) > 0, 'data kosong tidak dapat diproses');
fprintf('lanjut: %d data diproses\n', numel(dataSuhu));
catch e
fprintf('pesan assert: %s\n', e.message);
endpesan assert: data kosong tidak dapat diproses
lanjut: 3 data diprosesBreakpoint dari Command Window dengan dbstop#
Seluruh kendali breakpoint tersedia sebagai perintah: dbstop memasang breakpoint, dbclear melepasnya, dbcont melanjutkan eksekusi yang sedang berhenti, dan dbquit keluar dari mode debug tanpa menyelesaikan program. Bentuk dbstop if error bahkan menghentikan program pada baris tempat error apa pun terjadi, sehingga titik kesalahan ditemukan tanpa perlu ditebak lebih dahulu. Urutan perintah berikut menelusuri fungsi konversiSuhu dari bagian sebelumnya.
% tidak-dijalankan
% Perintah ini menuntut sesi interaktif karena eksekusi berhenti menunggu perintah berikutnya.
dbstop in konversiSuhu at 9 % berhenti sebelum baris validasi dijalankan
konversiSuhu(-500) % berjalan lalu berhenti, prompt K>> muncul
dbcont % lanjutkan sampai akhir atau breakpoint berikutnya
dbclear in konversiSuhu % lepas breakpoint pada berkas itu
dbquit % keluar dari mode debug tanpa menyelesaikan skripSaat program berhenti pada breakpoint, Command Window berpindah ke mode debug. Seluruh variabel fungsi yang sedang berjalan dapat diperiksa dengan mengetik namanya, dan fungsi lain juga dapat dipanggil untuk menguji dugaan perbaikan. Perintah dbstatus mendaftar breakpoint yang masih terpasang, dan dbstep menjalankan satu baris sebagai padanan tombol Step. Bentuk dbstop in konversiSuhu tanpa nomor baris berhenti pada baris pertama yang dapat dijalankan, dan dbclear all melepas seluruh breakpoint dalam satu perintah. Kombinasi lengkapnya menjadikan siklus pasang, periksa, dan lanjutkan dapat dijalankan sepenuhnya dari papan ketik.
Menangkap error dengan try/catch#
Blok try/catch membatasi ledakan error pada satu bagian yang memang berisiko gagal, misalnya pembacaan berkas yang mungkin tidak ada. Objek e pada klausa catch memuat identifier, pesan, dan jejak pemanggilan, dan ketiganya dapat dicetak sebagai catatan sebelum program memutuskan langkah berikutnya. Blok try sebaiknya dijaga sekecil mungkin agar error yang tertangkap memang milik operasi yang dimaksud, sebab cakupan yang terlalu lebar ikut menyembunyikan kegagalan dari bagian lain. Fungsi lasterror mengembalikan rekaman yang sama untuk kode yang memakai bentuk lama.
try
muat = load('catatanSuhuTidakAda.mat');
catch e
fprintf('id kosong : %d\n', isempty(e.identifier));
fprintf('pesan : %s\n', e.message);
riwayat = lasterror();
fprintf('bingkai riwayat: %d\n', numel(riwayat.stack));
end
fprintf('program tetap berlanjut sampai baris ini\n');id kosong : 1
pesan : load: unable to find file catatanSuhuTidakAda.mat
bingkai riwayat: 1
program tetap berlanjut sampai baris iniIdentifier kosong karena kegagalan pembacaan berkas pada implementasi ini tidak membawa identifier khusus, sedangkan pesannya menyebut berkas yang dicari. Nilai satu pada bingkai riwayat menyatakan error terjadi pada satu tingkat pemanggilan, dan pada program bertingkat, jejak itulah yang menunjukkan fungsi mana yang membangkitkan error. Teks pesan error seperti ini berbeda antar implementasi, tetapi informasinya tetap sama, yaitu berkas mana yang gagal dibaca. Setelah catatan tercetak, eksekusi berlanjut ke baris setelah blok, dan program dapat memutuskan untuk berhenti, memakai data cadangan, atau melanjutkan tanpa data itu.
Penelusuran dengan cetak bertingkat#
Ketika editor tidak tersedia, penelusuran paling sederhana adalah mencetak keadaan program pada tiap langkah dengan fprintf. Cetak bertingkat menirukan Step pada editor karena lekukan menunjukkan kedalaman, dan keadaan yang dicetak hanyalah yang benar-benar menentukan hasil. Pada contoh berikut, yang dicetak adalah pembanding dan nilai maksimum yang sedang dipegang pada tiap langkah, sehingga keputusan penggantian nilai terlihat pada keluarannya.
dataSuhu = [14 8 22 5];
nilaiMaks = dataSuhu(1);
for k = 2:numel(dataSuhu)
fprintf('langkah %d: bandingkan %d dengan %d\n', k, dataSuhu(k), nilaiMaks);
if dataSuhu(k) > nilaiMaks
nilaiMaks = dataSuhu(k);
fprintf(' nilai maks baru: %d\n', nilaiMaks);
end
end
fprintf('hasil: %d\n', nilaiMaks);langkah 2: bandingkan 8 dengan 14
langkah 3: bandingkan 22 dengan 14
nilai maks baru: 22
langkah 4: bandingkan 5 dengan 22
hasil: 22Pada keluaran di atas, baris berlekuk pada langkah ketiga memperlihatkan momen nilai maksimum diganti, dan empat langkah itu cukup untuk memastikan alurnya benar. Kelemahan cara ini adalah cetakan yang harus dibersihkan setelah penyebab ditemukan, sehingga cetak bertingkat cocok untuk penyelidikan singkat dan bukan alat tetap. Cetak bertingkat tetap berguna ketika kesalahan hanya muncul pada data tertentu atau saat editor tidak dapat dipakai, misalnya pada sesi jarak jauh yang hanya menampilkan teks.
Kesalahan umum#
- Menelan error dengan catch kosong. Blok
catchtanpa isi membuat kegagalan tidak terlihat dan hasil akhir kehilangan jaminan kebenarannya. Cetak konteks error lebih dahulu, lalu putuskan secara eksplisit antara melanjutkan, memakai cadangan, atau menghentikan program. - Membiarkan validasi menunggu sampai perhitungan dalam. Masukan yang tidak sah sebaiknya ditolak di ambang fungsi dengan
errorber-identifier, karena error yang muncul jauh dari penyebabnya memaksa penelusuran mundur yang panjang. - Menelusuri dengan menebak tanpa mempersempit. Pasang breakpoint atau cetakan penelusuran pada titik tengah alur, bukan pada seluruh baris sekaligus. Satu titik henti yang dipilih dengan baik membagi wilayah pencarian menjadi dua, sehingga beberapa siklus saja sudah cukup menemukan baris penyebab.
Ringkasan#
- Siklus debugging berjalan pasang, periksa, lanjutkan, baik lewat editor dengan breakpoint maupun lewat perintah
dbstop,dbcont,dbclear, dandbquit. - Validasi batas masukan memakai
errorber-identifier, dan janji keadaan antar bagian kode memakaiassertdengan pesan. try/catchmenangkap error beserta konteksnya pada objekedanlasterror, sehingga kegagalan dapat dicatat sebelum program melanjutkan.- Cetak bertingkat dengan
fprintfmenjadi penelusuran darurat ketika editor tidak tersedia, dan dibersihkan setelah penyebab ditemukan.
Referensi#
- dbstop — MathWorks
— Rujukan resmi pemasangan breakpoint beserta bentuk
dbstop if error. - assert — MathWorks — Rujukan resmi asersi kondisi beserta pembangkitan pesan kegagalan.
- MException — MathWorks — Rujukan resmi objek error yang memuat identifier, pesan, dan jejak pemanggilan.