A. Mengevaluasi Debuging Pada Aplikasi Sederhana
Debugger atau perkakas pendebug adalah program
komputer yang digunakan untuk menguji dan mendebug
program lainnya (program target). Kode yang diujikan dijalankan pada sebuah instruction set
simulator (ISS). Beberapa debugger menawarkan dua mode operasi, yaitu
simulasi parsial atau penuh, untuk membatasi dampak.Kerusakan terjadi
jika program tidak bisa melanjutkan secara normal karena adanya bug pemrograman.
Misalnya: program mungkin akan mencoba menggunakan instruksi yang tidak
tersedia pada CPU
versi terbaru atau mencoba mengakses memori terproteksi. (WIKI, 2016)
B.
Debugging (pengertian)
DEBUGGING
Debugging adalah sebuah metode yang
dilakukan oleh para pemrogram dan pengembang perangkat lunak untuk mencari
dan mengurangi bug,
atau kerusakan di dalam sebuah program
komputer atau perangkat keras sehingga perangkat tersebut bekerja
sesuai dengan harapan. Debugging cenderung lebih rumit ketika beberapa
subsistem lainnya terikat dengan ketat dengannya, mengingat sebuah perubahan di
satu sisi, mungkin dapat menyebabkan munculnya bug lain di dalam
subsistem lainnya.
Bug dengan
terjemahan langsung ke bahasa Indonesia adalah serangga atau kutu. Bug
merupakan suatu kesalahan desain pada suatu perangkat
keras komputer atau perangkat lunak komputer yang menyebabkan peralatan
atau program itu tidak berfungsi semestinya. Bug
umumnya lebih umum dalam dunia perangkat lunak dibandingkan dengan perangkat
keras.
Kenapa dinamakan bug?
Tahun 1945 sewaktu ukuran komputer masih
sebesar kamar, pihak militer Amerika
Serikat menggunakan komputer yang bernama “Mark 1”. Suatu hari komputer ini
tidak berfungsi dengan semestinya, setelah komputer itu diperiksa ternyata ada
suatu bagian perangkat keras di mana terdapat serangga yang tersangkut. Setelah
serangga itu diangkat dari perangkat keras, komputer dapat berfungsi dengan
baik. Maka sejak saat itu kata bug lekat dengan masalah-masalah pada
komputer. Debugging
adalah proses menghilangkan bug dari suatu program.
Pengujian perangkat lunak adalah proses yang dapat
direncanakan dan ditentukan secara sistematis. Desain test case dapat dilakukan,
strategi dapat ditentukan, dan hasil dapat dievaluasi berdasarkan
harapan-harapan yang ditentukan sebelumnya.
Debugging terjadi sebagai
akibat dari pengujian yang berhasil. Jika test case mengungkap kesalahan, maka
debugging adalah proses yang menghasilkan penghilangan kesalahan. Perekayasa
perangkat lunak yang mengevaluasi hasil suatu pengujian sering dihadapkan pada
indikasi “simtomatis” dari suatu masalah pernagkat lunak, yaitu bahwa
manisfestasi eksternaldari kesalahan dan penyebab internal kesalahan dapat
tidak memiliki hubungan yang jelas satu dengan lainnya. Proses mental yang
dipahami secara buruk yang menghubungkan sebuah symptom dengan suatu penyebab
disebut debugging.
Proses Debugging
Debugging bukan merupakan pengujian, tetapi selalu terjadi
sebagai bagian akibat dari pengujian. Proses debungging dimulai dengan eksekusi
terhadap suatu test case. Hasilnya dinilai, dan ditemukan kurangnya hubungan
antara harapan dan yang sesungguhnya. Dalam banyak kasus, data yang tidak
berkaitan merupakan gejala dari suatu penyebab pokok tetapi masih tersembunyi,
sehingga perlu ada koreksi kesalahan.
Proses debugging
akan selalu memiliki salah satu dari dua hasil akhir berikut:
- Penyebab akan ditemukan, dikoreksi, dan dihilangkan, atau
- Penyebab tidak akan ditemukan.
Dalam kasus yang terakhir, orang yang melakukan debugging
mungkin mencurigai suatu penyebab, mendesainsuatu test case untuk membantu
kecurigaannya, dan bekerja untuk koreksi kesalahan dengan gaya yang iterative.
Beberapa karakteristik bug memberi kunci :
- Gejala dan penyebab dapat jauh secara geografis, dimana gejala dapat muncul didalam satu bagian dari suatu program, sementara penyebab dapat ditempatkan pada suatu sisi yang terlepas jauh.
- Gejala dapat hilang (kadang-kadang) ketika kesalahan yang lain dibetulkan.
- Gejala dapat benar-benar disebabkan oleh sesuatu yang tidak salah (misalnya pembulatan yang tidak akurat).
- Simpton dapat disebabkan oleh kesalahan manusia yang tidak dapat dengan mudah ditelusuri.
- Gejala dapat merupakan hasil dari masalah timing, dan bukan dari masalah pemrosesan.
- Mungkin sulit untuk mereproduksi kondisi input secara akurat (misalnya aplikasi real time dimana pengurutan input tidak ditentukan).
- Gejala dapat sebentar-sebentar. Hal ini sangat umum pada system yang embedded yang merangkai perangkat lunak dan perangkat keras yang tidak mungkin dilepaskan.
- Gejala dapat berhubungan dengan penyebab yang didistribusikan melewati sejumlah tugas yang bekerja pada prosesor yang berbeda.
Selama debugging, kita menemukan kesalahan-kesalahan mulai
dari gangguan yang halus (missal format output yang tidak betul) sampai
katrastropis (misalnya kegagalan system yang menyebabkan kerusakan fisik atau
ekonomis).
Sebagai akibat dari peningkatan keslahan, jumlah tekanan
untuk menemukan kesalahan juga bertambah. Sering kali tekanan memaksa seorang
pengembang perangkat lunak untuk membetulkan keslahan dan pada saat yang sama
memunculkan lagi dua kesalahan baru.
Pertimbangan Psikologis
Sayangnya muncul banyak bukti bahwa kekuatan debugging
adalah sifat bawaan manusia. Banyak orang yang cakap dalam hal ini, sementara
banyak juga yang tidak. Menanggapi aspek manusia dari debugging. Shneiderman
[SHN80] menyatakan :
Debugging merupakan salah satu dari berbagai bagian
pemrograman yang membuat lebih frustasi. Debugging memiliki elemen pemecahan
masalah atau pengganggu otak, yang bersama dengan penghindaran kesadaran bahwa
Anda melakukan suatu kesalahan. Kekhawatiran yang meningkat dan keengganan
untuk menerima, kesalahan akan meningkatkan kesulitan tugas. Sayangnya, ada
keluhan yang sangat mendalam mengenai pembebasan dan pengurangan ketegangan
ketika pada akhirnya bug ……… dikoreksi.
Meskipun mungkin sulit untuk mempelajari debugging,
sejumlah pendekatan terhadap masalah tersebut dapat diusulkan. Kita akan
melihat dalam sub bab selanjutnya.
Pendekatan-pendekatan Debugging
Tanpa memperhatikan pendekatan yang diambil, debugging
memiliki satu sasaran yang diabaikan, untuk menemukan dan mengkoreksi penyebab
kesalahan perangkat lunak. Sasaran tersebut direalisasi dengan suatu kombinasi
evaluasi yang sistematis, intuisi, dan keberuntungan.
Bradley (BRA85) menggambarkan pendekatan Debugging dengan
cara berikut :
Debugging adalah sebuah aplikasi langsung dari
metodekeilmuan yang telah dikembangkan selama 2500 tahun. Dasar dari debugging
adalah meletakkan sumber-sumber masalah (penyebab) dengan partisi biner melalui
hipotesis kerja yang memperkirakan nilai-nilai baru yang akan diuji.
Ambillah contoh non-perangkat lunak sederhana,
yaitu :
Lampu dirumah saya tidak bekerja. Bila tidak ada yang
bekerja didalam rumah itu, penyebabnya tentu pada pemutus rangkaian utama atau
sebab dari luar. Saya melihat sekeliling untuk melihat apakah lampu para
tetangga juga mati. Saya memasukkan lampu yang dicurigai kedalam soket yang
bekerja dan menyelidiki lampu rangkaian yang dicurigai. Begitulah berbagai
pilihan hipotesa dan pengujian.
Secara umum, tiga kategoti pendekatan debugging
dapat diusulkan (MYE79) :
- 1. Gaya yang kasar (Brute force)
Kategori debugging brute force mungkin merupakan
yang paling umum dan metode yang paling efisien untuk mengisolasi penyebab
kesalahan perangkat lunak. Kita mengaplikasikan metode debugging brute
force bila semua yang lain telah gagal. Dengan menggunakan filosofi
”biarkan komputer menemukan kesalahan”, tempat sampah memori dipakai,
penelusuran runtime dilakukan, dan program dibebani dengan statemen WRITE. Kita
mengharapkan bahwa dimanapun didalam rawa informasi yang diproduksi, kita akan
menemukan suatu kunci yang akan membawa kita kepada penyebab kesalahan.
Meskipun banyaknya informasi yang dihasilkan pada akhirnya akan membawa kita
meraih sukses, lebih sering dia menyebabkan kita menghambur-hamburkan usaha dan
waktu. Kita harus memikirkannya terlebih dahulu.
- 2. Penelusuran balik (backtracking)
Backtracking adalah
pendekatan debugging yang sangat umum yang dapat digunakan secara sukses
didalam program yang kecil. Mulai pada sisi dimana suatu gejala diungkap, kode
sumber ditelusuri balik (secara manual) samapai sisi penyebab ditemukan.
Sayangnya, bila jumlah baris sumber bertambah, maka jumlah jalur balik
potensial dapat sangat banyak.
- 3. Eliminasi penyebab
Cause elimination
dimanisfestasikan oleh induksi atau deduksi serta mengawali konsep partisi
biner. Data yang berhubungan dengan kejadian kesalahan dikumpulkan untuk
mengisolasi penyebab potensial. Hipotesis penyebab dibuat dan data digunakan
untuk membuktikan penolakan hipotesis tersebut. Sebagai alternatif, daftar
semua penyebab yang mungkin dikembangkan dan dilakukan pengujian untuk
mengeliminasi masing-masing kesalahan. Jika pengujian awal menunjukkan bahwa
suatu hipotesis penyebab memberikan gambaran hasil yang jelas, maka data itu
disaring sebagai usaha untuk mengisolasi bug.
Masing-masing pendekatan debugging tersebut dapat ditambah
dengan piranti debugging. Kita dapat mengaplikasikan berbagai kompiler
debugging yang luas, bantuan debugging yang dinamis (tracer), generator test
case, ruang sisa memori dan peta cross-reference. Namun piranti bukanlah
pengganti bagi evaluasi yang berhati-hati yang didasarkan atas dokumen desain
perangkat lunak yang lengkap dan kode sumber yang jelas.
Sekali bug ditemukan, bug harus dibetulkan. Tetapi seperti
telah kita catat, koreksi terhadap suatu bug dapat memunculkan kesalahan lain
sehingga lebih banyak merugikan daripada menguntungkan.
Van Vleck (FAN89) mengusulkan tiga pertanyaan sederhana
yang harus diajukan kepada perekayasa perangkat lunak sebelum melakukan koreksi
yang menghilangkan penyebab suatu bug, yaitu :
- 1. Apakah penyebab bug direproduksi didalam bagian lain program tersebut?
Dalam berbagai situasi, kesalahan program disebabkan oleh
sebuah contoh logika yang keliru yang dapat dibuat ulang ditempat lain.
Pertimbangan eksplisit dari contoh logika tersebut akan menghasilkan penemuan
kesalahan yang lain.
- 2. Apa ”bug selanjutnya,” yang akan dimunculkan oleh perbaikan yang akan dibuat?
Sebelum koreksi dibuat, kode sumber (atau lebih
baik,desain) harus dievaluasi untuk memperkirakan pemasangan logika dan
struktur data. Bila koreksi akan dilakukan pada bagian program yang akan
dirangkai, maka harus ada perhatian khusus bila banyak perubahan dilakukan.
- 3. Apa yang dapat kita lakukan untuk menghindari bug ini didalam tempat pertama?
Pertanyaan ini merupakan langkah pertama untuk membangun
pendekatan jaminan kualitas perangkat lunak statistik. Bila kita mengkoreksi
proses dan produk, bug akan dihilangkan dari program yang ada dan dapat
dieliminasi dari semua program selanjutnya. (REVOLUTIONER, 2009)
C. Teknik Debugging
Dalam Membuat Program
Istilah
debugging dalam programming, artinya adalah mencari kesalahan algoritma dalam
program yang sedang dibuat. Lho… bagaimana kita tahu ada algoritma yang salah?
Algoritma yang salah ini akan mengakibatkan hasil atau output yang salah atau
tidak seperti yang diharapkan. Istilah kesalahan ini sering disebut ‘algoritmic
error’.
Contoh sederhana dari algoritmic error
ini adalah, misalkan kita akan membuat program untuk menjumlahkan dua buah
bilangan bulat, katakanlah A dan B. Dan program yang dibuat adalah sebagai
berikut (dalam Pascal):
program
jumlahkan;
var a, b, hasil : integer;
begin
write('Masukkan nilai A : ');
readln(a);
write('Masukkan nilai B : ');
readln(b);
hasil := a - b;
write('Hasil penjumlahannya adalah : ',hasil);
end.
var a, b, hasil : integer;
begin
write('Masukkan nilai A : ');
readln(a);
write('Masukkan nilai B : ');
readln(b);
hasil := a - b;
write('Hasil penjumlahannya adalah : ',hasil);
end.
Apabila kita jalankan program di atas
atau kita compile, maka tidak akan ada error yang muncul, dalam hal ini syntax
error (error yang terkait dengan aturan penulisan program). Namun ketika
dijalankan, dan misalkan kita masukkan nilai A = 5 dan B = 4, maka hasil yang
muncul adalah 1 (bukannya 9). Nah… inilah yang dimaksud dengan algoritmic
error, atau error yang disebabkan kesalahan dalam langkah penyelesaian masalah.
Contoh sederhana lain, tapi hal ini tidak
ada kaitannya dengan program, yaitu tentang algoritma merebus mie instan wah jadi laper nih…
Misalkan, diberikan algoritma untuk
merebus mie instan sbb:
- Buka bungkus mie
- Siapkan panci dan taruh panci di atas kompor
- Masukkan mie ke dalam panci
- Nyalakan api kompor kira-kira 3 menit
- Masukkan air mentah 2 gelas
- Matikan kompor
- Taruh mie ke dalam mangkuk
Nah… bagaimana pendapat Anda tentang
algoritma di atas? Ya… kita akan tetap mendapatkan output dari proses merebus
mie, tapi tidak sesuai yang diharapkan, yaitu mienya gosong dan airnya masih
mentah Mengapa demikian? ya… hal ini karena
ada langkah yang salah dalam merebus mie. Inilah contoh algoritmic error.
So… saya harap Anda sudah tahu maksud
algoritmic error. Sekarang, bila Anda mendapatkan program yang Anda buat
mengalami algoritmic error, apa yang harus dilakukan? Ya… langkah satu-satunya
adalah mencari letak proses yang salah dalam algoritmanya. Nah… proses
pencarian ini dinamakan debugging.
Mengapa disebut debugging? Konon istilah tersebut muncul karena si
penemu kata ini pada waktu itu juga sedang mencari kesalahan program, namun
saking jengkelnya karena gak ketemu-ketemu, trus dia menyebutnya si ‘kutu’ atau
‘bug’. Kemudian istilah mencari si kutu program ini, sering disebut
‘debugging’.
Kalau kita mendapati syntax error, maka
dapat dengan mudah dan cepat kita akan menemukannya. Hal ini karena biasanya
akan muncul warning adanya penulisan yang salah dan biasanya akan disertai
dengan nomor baris yang salah tersebut. Nah… kalau algoritmic error, proses
pencariannya tidak mudah.
So… bagi para mahasiswaku atau
pengunjung setia blog ini, bila program Anda dicompile tidak ada error, jangan
bersenang-senang dahulu, karena tujuan proses compile itu hanya mencari ada
tidaknya syntax error. Siapa tahu program Anda menyimpan si kutu
OK… kita kembali ke laptop, eh salah…
kembali ke teknik debugging
Trus… sekarang bagaimana langkah
debugging, bila program sudah jadi namun hasilnya salah? Ya… untuk proses ini,
Anda harus mengeceknya step by step sesuai alur algoritma program yang Anda
buat. Bagaimana cara mengeceknya? Kalau saya pribadi, atau yang sering saya
lakukan adalah menampilkan output di setiap proses. Sedangkan proses setelah
bagian yang sedang saya cek tersebut, saya nonaktifkan atau saya buat menjadi komentar.
Perhatikan contoh berikut ini. Contoh
ini baru saja saya gunakan untuk menjelaskan teknik debugging ketika
perkuliahan.
write(kombinasi);program cariKombinasi; var n, m : integer;
kombinasi : real; function faktorial(x : integer) : real; var i : integer;
hasil : real; begin
hasil := 1;
for i:=1 to x do
begin
hasil := hasil * i;
end;
faktorial := hasil; end; begin
n := 3;
m := 2;
kombinasi := faktorial(n)/faktorial(n-m)*faktorial(m);
end.
Program di atas dibuat dengan tujuan
untuk mencari hasil dari kombinasi n, m atau C(n, m). Dari contoh di atas,
dipilih n = 3 dan m = 2. Menurut perhitungan kita, hasil yang benar dari
kombinasi tersebut adalah 3. Namun apa yang terjadi bila program di atas
dijalankan? Ya… dari sisi syntax error tidak ada, namun hasilnya adalah 12.
Tentu hal ini salah.
Lantas… bagaimana mengetahui letak
kesalahannya? Ya… untuk melakukan hal ini, kita harus mengecek terlebih dahulu
apakah function faktorial() sudah berfungsi dengan baik atau belum. Untuk
mengeceknya, ya… kita tambahkan saja perintah write(faktorial(n));
begin
n := 3;
m := 2;
write(faktorial(n));
{ kombinasi := faktorial(n)/faktorial(n-m)*faktorial(m);
write(kombinasi);}
end.
Oya… untuk baris perintah setelah
write(faktorial(n)) ini hendaknya kita jadikan komentar dahulu supaya tidak ada
interfensi dalam proses. Apabila dijalankan, maka akan muncul output 6. Ya…
hasil ini benar karena kita menampilkan n! atau dalam hal ini 3!. Sehingga
function faktorial() tidak ada masalah dan berfungsi dengan baik.
Selanjutnya akan kita cek untuk
menghitung kombinasinya sendiri atau pada baris
kombinasi := faktorial(n)/faktorial(n-m)*faktorial(m);
Satu-satunya kemungkinan salah adalah
di sini, karena proses inilah yang dilakukan tepat sebelum ditampilkan
outputnya. Apabila kita perhatikan dengan benar, maka ada bagian yang salah
yaitu pada pembagian. Ingat rumus mencari C(n, m). Rumus yang benar haruslah
kombinasi := faktorial(n)/(faktorial(n-m)*faktorial(m));sehingga baris programnya menjadibegin
n := 3;
m := 2;
kombinasi := faktorial(n)/(faktorial(n-m)*faktorial(m));
write(kombinasi);
end.
Nah… setelah diperbaiki, barulah
program di atas akan menghasilkan output yang benar yaitu 3.
Sehingga kesimpulan dari teknik debug
ini adalah ceklah output untuk setiap langkah proses dengan menampilkannya ke
layar. Untuk menghindari interfensi dari baris program yang lain, hendaknya
baris program di bawahnya atau selanjutnya, dibuat komentar (jangan dihapus)
terlebih dahulu. Teknik ini bisa diterapkan untuk bahasa pemrograman yang lain.
ADAPUN PENJELASAN YANG LAINNYA DIBAWAH INI:
Beberapa jenis bug sangat umum di semua bahasa (kesalahan logika, kesalahan aritmatika, dsb), tapi bug tertentu hanya muncul di bahasa tertentu atau jika menggunakan framework tertentu. Jadi pengalaman coding tetap merupakan guru yang utama. Contoh bug yang sederhana adalah lupa menginisialisasi atau mereset variabel. Biasanya jika program berjalan benar pertama kali, lalu ketika diulangi tidak benar hasilnya (dan benar lagi ketika aplikasi direstart) maka penyebabnya adalah lupa mereset variabel. Contoh lain adalah menggunakan try catch secara malas, misalnya dengan membungkus seluruh fungsi dalam satu try except. Dengan cara ini, maka tidak jelas apa sumber error di sesungguhnya. Contoh bug yang spesifik terhadap bahasa adalah bug manajemen memori di C. Kesalahan mengakses memori di C sangat mudah terjadi dan biasanya akan menyebabkan crash.
assert(index >= 0);
val = values[index];
Jika index kurang dari 0, maka ada sesuatu kesalahan fatal di program kita (mungkin kesalahan logika, mungkin ada hal yang lupa ditangani). Jika asersi diaktifkan biasanya program akan berhenti dengan “Assertion error”.
Di berbagai bahasa assert ini bisa diaktifkan/nonaktifkan dengan opsi tertentu. Jadi dalam versi rilis kita bisa membuang berbagai pengecekan asersi ini.
Bug
Bug adalah segala macam cacat dalam program. Bisa saja cacatnya hanya berupa tampilan yang sedikit salah, bisa crash, bisa berupa bug security (harusnya hanya bisa diakses user X, bisa diakses user Y), kadang bug tertentu tidak muncul sampai kasus ekstreem (misalnya jika jumlah user banyak maka akan out of memory karena ada memory leak). Sumber bug bisa banyak, dari mulai salah design, salah implementasi, salah konfigurasi, dsb. Sebagai programmer, bug yang akan saya bahas adalah dari sisi implementasi (coding). Biasanya seorang programmer akan belajar sedikit demi sedkit jenis bug dari pengalaman. Semakin banyak coding, semakin banyak salah, semakin banyak belajar.Beberapa jenis bug sangat umum di semua bahasa (kesalahan logika, kesalahan aritmatika, dsb), tapi bug tertentu hanya muncul di bahasa tertentu atau jika menggunakan framework tertentu. Jadi pengalaman coding tetap merupakan guru yang utama. Contoh bug yang sederhana adalah lupa menginisialisasi atau mereset variabel. Biasanya jika program berjalan benar pertama kali, lalu ketika diulangi tidak benar hasilnya (dan benar lagi ketika aplikasi direstart) maka penyebabnya adalah lupa mereset variabel. Contoh lain adalah menggunakan try catch secara malas, misalnya dengan membungkus seluruh fungsi dalam satu try except. Dengan cara ini, maka tidak jelas apa sumber error di sesungguhnya. Contoh bug yang spesifik terhadap bahasa adalah bug manajemen memori di C. Kesalahan mengakses memori di C sangat mudah terjadi dan biasanya akan menyebabkan crash.
Source Control
Jangan heran juga kalau kadang bug baru muncul karena hal sepele, misalnya source code berubah karena keyboard tersenggol. Msalnya sebuah konstanta 1000 terdelete angka nol terakhirnya (atau bertambah satu), atau tanda “lebih besar sama dengan” terhapus menjadi lebih besar saja. Di sini penggunakan version control (yang populer saat ini: Git) sangat berguna, Anda bisa mereview segala perubahan pada source code. Source control juga memungkinkan kita melihat sejarah perubahan secara keseluruhan. Bagi security researcher, ini sering menjadi ladang untuk mencari bug baru di software open source. Jika ada yang menambahkan fungsionalitas baru, maka kemungkinan ada bug baru yang muncul.Unit Testing
Mencari dan membetulkan bug itu susah (baik bug sendiri maupun orang lain), jadi hal pertama yang perlu dicoba adalah: menghindari bug. Hal yang paling dasar adalah: kita perlu memecah program kita menjadi unit yang kecil (unit di sini berupa fungsi/kelas/method) dan menguji tiap bagian kecil tersebut. Istilahnya untuk ini adalah unit testing. Kita bisa menggunakan library tertentu untuk unit testing, atau panggil saja fungsi yang akan ditest. Saya akan mengasumsikan Anda minimal sudah bisa membuat aplikasi yang bisa dicompile dan bisa dijalankan. Jika Anda masih salah syntax, salah opsi untuk mengcompile, dsb, sebaiknya ada mulai lagi dari nol dan mulai perlahan. Dengan memecah program menjadi unit kecil dan mengujinya satu persatu, maka kesalahan umumnya bisa dilokalisasi: fungsi X ini masih salah. Pertanyaan berikutnya adalah: apa salahnya?Asersi
Saat ini kebanyakan bahasa memiliki fitur assert. Fitur ini memungkinkan kita melakukan pengecekan ekstra (yang biasanya tidak akan dilakukan di versi produksi). Assert ini biasanya digunakan untuk menyatakan kondisi yang pasti harus benar, karena jika tidak benar maka titik program berikutnya akan error fatal. Ini adalah contohnya:assert(index >= 0);
val = values[index];
Jika index kurang dari 0, maka ada sesuatu kesalahan fatal di program kita (mungkin kesalahan logika, mungkin ada hal yang lupa ditangani). Jika asersi diaktifkan biasanya program akan berhenti dengan “Assertion error”.
Di berbagai bahasa assert ini bisa diaktifkan/nonaktifkan dengan opsi tertentu. Jadi dalam versi rilis kita bisa membuang berbagai pengecekan asersi ini.
Pesan dari Compiler dan Linter
Sebelum melihat jauh ke mana-mana, coba lihat dulu apakah ada warning dari compiler Anda. Contohnya untuk potongan kode C ini:
int i;
printf("i = %d\n", i);
Compiler memberitahu:
warning: ‘i’ is used uninitialized in this function [-Wuninitialized]
Bacalah pesan error dan warning dengan teliti. Di
situ dijelaskan bahwa variabel i tidak diinisialisasi. Di C, variabel
lokal nilainya tidak bisa diprediksi jika tidak diinisialisasi.
Selain compiler, biasanya ada program yang namanya linter
untuk sebuah bahasa yang bisa memberi peringatan jika ada sesuatu yang
dianggap tidak standar atau aneh.
Print debugging
Lalu berikutnya cara paling primitif dalam debugging adalah dengan menuliskan nilai saat ini menggunakan: “print” “echo”, “printf” atau sejenisnya. Contoh sederhana, misalnya kita punya conditional di Python seperti ini (melakukan regular expression matching):
if (re.search(PATTERN, x)): # do something
Lalu bagian aksi tidak pernah dieksekusi, atau cuma dieksekusi
beberapa kali. Apakah Anda yakin patternnya benar? Coba print
sebelumnya, jangan-jangan regexnya masih salah untuk input tertentu:
print "Input ", x, "Match result ", re.search(PATTERN, x)
Tentunya tidak semua aplikasi bisa punya layar yang menampilkan teks
itu (contohnya Game, atau aplikasi grafik lain). Biasanya cara yang
lebih baik adalah menggunakan library untuk logging yang saat ini sudah
built in di banyak bahasa (misalnya ada modul logger di Python,
java.util.logging di Java, dsb). Output logging bisa dikonfigurasi
sedetail apa, dan outputnya ke mana (ke file, ke terminal, ke jaringan,
dsb).
Logging tidak hanya untuk proses development. Banyak aplikasi
menyediakan fungsi logging untuk mencatat berbagai hal yang berhubungan
dengan aplikasi untuk mendebug jika ada masalah ketika dijalankan.
Contohnya aplikasi bisa menampilkan di lognya: “berusaha melakukan
koneksi database ke server XX port YY dengan username ZZ”, yang bisa
diikuti dengan “Koneksi berhasil”, atau “Koneksi Gagal, pesan error:
invalid username or password”.
Debugger
Debugger adalah tools untuk mencari bug. Di kebanyakan IDE (Integrated Development Environment), tools ini sudah built in dan mudah dipakai. Ada juga debugger stand alone, tapi biasanya ini lebih sulit bagi pemula. Untuk menggunakan debugger pertama kita perlu mengeset breakpoint, yaitu titik berhenti sementara (break). Ketika kita mengklik “debug” maka debugger akan mulai menjalankan program sampai titik itu. Di beberapa bahasa, jika kita tidak mengeset breakpoint, maka program dihentikan sementara di titik awal. Debugger paling dasar sekalipun akan memiliki fungsi untuk menampilkan nilai variabel saat ini. Dengan menggunakan ini kita biasanya tidak perlu mencetak dengan printf, tapi untuk mencetak objek yang kompleks, kadang tetap saja keluaran print masih lebih baik. Fungsi debugger berikutnya adalah melakukan single stepping, artinya kita bisa menelusuri langkah demi langkah program. Contohnya jika kita memiliki source sederhana
diskon = 0.1
harga = 10000
harga = harga - (diskon * harga)
Kita bisa melakukan single step dan melihat nilai diskon dan harga di setiap langkah.
Jika kita memanggil fungsi lain, maka kita memiliki dua opsi, masuk
ke dalam fungsi itu (istilahnya biasanya “step into”) atau memanggil
fungsi itu, lalu segera meneruskan ke baris berikutnya (kita tidak
peduli atau tidak ingin mendebug fungsi itu, istilah ini “step over”).
Jika fungsi yang akan kita cek sangat jauh atau hanya dipanggil di
kondisi tertentu maka kita bisa menggunakan breakpoint. Biasanya di
berbagai IDE ini bisa dilakukan dengan mengklik di samping nomor baris,
dan akan muncul bulatan merah. Jika kita menekan tombol “continue”, maka
program akan dijalankan dan akan dihentikan sementara di titik
breakpoint tersebut.
Ada juga yang namanya “conditional breakpoint”. Artinya kita akan
berhenti hanya pada kondisi tertentu. Misalnya kita ingin berhenti dalam
loop setelah i > 100, karena di titik itu ada data yang aneh, maka
kita bisa menambahkan kondiri “i>100”

Beberapa debugger memiliki fungsi yang menakjubkan, misalnya GDB mendukung reverse execution
dan Visual Studio mendukung “Edit and Continue”. Untuk perubahan kecil,
kita bisa mengubah program kita tanpa menghentikan debugger.
Di beberapa environment mensetup debugging tidak mudah, tapi ketika sudah terinstall ini akan sangat berguna sekali.
Debugger level Assembly
Untuk program biasa, Anda biasanya tidak akan pernah butuh mendebug sampai level ini, tapi jika Anda membuat eksploit atau berusaha mengeksploit binary, Anda perlu tahu ini (saya pernah membuat pengantar mengenai buffer overflow jika Anda tertarik).Debugger di level assembly sebenarnya tidak berbeda jauh dari level source code. Jika kita punya source codenya, bahkan kita bisa melihat keduanya berdampingan. Di level assembly kita bisa menelusuri tiap instruksi dan juga melihat nilai register. Dengan melihat nilai register beserta flagsnya Anda bisa belajar banyak mengenai assembly.
Tools lain
Kadang debugger saja tidak cukup, tools analisis runtime seperti strace, ltrace, valgrind dsb akan berguna membantu menemukan bug terutama di kode native.Logika
Tools apapun tidak akan bisa membantu jika kita tidak punya logika yang baik. Dasar dari debugging adalah mencari kesalahan program, lalu membetulkannya agar berjalan sesuai harapan. Jadi di tahap paling awal, Anda sendiri harus tahu harapannya apa yang terjadi di setiap langkah.Contohnya jika Anda mendebug algoritma mencari nilai maksimum, Anda perlu mengerti dulu seperti apa seharusnya algoritmanya dan apakah ketika dijalankan sudah sesuai harapan. Dalam kasus ini, di langkah pertama seharusnya nilai maksimum adalah elemen pertama, di langkah kedua, jika nilainya lebih besar maka elemen ini yang jadi elemen maksimum (dan jika tidak, maka elemen pertama yang tetap menjadi maksimum), dan seterusnya untuk elemen berikutnya.
Penutup
Sebenarnya bisa panjang sekali bahasan mengenai bug software, artikel ini hanya sekedar perkenalan. Anda sebaiknya mendalami berbagai tools supaya lebih produktif dalam bekerja, dari mulai tools source control, editor, debugger, linter, build system (Makefile, CMake, Ant, Maven, atau apapun), maupun tools lainnya.Untuk Anda yang baru belajar memprogram: jika Anda menggunakan IDE, sesekali tekanlah tombol debug (atau menu debug) dan cobalah bereksperimen menggunakan fungsi dasar seperti step into, step over, dsb. Ini akan sangat membantu Anda dalam belajar pemrograman.
Tidak ada komentar:
Posting Komentar