Berpikir Ketika Memprogram dan Menguji Program

Setelah membaca posting reddit ini, saya teringat kembali pada buku Programming Pearl, terutama bagian yang dibahas dalam posting itu yaitu mengenai binary search. Dalam buku programming pearl dinyatakan bahwa para programmer professional yang diberi waktu 2 jam untuk menulis binary search, 90% memiliki bug (terutama di *boundary* condition). Penulis blog memberi tantangan pada pembacanya untuk membuat binary search, boleh beberapa jam, tapi *tanpa testing* sama sekali.

Respon kebanyakan orang bisa dirangkum menjadi tiga kubu. Kubu pertama: ah di dunia nyata kan orang pasti testing, keahlian buat memprogram dengan benar tanpa testing itu tidak berguna. Kubu kedua menyatakan: kalau program sependek itu tidak bisa dibuat tanpa testing, bagaimana mungkin bisa membuat program besar yang rumit, apakah tiap baris program harus ditest?. Kubu terakhir menyatakan: buat apa sih membuat binary search, kan sudah ada di library/API?

Untuk kubu terakhir, jawabannya sederhana: ada kasus di mana hal tersebut masih diperlukan. Misalnya fungsi binary search di library kebanyakan tidak menyatakan elemen mana yang akan dikembalikan jika ada lebih dari 1 data yang cocok, dan tidak akan mengembalikan lokasi di mana data bisa disisipkan jika data belum ada. Contohnya di fungsi bsearch di C (POSIX):

The bsearch() function returns a pointer to a matching member of the array, or NULL if no match is found. If there are multiple elements that match the key, the element returned is unspecified.

Kadang diperlukan fungsi yang mengembalikan elemen pertama yang cocok, atau terakhir yang cocok, atau bahkan elemen random dari antara semua elemen yang cocok. Tentu saja salah satu solusinya adalah membungkus fungsi bsearch, lalu mencari ke depan atau belakang sampai tidak cocok lagi. Tapi dalam hal ini Anda juga tetap perlu memperhatikan batas index ketika mencari, jadi Anda tetap perlu menulis kode (yang perlu testing dan perlu dipikirkan).

Jika Anda mengimplementasikan fungsi binary search sendiri, Anda bisa membuat fungsi yang sekaligus mengembalikan posisi elemen di mana kita harus menyisipkan elemen tersebut jika elemen tidak ditemukan (ini bisa didapat dari lokasi perbandingan terakhir), dalam kasus ini kita tidak bisa membungkus fungsi bsearch, karena fungsi tersebut hanya mengembalikan NULL jika elemen tidak ditemukan.

Beberapa Pelajaran yang bisa dipetik dari posting dan diskusi adalah: testing itu perlu, bahkan untuk program kecil sekalipun. Pelajaran kedua adalah: kita tetap harus teliti dan berpikir ketika memprogram. Pelajaran ketiga adalah: meski isi library di berbagai bahasa sudah cukup lengkap, mengerti algoritma sederhana itu perlu, dan kadang kita perlu mengimplementasikan algoritma tersebut atau variannya.

Sebagian orang berpikir: ah tidak perlu terlalu teliti ketika memprogram, nanti akan ketauan salahnya ketika testing. Sebagian lagi berpikir: program ini sudah saya pikirkan, jadi gak perlu ditest. Sikap yang benar adalah: kedua hal tersebut berhubungan, kita harus teliti ketika memprogram, dan harus teliti juga dalam membuat testing. Mengapa tidak menggantungkan diri pada testing saja? ada beberapa masalah dengan testing, pertama testing itu sulit, untuk membuat test case yang baik perlu kasus yang sangat besar dan kedua testing tidak selalu bisa dilakukan.

Contoh sebuah program dengan testing yang baik adalah SQLLite, kode program utama hanya 62 ribu baris kode, tapi kode untuk testingnya lebih dari 45 juta baris kode, atau 679 kali lebih besar dari programnya sendiri (Sumber: http://www.sqlite.org/testing.html). Apakah Anda sanggup memikirkan dan membuat test sebanyak itu?. Mungkin Anda berpikir: ah tidak perlu sebanyak itu, test yang penting saja. Nah pertanyaannya: bagian mana yang penting untuk ditest? Anda perlu mencari semua boundary condition (misalnya dalam binary search: kasus kosong, kasus 1 elemen, kasus data berjumlah ganjil, kasus data berjumlah genap, kasus data tidak ditemukan, kasus data yang sangat besar).

Banyak sekali security bug dalam program terjadi karena off-by-one error, dan sering kali ini tidak diketahui. Kasus seperti ini akan sering jika penulis kode unit testing bukan programmer yang menulis kode, sehingga dia tidak bisa melakukan boundary value analysis. Oleh karena itu berpikir sambil memprogram adalah hal yang penting (jangan menggantungkan diri dari testing saja).

Ada kalanya testing kadang sulit dilakukan, misalnya jika program harus dijalankan di harware khusus. Hal ini terutama jika hardware tidak memiliki emulator, atau jika emulator tidak sempurna. Contohnya: banyak emulator ponsel (terutama Symbian versi awal) tidak mengimplementasikan bluetooth, kamera dan wifi. Mau tidak mau kita harus testing di hardware sebenarnya, yang biasanya memakan waktu lebih lama, dan kadang membutuhkan biaya yang lebih besar. Dalam kasus ini testing tetap bisa dilakukan, tapi harus diminimasi, dan harus dipikirkan dengan matang apa saja yang ingin ditest.

Jadi yang perlu diingat: jangan asal coding, lalu mendebug/mengetes sampai kodenya benar, pikirkan dulu sebelum menulis kode. Setelah dipikirkan, baru diuji, sambil memikirkan aneka kasus uji yang penting.

Programmers are not to be measured by their ingenuity and their logic but by the completeness of their case analysis.
Alan Perlis

Leave a Reply

Your email address will not be published. Required fields are marked *