Cari artikel di situs ini

Pengenalan tentang Program yang Benar dan Tangguh

Versi ramah cetakVersi ramah cetak

Suatu program disebut "benar" jika ia menyelesaikan suatu tugas sesuai dengan desainnya. Program disebut "tangguh" jika ia bisa menangani suatu situasi yang tidak biasa dengan cara yang masuk akal. Misalnya, suatu program didesain untuk membaca angka yang diketik oleh user, kemudian menampilkan angka dengan urutan tertentu. Program tersebut benar jika ia bekerja untuk angka berapa pun. Program tersebut tangguh jika program tersebut bisa menangani input yang salah, misalnya jika user memasukkan sesuatu yang bukan angka, misalnya, dengan cara memberi tahu user bahwa input yang dia masukkan salah, dan mengabaikan input yang salah tersebut. Program yang tidak tangguh akan keluar tiba-tiba atau memberikan keluaran yang tidak bermakna dalam kondisi tertentu.

Semua program harusnya bekerja dengan benar. (Program yang dibuat untuk mengurutkan angka tetapi tidak mengurutkan dengan benar adalah program yang tidak berguna). Program tidak selalu harus tangguh secara total. Akan tetapi tergantung pada siapa yang akan menggunakan dan bagaimana program tersebut digunakan. Misalnya, program kecil yang digunakan hanya oleh Anda sendiri tidak harus tangguh total, karena kita tahu batas-batas dan bagaimana program tersebut bekerja.

Kebenaran suatu program sebenarnya lebih sulit dari apa yang kita bayangkan. Seorang programmer mencoba membuat program sesuai dengan spesifikasi tentang bagaimana sebuat program "seharusnya" bekerja. Hasil kerja programmer tersebut benar jika program yang ia buat bekerja sesuai dengan spesifikasinya. Tapi apakah itu berarti program tersebut benar? Bagaimana jika ternyata spesifikasinya kurang lengkap atau salah? Program yang benar seharusnya merupakan implementasi dari spesifikasi yang lengkap dan benar. Pertanyaannya apakah spesifikasi tersebut lengkap dan sesuai dengan yang diinginkan tercakup di luar domain ilmu komputer.


Banyak pengguna komputer memiliki pengalaman di mana program tidak bekerja atau crash. Dalam banyak hal, masalah tersebut hanya mengganggu saja, tapi kadang-kadang masalahnya lebih kompleks dari itu, misalnya hilangnya data atau uang. Jika komputer diberi tugas penting, konsekuensinya akan lebih serius apabila program tersebut berperilaku tidak normal.

Beberapa tahun yang lalu, kegagalan dua misi ruang angkasa ke Mars masuk dalam berita. Kedua kegagalan tersebut dipercaya karena masalah pada software, akan tetapi pada kedua kasus tersebut masalahnya bukan pada program yang tidak benar. Pada bulan September 1999, Orbiter Iklim Mars terbakar di atmosfer Mars karena data yang ditulis dalam satuan Inggris (inci, kaki, dll) dimasukkan ke dalam program komputer yang didesain untuk menerima input satuan Metrik (sentimeter, kilometer, dll). Beberapa bulan kemudian, Pendarat Kutub Mars jatuh karena softwarenya mematikan mesinnya terlalu cepat. Program yang dibuat seharusnya bisa mendeteksi tumpuan ketika pesawat mendarat dan baru kemudian mematikan mesin. Akan tetapi, roda pendarat kemungkinan macet yang menyebabkan program pemati mesin aktif sebelum pesawat menyentuh tanah. Sistem yang lebih tangguh akan mengecek terlebih dahulu ketinggian pesawat sebelum mesin dimatikan.

Masih banyak beberapa kisah tentang masalah yang disebabkan oleh jeleknya desain atau implementasi suatu software. Silakan lihat buku Computer Ethics karangan Tom Forester dan Perry Morrison untuk melihat beberapa insiden yang pernah terjadi. (Buku ini menceritakan tentang isu etika dalam bidang komputer. Buku ini mungkin penting sekali untuk dibaca oleh orang yang berkecimpung dalam dunia ilmu komputer).

Pada tahun 1985 dan 1986, satu orang tewas dan beberapa lainnya terluka karena overdosis radiasi, pada saat melakukan perawatan radiasi dengan mesin radiasi yang komputernya tidak diprogram dengan benar. DI kasus lain, selama 10 tahun hingga tahun 1992, sekitar 1000 pasien kanker menerima dosis radiasi sekitar 30% lebih rendah dari yang diberikan dokter karena kesalahan pemrograman.

Pada tahun 1985, sebuah komputer di Bank of New York menghancurkan data-data transaksi sekuritas yang sedang berjalan karena adanya kesalahan pada program. Butuh kurang dari 24 jam untuk memperbaiki program tersebut, akan tetapi pada saat itu, bank sudah kehilangan sekitar 5 juta US dollar karena bunga overnight yang harus dipinjam untuk mengkover masalah tersebut.

Pemrograman sistem kendali inersia dari pesawat tempur F-16 bisa membalik pesawat dari atas ke bawah ketika digunakan di atas khatulistiwa, untungnya masalah ini sudah ditemukan dalam simulasi. Pemindai luar angkasa Mariner 18 hilang karena kesalahan di satu baris program. Kapsul luar angkasa Gemini V salah mendarat beberapa ratus kilometer lebih jauh karena programmer lupa untuk memasukkan perputaran bumi ke dalam perhitungan.

Pada tahun 1990, layanan telephon jarak jauh AT&T terganggu di seluruh Amerika Serikat ketika program komputer yang baru dijalankan terbukti memiliki bug.

Contoh-contoh di atas adalah beberapa yang pernah terjadi. Masalah software adalah masalah yang sangat umum. Sebagai programmer, kita harus mengerti kenapa itu bisa terjadi dan bagaimana cara mengatasinya.


Salah satu bagian dari masalahnya dapat dilacak kepada bahasa pemrogramannya itu sendiri, begitu kata para penemu Java. Java didesain untuk memberikan proteksi terhadap beberapa jenis kesalahan. Bagaimana caranya suatu bahasa pemrograman menghindari kesalahan? Mari kita lihat beberapa contohnya.

Bahasa pemrograman terdahulu tidak membutuhkan variabel untuk dideklarasikan. Pada bahasa pemrograman tersebut, ketika suatu nama variabel digunakan dalam program, variabel akan otomatis dibuat. Mungkin ini terlihat lebih mudah dan nyaman daripada harus mendeklarasikan variabel beserta tipenya terlebih dahulu. Akan tetapi, ada konsekuensinya : Kesalahan ketik sedikit saja akan membuat komputer menciptakan variabel baru yang sebetulnya tidak kita inginkan. Kesalahan seperti ini pernah terjadi dan mengakibatkan hilangnya pesawat ruang angkasa.

Dalam bahasa pemrograman FORTRAN, perintah "DO 20 I = 1,5" adalah pernyataan pertama dari suatu perulangan. Sekarang, spasi tidak lagi suatu hal yang penting pada bahasa FORTRAN, sehingga perintah ini akan sama dengan "DO20I=1,5". Di lain pihak, perintah "DO20I=1.5" dengan tanda titik bukan koma, merupakan pernyataan pemberi nilai yang memberi nilai 1.5 ke dalam variabel DO20I. Misalnya ada kesalahan dalam mengetik koma menjadi titik, bisa jadi akan menyebabkan suatu roket meledak sebelum diluncurkan.

Karena FORTRAN tidak memerlukan variabel untuk dideklarasi, kompilernya akan senang menerima perintah "DO20I=1.5". Ia akan membuat variabel baru bernama DO20I. Jika FORTRAN membutuhkan variabel untuk dideklarasikan di awal, kompiler akan mengeluarkan pesan kesalahan di awal karena variabel DO20I tidak pernah dideklarasikan sebelumnya.

Hampir semua bahasa pemrograman saat ini perlu mendeklarasikan variabel sebelum digunakan, akan tetapi masih ada beberapa fitur pada bahasa pemrograman yang bisa menyebabkan kesalahan. Java sudah membuang fitur ini. Beberapa orang tidak suka karena ini membuat Java menjadi kurang feksibel dan kurang ampuh. Walaupun mungkin kritik ini benar, meningkatnya tingkat keamanan dan ketangguhan suatu program mungkin lebih dipentingkan dalam beberapa hal.

Pertahanan yang paling baik untuk mencegah beberapa macam jenis kesalahan adalah mendesain bahasa pemrograman di mana membuat kesalahan tidak mungkin sama sekali. Dalam kasus lain, di mana kesalahan tidak bisa dihilangkan sama sekali, bahasa pemrograman bisa didesain sehingga apabila kesalahan terjadi, maka kesalahan ini akan dapat dideteksi secara otomatis. Paling tidak cara ini akan mencegah kesalahan tersebut membuat bencana yang lebih besar, karena akan memberi peringatan kepada programmer bahwa ada sesuatu bug yang harus diperbaiki. Mari lihat beberapa contoh yang diberikan Java untuk mengatasi permasalahan ini.

Suatu array dibuat dengan beberapa lokasi, dimulai dengan 0 hingga ke indeks maksimumnya. Kita tidak dibolehkan untuk menggunakan lokasi array di luar rentang yang sudah dibuat. Pada Java, jika kita memaksakan untuk melakukan itu, sistem akan otomatis mendeteksi hal ini. Pada bahasa pemrograman lain seperti C dan C++, programmer diberi keleluasaan penuh untuk memastikan bahwa indeks array berada di dalam rentang tersebut.

Misalnya suatu array, A, memiliki tiga lokasi A[0], A[1], dan A[2]. Maka A[3], A[4], dan berikutnya adalah lokasi pada memori di luar array tersebut. Pada Java, apabila kita mencoba untuk menyimpan data pada A[3], Java akan mendeteksi ini. Program akan dihentikan saat itu juga (kecuali kesalahan ini "ditangkap" yang akan dibahas kemudian). Pada bahasa C atau C++, komputer akan diam saja dan melakukan penyimpanan di lokasi ini. Hasilnya akan tidak bisa diprediksi. Konsekuensinya akan jauh lebih berat daripada jika program berhenti (Kita akan diskusikan tentang tumpahan buffer di bagian ini nanti).

Pointer (penunjuk memori) juga merupakan kesalahan pemrograman yang paling sulit. Dalam Java, variabel dari suatu objek menyimpan pointer atau rujuan ke alamat memori di mana objek tersebut disimpan, atau isinya bisa juga null. Jika kita mencoba untuk menggunakan nilai null seperti layaknya rujukan ke objek sungguhan, maka sistem komputer akan mendeteksinya. Dalam bahasa pemrograman lain, lagi-lagi, adalah tanggung jawab programmer untuk mencegah digunakannya rujukan ke null. Pada komputer Macintosh lama, alamat null merupakan alamat ke lokasi di memori dengan alamat 0. Program dapat menggunakan memori di dekat alamat 0. Sayangnya, Macintosh menyimpan data penting tentang sistem di lokasi tersebut. Mengubah data di lokasi tersebut akan membuat sistem crash atau hang, bukan hanya program tersebut saja tetapi keseluruhan sistem operasi akan berhenti.

Kesalahan pointer lain adalah jika isi pointer menunjuk pada tipe data yang salah atau lokasi di memori yang tidak memiliki objek sama sekali. Kesalahan seperti ini tidak mungkin dalam bahasa Java, karena programmer tidak diperbolehkan untuk mengganti pointer sama sekali. Di dalam bahasa pemrograman lain, programmer bisa mengganti lokasi pointer ke lokasi lain, intinya, ke lokasi memori manapun. Jika tidak dilakukan dengan benar, pointer ini bisa menunjuk pada lokasi berbahaya atau menghasilkan sesuatu yang tidak bisa diperkirakan.

Kesalahan lain yang bisa terjadi pada Java adalah kebocoran memori. Pada Java, sewaktu tidak ada lagi pointer yang merujuk ke pada suatu objek, objek tersebut akan diambil oleh pemulung memori, sehingga memori tersebut dapat digunakan lagi oleh bagian program lain. Dalam bahasa pemrograman lain, programmer bertanggung jawab untuk mengembalikan memori yang tidak digunakan kepada sistem operasi. Jika programmer tidak melakukannya, makan memori yang tidak terpakai akan terakumulasi, sehingga jumlah memori yang tersedia akan berkurang. Ini adalah salah satu contoh masalah umum yang terjadi pada komputer Windows di mana banyak sekali kebocoran memori yang terjadi, sehingga komputer harus direstart ulang setiap beberapa hari.

Banyak program yang terjangkit masalah tumpahan buffer (buffer overflow error). Tumpahan buffer sering menjadi berita utama karena hal ini sering mengakibatkan kompromi masalah keamanan komputer. Ketika komputer menerima data dari komputer lain dari network atau internet misalnya, data tersebut akan disimpan dalam buffer. Buffer adalah bagian memori yang telah dialokasikan program untuk menyimpan data tersebut. Tumpahan buffer terjadi jika data yang diterima lebih banyak dari jumlah data yang bisa ditampung oleh buffer. Pertanyaannya adalah kapan ini terjadi?

Jika kesalahan ini bisa dideteksi oleh program atau program yang mengatur lalu lintas network, maka satu-satunya kemungkinan adalah pada karena kesalahan transmisi data pada network. Masalah utamanya terjadi ketika program tidak bisa mendeteksi tumpahan buffer secara benar. Dalam hal ini, software terus mensuplai data ke memori meskipun buffer telah terisi penuh, dan data lebihnya disimpan pada bagian memori yang tidak dialokasikan untuk buffer tersebut. Bagian memori yang tertunpah tersebut mungkin digunakan untuk fungsi lain. Mungkin juga digunakan untuk menyimpan data penting lain. Atau bahkan mungkin menyimpan kode program itu sendiri. Ini yang akan menjadi masalah keamanaan. MIsalnya tumpahan buffer ini menimpa bagian dari program. Ketika komputer mengeksekusi bagian program yang telah diganti, maka sebetulnya komputer akan menjalankan data yang diterima dari komputer lain. Data ini bisa berisi apa saja. Bisa jadi program untuk menghentikan komputer atau bahkan mengendalikan komputer. Programmer jahat yang bisa menemukan kesalahan tumpahan memori dalam software pengendali network bisa menggunakan lubang ini untuk menjalankan program-program jahatnya.

Untuk software yang ditulis dalam Java, kesalahan tumpahan buffer tidak dimungkinkan. Bahasa Java tidak mungkin menyimpan data di memori yang tidak dialokasikan kepadanya. Untuk bisa menyimpan data, komputer membutuhkan pointer yang menunjuk pada lokasi memori yang belum terpakai, atau menggunakan lokasi array yang berada di luar lokasi yang disediakan untuk array tersebut. Seperti dijelaskan sebelumnya, kedua kemungkinan tersebut tidak diperbolehkan sama sekali pada Java. (Akan tetapi, masih mungkin kesalahan seperti ini muncul pada kelas standar Java, karena beberapa metode pada kelas ini sebenarnya ditulis dalam bahasa C bukan Java).

Sudah jelas desain bahasa bisa membantu mencegah kesalahan atau membantu mendeteksi masalah yang mungkin terjadi. Atau dibutuhkan pengujian, misalnya menguji apakah pointer bernilai null. Beberapa programmer mungkin merasa harus mengorbankan kecanggihan dan efisiensi. Akan tetapi, ada banyak situasi di mana keamanan merupakan prioritas utama. Java didesain untuk situasi seperti ini.


Ada satu bagian di mana desainer Java tidak memasukkan pendeteksi masalah secara otomatis, yaitu perhitungan numerik. Pada Java, nilai suatu bilangan int dinyatakan dalam bilangan biner 32-bit. Dengan 32 bit, maka terdapat kurang lebih 4 milyar bilangan yang bisa dibentuk. Nilai int memiliki rentang antara -2147483648 hingga 2147483647. Apa yang terjadi jika hasil perhitungan berada di luar rentang ini? Misalnya, berapa 2147483647 + 1? Dan berapa 2000000000 * 2? Jawaban yang benar secara matematis berada di luar nilai int. Contoh-contoh di atas disebut tumpahan bilangan bulat (integer overflow). Dalam banyak kasus, tumpahan bilangan bulat termasuk suatu kesalahan. Akan tetapi Java tidak otomatis mendeteksi kesalahan tersebut. Misalnya, perhitungan 2147483647 + 1 akan bernilai negatif -2147483648 (Apa yang terjadi sebenarnya adalah bit tambahan di luar bit ke-32 diabaikan. Nilai yang lebih besar dari 2147483647 akan "terpotong" sehingga menjadi nilai negatif. Secara matematis, hasilnya akan selalu merupakan sisa pembagian dari pembagian dengan 232).

Banyak kesalahan program yang disebabkan oleh kesalahan semacam ini. Program tersebut benar, akan tetapi tidak bisa menangani bilangan lebih besar daripada 32 bit. Contoh sederhana adalah kesalahan Y2K sebenarnya merupakan kesalahan yang mirip dengan ini.

Untuk jenis bilangan real seperti double, masalahnya bahkan lebih kompleks lagi. Bukan hanya tumpahan yang mungkin terjadi. Untuk jenis double, rentangnya berlaku hingga 10308. Nilai yang lebih dari nilai ini tidak "terpotong" menjadi negatif. Akan tetapi ia akan diubah menjadi suatu konstanta yang bernilai tak berhingga. Nilai Double.POSITIVE_INFINITY dan Double.NEGATIVE_INFINITY melambangkan nilai positif tak hingga dan negatif tak hingga. Nilai spesial lainnya dari tipe data double adalah Doube.NaN atau bukan bilangan (not a number), yang melambangkan suatu nilai yang tidak berarti. Misalnya pembagian dengan 0 atau akar kuadrat suatu bilangan negatif. Kita bisa menguji apakah suatu variabel berisi bukan bilangan dengan memanggil fungsi yang bertipe keluaran boolean, yaitu Double.isNaN(x).

Untuk bilangan real, ada komplikasi tambahan yaitu hampir semua bilangan real hanya bisa dilambangkan dalam bentuk pendekatan. Bilangan real bisa memiliki jumlah digit di belakang koma yang tak terhingga banyaknya. Nilai bertipe double biasanya akurat sekitar 15 digit di belakang koma. Bilangan real 1/3, misalnya, berarti 0.33333333......, dan bilangan ini tidak bisa digantikan dengan bilangan dengan jumlah bit terbatas. Perhitungan dengan bilangan real biasanya memiliki kesalahan akurasi. Sebenarnya, jika kita kurang berhati-hati, akan menyebabkan perhitungan sama sekali salah. Ada bidang tertentu dalam ilmu komputer yang dinamakan analisis numerik yang berkonsentrasi pada algoritma untuk memanipulasi bilangan real.


Tidak semua kesalahan yang mungkin terjadi bisa dideteksi otomatis oleh Java. Lebih jauh, bahkan ketika suatu kesalahan bisa dideteksi secara otomatis, reaksi standar dari sistem adalah melaporkan kesalahan dan menghentikan jalannya program. Ini bukan ciri program yang tangguh! Sehingga programmer harus mempelajari teknik untuk mencegah dan mengatasi kesalahan. Topik ini akan dibahas pada bab ini.