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 2
32).
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 10
308. 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..