Hampir dua puluh tahun yang lalu, saya mendapatkan banyak wawasan tentang hal ini dari buku David Thielen yang sangat baik "No Bugs: Memberikan Kode Bebas Kesalahan dalam C dan C ++", yang sekarang tersedia dalam bentuk PDF gratis .
Dia mengajari saya dua ide hebat ...
Bug tidak datang entah dari mana. Kita semua programmer duduk dan menuliskannya ke dalam kode kita dengan jari kita sendiri.
"Bug" berkonotasi bahwa beberapa agensi luar memutuskan untuk menginfeksi program Anda dengan bug dan bahwa jika Anda menjalani kehidupan yang bersih, dan mengorbankan hewan berbulu kecil di kaki komputer Anda, mereka akan pergi ... Konsep ini penting karena warna pendekatan Anda untuk men-debug kode Anda. Jika Anda melihat kesalahan sebagai "bug," Anda berharap tidak ada yang ditemukan. (Kamu berharap peri yang baik datang, menaburkan debu peri, dan serangga pergi.)
Bug tidak boleh disebut bug, mereka harus disebut Massive Fuck-Ups [MFUs] ... MFU ada karena program ditulis oleh orang-orang, dan orang-orang membuat kesalahan ... Anda akan menulis MFU. Anda akan duduk dan dengan kebencian penuh dari pemikiran sebelumnya menempatkan MFU dalam kode Anda. Pikirkan tentang hal ini - Anda tahu bahwa Anda yang meletakkan bug di sana. Jadi, jika Anda duduk dengan kode, Anda akan memasukkan beberapa bug.
Karena takdir semua programmer tidak bisa dihindari untuk menulis bug, saya perlu kode defensif, termasuk hal-hal yang akan melompat, menjerit, dan mengibarkan bendera merah ketika mereka mendeteksi bug.
Setelah ditulis pada awal tahun 90-an, kekhususan dalam buku Thielen ini agak ketinggalan zaman. Misalnya, di Linux dan Mac OS X, Anda tidak perlu lagi menulis bungkus sendiri untuk operator baru C ++; Anda dapat menggunakan valgrind untuk itu.
Tetapi ada beberapa hal yang secara rutin saya lakukan untuk C / C ++ / ObjC:
- Ketika saya bisa, nyalakan opsi "Peringatan adalah kesalahan" dari kompiler, dan perbaiki semuanya. (Saya mengelola satu proyek lama di mana memperbaiki semuanya sekaligus akan memakan waktu berminggu-minggu, jadi saya hanya memperbaiki file setiap beberapa minggu - dan dalam beberapa tahun, saya dapat mengaktifkan opsi itu.)
- Gunakan alat analisis kode statis, seperti Gimpel's PC-Lint atau yang sangat bagus sekarang dibangun ke dalam Xcode Apple. Cakupan bahkan lebih baik, tetapi biayanya untuk perusahaan besar, bukan hanya manusia biasa.
- Gunakan alat analisis dinamis, seperti valgrind, untuk memeriksa masalah memori, kebocoran, dll.
- Seperti yang dikatakan Thielen (dan bab ini masih layak dibaca): Assert The World . Tentu saja, tidak ada orang selain idiot yang akan memanggil fungsi Anda dengan pointer nil - dan itu berarti seseorang, di suatu tempat, adalah idiot yang akan melakukan hal itu. Bahkan mungkin Anda dalam tiga tahun ketika apa yang Anda lakukan hari ini telah berkabut. Jadi tambahkan saja pernyataan di awal fungsi untuk memvalidasi argumen pointer - dibutuhkan tiga detik untuk mengetik, dan hilang dalam rilis executable.
- Di C ++, RTTI adalah teman Anda. Sekali lagi, tidak ada orang selain idiot yang akan memanggil fungsi Anda dengan penunjuk ke objek yang salah - yang berarti bahwa, pasti, beberapa orang idiot akan - dan biaya untuk bertahan terhadap hal itu dapat diabaikan. Dalam kode berbasis-C yang diturunkan dari GObject, Anda dapat melakukan hal yang sama dengan macro cast dinamis yang defensif.
- Unit dan tes regresi otomatis sekarang menjadi bagian penting dari repertoar saya. Pada satu proyek, mereka adalah bagian integral dari sistem build rilis, dan build tidak akan selesai kecuali mereka semua lulus.
- Bagian penting lainnya adalah mencatat kode di debug dan melepaskan executable yang dapat diaktifkan saat runtime oleh sesuatu seperti variabel lingkungan.
- Tulis tes defensif sehingga programmer yang menjalankan debug tidak dapat mengabaikannya jika gagal. Pesan runtime ke konsol dapat diabaikan. Program macet dengan tegas tidak dapat diabaikan.
- Saat merancang, menyediakan API publik, dan implementasi pribadi yang tidak bisa didapatkan oleh kode luar. Dengan begitu, jika Anda harus refactor, tidak ada yang bergantung pada beberapa variabel keadaan interior sihir atau sesuatu. Di kelas C ++, saya penggemar berat yang dilindungi dan pribadi untuk ini. Saya juga berpikir kelas proxy hebat, tapi jangan gunakan itu sendiri.
Tentu saja, apa yang akan Anda lakukan untuk bahasa atau teknologi baru akan bervariasi dalam detailnya. Tapi begitu Anda memasukkan ke dalam hati Anda anggapan bahwa serangga itu Besar-Besaran, Anda Menulis Dengan Jari Anda Sendiri, dan kode Anda terus-menerus diserang oleh pasukan idiot, dengan Anda sebagai kepala jenderal, dengan Anda sebagai kepala jenderal, saya yakin Anda Saya akan mencari teknik pertahanan yang cocok.
Semua hal di atas adalah poin yang bagus. Tetapi ada sesuatu yang tidak disebutkan. Anda perlu membuat modul dan fungsi Anda menjadi paranoid. Rentang menguji semua parameter fungsi. Hati-hati dengan string dengan awal atau akhir yang kosong atau yang terlalu pendek atau terlalu panjang. Waspadalah terhadap boolean yang benar-benar tidak palsu. Dalam bahasa yang tidak diketik seperti PHP, perhatikan jenis variabel yang tidak terduga. Watch out for NULL.
Kode paranoid ini sering dikodekan sebagai pernyataan yang dapat dinonaktifkan pada build produksi untuk mempercepat. Tapi itu pasti akan mencegah bug panik menit terakhir.
sumber
Rob benar dalam mengatakan bahwa unit test tidak akan menyelamatkan Anda dari bug yang tidak diketahui TETAPI unit test akan membantu Anda dari memperkenalkan bug saat Anda memperbaiki bug yang tidak dikenal dan akan menyelamatkan Anda dari pengenalan kembali bug lama secara tidak sengaja. TDD juga akan memaksa Anda untuk merancang perangkat lunak Anda sejak awal agar dapat diuji dan yang memiliki nilai berkelanjutan positif yang sangat besar.
sumber
Hindari status / "efek samping" jika memungkinkan. Meskipun komputer bersifat deterministik, dan memberikan output yang sama untuk input yang sama, tinjauan umum tentang input selalu tidak lengkap. Sayangnya, sebagian besar waktu kita tidak menyadari betapa tidak lengkapnya itu.
Ketika berbicara tentang aplikasi web, seluruh database, permintaan saat ini, sesi pengguna, pustaka pihak ke-3 yang diinstal, dan banyak lagi bagian input. Ketika berbicara tentang utas, itu lebih buruk lagi: seluruh sistem operasi Anda, dengan semua proses lainnya yang dikelola oleh penjadwal yang sama adalah 'bagian dari input'.
Bug disebabkan oleh salah menilai cara input ditangani atau dengan salah menilai input. Yang terakhir adalah, dalam pengalaman saya, yang sulit: Anda hanya dapat mengamati mereka 'hidup', seringkali, Anda tidak memiliki input lagi.
Ketika mempelajari Teknologi, Infrastruktur baru, dll., Sebaiknya praktik itu mendapatkan gambaran umum, komponen apa yang berkontribusi pada input dan kemudian mencoba untuk menghindari sebanyak mungkin dari mereka .
sumber
Karena perangkat lunak Anda menjadi lebih kompleks, tidak dapat dihindari bahwa beberapa bug akan terjadi. Satu-satunya cara untuk menghindari itu sepenuhnya adalah dengan hanya mengembangkan perangkat lunak sepele - dan bahkan kemudian, Anda pasti akan membuat kesalahan gila dari waktu ke waktu.
Satu-satunya hal praktis yang dapat Anda lakukan adalah menghindari kerumitan yang tidak perlu - membuat perangkat lunak Anda sesederhana mungkin, tetapi tidak lebih sederhana dari itu.
Pada dasarnya itulah prinsip dan pola desain yang lebih spesifik - membuat segala sesederhana mungkin. Masalahnya adalah bahwa "sederhana dengan cara apa" dapat bersifat subyektif - maksud Anda desain paling sederhana mutlak untuk persyaratan saat ini, atau sederhana untuk memodifikasi untuk persyaratan di masa depan. Dan ada prinsip untuk itu juga.
Tes unit adalah contoh dari ketidakpastian ini. Di satu sisi, mereka adalah kompleksitas yang tidak perlu - kode yang harus dikembangkan dan dipelihara, tetapi yang tidak menyelesaikan pekerjaan. Di sisi lain, mereka adalah cara sederhana untuk mengotomatisasi pengujian, mengurangi jumlah pengujian manual yang jauh lebih sulit yang harus dilakukan.
Tidak peduli berapa banyak teori desain yang Anda pelajari dan berapa banyak pengalaman yang Anda dapatkan, prinsip utama (dan kadang-kadang satu-satunya panduan yang Anda miliki) adalah bertujuan untuk kesederhanaan.
sumber
Tidak ada yang acak tentang bug perangkat lunak, penyebab utama bersifat deterministik sempurna, instruksi yang salah ke komputer.
Threading bug dapat bersifat non-deterministik dalam perilaku eksekusi, tetapi tidak secara acak menjadi penyebab utama.
Mereka terjadi untuk alasan yang sama persis hanya pada saat-saat yang tampaknya tidak dapat diprediksi dalam waktu, tetapi itu tidak membuat mereka acak hanya tampaknya tidak dapat diprediksi, setelah Anda mengetahui akar penyebabnya, Anda dapat secara deterministik memprediksi kapan mereka akan terjadi.
Saya mengatakan dengan jelas dan membuat perbedaan karena suatu alasan. Acak berarti satu hal, Dibuat, dilakukan, terjadi, atau dipilih tanpa metode atau keputusan sadar , yang menyiratkan ada beberapa pengambilan keputusan independen pada bagian komputer, tidak ada yang melakukan persis apa yang diperintahkan untuk dilakukan, Anda hanya tidak menyuruhnya melakukan hal yang benar dalam beberapa kasus yang sangat deterministik.
Semantik kata ada karena suatu alasan, acak tidak berarti sesuatu yang berbeda hanya karena seseorang menggunakannya dengan benar, itu selalu berarti hal yang sama. Istilah yang lebih baik adalah kesalahan logika yang tidak disengaja atau tidak jelas .
Mempertimbangkan bug secara acak hampir seperti menerima bahwa ada kekuatan lain yang tidak dapat dipahami di tempat kerja yang tidak sepenuhnya dipahami bertindak secara independen dari input Anda ke komputer, dan itu tidak terlalu ilmiah. Maksud saya, apakah para Dewa marah dan memukul permohonan Anda karena iseng?
sumber