Proses apa yang biasanya Anda gunakan ketika mencoba men-debug masalah / masalah / bug dengan perangkat lunak Anda? [Tutup]

15

Kebanyakan orang tampaknya memperlakukan debugging sebagai seni, bukan sebagai sains. Bagi mereka di sini yang memperlakukannya sebagai ilmu pengetahuan, bukan seni - proses apa yang biasanya Anda gunakan ketika dihadapkan dengan masalah / bug / masalah baru?

blueberryfields
sumber

Jawaban:

13

Secara umum, yang saya lakukan adalah:

  1. Cobalah untuk mengisolasi masalahnya. Pikirkan apa yang telah berubah ketika bug pertama kali muncul. Di mana Anda bekerja? Bagian mana dari kode yang Anda ubah? 99% bug saya dipecahkan dengan cara ini. Ini biasanya sesuatu yang konyol.

  2. Jika saya menebak di mana masalahnya, perhatikan baik-baik kode yang tampaknya menjadi penyebabnya. Membacanya. Baca dengan keras bahkan. Tanyakan pada diri sendiri: "Apa yang ingin saya capai?" Untuk beberapa jenis masalah: Mungkinkah ada efek samping atau mungkinkah dipengaruhi oleh kode di tempat lain dengan cara yang tidak saya pikirkan?

  3. Coba dengan berbagai cara untuk menganalisis apa yang salah, di mana dan kapan (lihat di bawah).

  4. Jika saya masih tidak memiliki petunjuk, saya memeriksa apakah versi yang lebih lama dari sumber saya memiliki masalah yang sama, coba temukan ketika dalam timeline pengembangan saya masalah pertama kali muncul. Untuk melakukan ini, Anda perlu bekerja dengan sistem kontrol versi yang bagus, seperti git (git memiliki fitur yang disebut bisect untuk debugging semacam ini).

  5. Jika masih tidak tahu, istirahatlah .... itu sebenarnya sering membantu.

  6. Kembali ke papan gambar - tinjau bagaimana program Anda seharusnya bekerja dan apakah itu benar-benar masuk akal.

Ini benar-benar tergantung pada jenis masalah, tetapi dengan asumsi saya memiliki ide umum tentang di mana masalahnya, maka:

  • Jika saya menduga masalahnya ada di beberapa bagian kode / perubahan terbaru, saya coba dulu untuk menghapus / mengomentari / mengubah atau apa pun untuk menghilangkan bug dengan membuat kode lebih sederhana, dan kemudian mengembalikan kode bermasalah dan mengambil lihat itu.

  • Jalankan debugger dengan breakpoints (jika mungkin sama sekali) dan lihat bagaimana data saya terlihat berusaha menemukan ketika itu mulai bertindak buruk, untuk mendapatkan ide yang lebih baik dari mana ada yang salah.

sinelaw
sumber
1
+1 untuk istirahat. Masalah yang paling sulit hanya menjadi lebih sulit ketika Anda frustrasi dan di jam 6 Anda men-debug mereka. Mengetahui kapan harus istirahat adalah salah satu keterampilan debugging paling berguna yang saya peroleh.
Brad Gardner
Jawaban yang luar biasa. Saya tidak bisa melakukan yang lebih baik.
EricBoersma
1
Sama seperti pendekatan saya, tetapi Anda lupa sedikit di mana Anda meminta seorang rekan untuk melihat sekilas dan mereka langsung melihat kesalahan ejaan ...
ChrisAnnODell
1
Jawaban yang sangat bagus. Saya hanya ingin menambahkan bahwa satu ons pencegahan bernilai satu pon penyembuhan. Sebagian besar dari proses debugging saya adalah ketika saya sedang mengkode, saya hanya membuat perubahan kecil dan bertahap, mengkompilasi, menguji, dan melakukan secara lokal di antara masing-masing. Dengan begitu jika bug tiba-tiba muncul, daftar yang dicurigai sangat kecil dan mudah dilihat dengan bzr qdiffperintah.
Karl Bielefeldt
8

Saya mencoba menggunakan test-driven development ( TDD ). Saya menulis tes yang mereplikasi bug, kemudian mencoba untuk mendapatkan tes untuk lulus. Kadang-kadang tindakan menulis tes membantu menemukan bug.

Ini membuat saya keluar dari debugger sebagian besar waktu, dan memberikan tes regresi untuk mencegah memperkenalkan kembali bug.

Beberapa tautan:

rev TrueWill
sumber
4
Saya pikir jawaban ini sangat tidak lengkap. Saya tidak mengerti banyak upvotes.
Alex
1
Itu hanya mendapat banyak upvotes karena termasuk akronim magis: TDD.
Bjarke Freund-Hansen
@Alex - Saya menambahkan beberapa tautan. Contoh "Temukan BUG, ​​Tulis UJI" memiliki contoh. Saya dapat mengembangkan ini, tetapi sebenarnya sesederhana itu.
TrueWill
7

Ada sejumlah definisi untuk kata sains, tetapi sepertinya Anda mungkin merujuk pada apa yang lebih tepat disebut " metode ilmiah ". Metode ilmiah dapat diringkas sebagai mengamati beberapa fenomena (mungkin bug atau perilaku program yang tidak terduga), merumuskan hipotesis atau hipotesis untuk menjelaskan perilaku, dan yang paling mungkin bereksperimen untuk membuktikannya (menulis tes yang mereproduksi masalah dengan andal).

Jenis bug (fenomena) yang dapat terjadi praktis tidak ada habisnya dan beberapa tidak perlu proses yang jelas. Misalnya, kadang-kadang Anda mengamati bug dan Anda langsung tahu apa yang menyebabkannya hanya karena Anda sangat terbiasa dengan kode tersebut. Di waktu lain, Anda tahu bahwa dengan beberapa input (aksi, serangkaian langkah, dll.), Hasil yang salah terjadi (macet, output buruk, dll.). Untuk kasus-kasus itu, seringkali tidak memerlukan banyak pemikiran "ilmiah". Beberapa pemikiran dapat membantu mengurangi ruang pencarian, tetapi metode yang umum adalah hanya dengan menelusuri kode dalam debugger dan melihat di mana semuanya berjalan serba salah.

Namun, situasi yang saya anggap paling menarik dan mungkin layak untuk proses ilmiah adalah ketika Anda menyerahkan beberapa hasil akhir dan diminta untuk menjelaskan bagaimana hal itu terjadi. Contoh nyata dari ini adalah crash dump. Anda dapat memuat crash dump dan mengamati keadaan sistem dan tugas Anda adalah menjelaskan bagaimana keadaannya. Kecelakaan crash (atau inti) dapat menunjukkan pengecualian, kebuntuan, kesalahan internal, atau keadaan "tidak diinginkan" seperti yang didefinisikan oleh pengguna (misalnya, kelesuan). Untuk situasi ini, saya biasanya mengikuti langkah-langkah berikut ini:

  • Observasi Sempit : Studi informasi langsung di sekitar masalah spesifik jika berlaku. Hal-hal yang jelas di sini adalah tumpukan panggilan, variabel lokal jika Anda bisa melihatnya, garis-garis kode yang mengelilingi masalah. Jenis studi lokasi spesifik ini tidak selalu berlaku. Sebagai contoh, mempelajari sistem "lambat" mungkin tidak memiliki lokasi awal yang jelas seperti ini, tetapi situasi kerusakan atau kesalahan internal kemungkinan akan memiliki titik kepentingan yang segera dan jelas. Salah satu langkah spesifik di sini mungkin menggunakan alat seperti windbg (jalankan! Analisis -v pada crash dump yang dimuat dan lihat apa yang memberitahu Anda).

  • Pengamatan Luas : Mempelajari bagian lain dari sistem. Periksa status semua utas dalam sistem, lihat informasi global apa pun (jumlah pengguna / operasi / item, transaksi / proses / widget aktif, dll.), Informasi sistem (OS), dll. Jika pengguna memberikan detail eksternal apa pun , pikirkan hal-hal yang berkaitan dengan apa yang telah Anda amati. Misalnya, jika mereka memberi tahu Anda bahwa masalahnya terjadi setiap Selasa sore, tanyakan pada diri sendiri apa artinya itu.

  • Mengadakan hipotesa: Ini adalah bagian yang benar-benar menyenangkan (dan saya tidak bercanda tentang hal itu menjadi menyenangkan). Ini seringkali membutuhkan banyak pemikiran logis secara terbalik. Sangat menyenangkan untuk memikirkan bagaimana sistem masuk ke kondisi saat ini. Saya menduga ini bagian yang banyak orang anggap sebagai seni. Dan saya kira itu mungkin jika programmer baru saja mulai melemparkan benda-benda secara acak untuk melihat tongkat apa. Tetapi dengan pengalaman, ini bisa menjadi proses yang didefinisikan dengan cukup baik. Jika Anda berpikir sangat logis pada titik ini, sering kali mungkin untuk menentukan set path yang mengarah ke status yang diberikan. Saya tahu bahwa kita dalam keadaan S5. Agar itu terjadi, S4a atau S4b perlu terjadi dan mungkin S3 sebelum S4a, dll. Lebih sering tidak, mungkin ada beberapa item yang dapat mengarah ke keadaan tertentu. Kadang-kadang mungkin membantu untuk menuliskan pada kertas awal alur sederhana atau diagram keadaan atau serangkaian langkah yang berhubungan dengan waktu. Proses aktual di sini akan sangat bervariasi tergantung pada situasinya, tetapi pemikiran serius (dan pemeriksaan ulang pada langkah-langkah sebelumnya) pada saat ini akan sering memberikan satu atau lebih jawaban yang masuk akal. Perhatikan juga bahwa bagian yang sangat penting dari langkah ini adalah untuk menghilangkan hal-hal yang tidak mungkin. Menghapus yang mustahil dapat membantu memangkas ruang solusi (ingat apa yang dikatakan Sherlock Holmes tentang apa yang tersisa setelah Anda menghilangkan yang mustahil). Perhatikan juga bahwa bagian yang sangat penting dari langkah ini adalah untuk menghilangkan hal-hal yang tidak mungkin. Menghapus yang mustahil dapat membantu memangkas ruang solusi (ingat apa yang dikatakan Sherlock Holmes tentang apa yang tersisa setelah Anda menghilangkan yang mustahil). Perhatikan juga bahwa bagian yang sangat penting dari langkah ini adalah untuk menghilangkan hal-hal yang tidak mungkin. Menghapus yang mustahil dapat membantu memangkas ruang solusi (ingat apa yang dikatakan Sherlock Holmes tentang apa yang tersisa setelah Anda menghilangkan yang mustahil).

  • Eksperimen : Pada tahap ini, cobalah untuk mereproduksi masalah berdasarkan hipotesis yang diturunkan pada langkah sebelumnya. Jika Anda melakukan pemikiran serius pada langkah sebelumnya, ini seharusnya sangat mudah. Terkadang saya "menipu" dan memodifikasi basis kode untuk membantu tes yang diberikan. Sebagai contoh, saya baru-baru ini menyelidiki kecelakaan yang saya simpulkan karena kondisi balapan. Untuk memverifikasinya, saya cukup meletakkan Sleep (500) di antara beberapa baris kode untuk memungkinkan utas lain melakukan hal-hal buruk pada saat yang tepat. Saya tidak tahu apakah ini diizinkan dalam sains "nyata", tetapi sangat masuk akal dalam kode yang Anda miliki.

Jika Anda berhasil mereproduksinya, kemungkinan Anda hampir selesai (semua yang tersisa adalah langkah sederhana untuk memperbaikinya ... tapi itu untuk hari lain). Pastikan untuk memeriksa tes baru ke dalam sistem uji regresi. Dan saya harus menunjukkan bahwa saya bermaksud pernyataan sebelumnya tentang memperbaikinya menjadi sederhana. Menemukan suatu solusi dan mengimplementasikannya membutuhkan kerja keras. Menurut pendapat saya, memperbaiki bug bukan bagian dari proses debugging, melainkan pengembangan. Dan jika perbaikannya sama sekali terlibat, bahwa itu harus memerlukan sejumlah desain dan ulasan.

Mark Wilkins
sumber
Sebagian besar bug yang saya lihat belum dapat direproduksi secara andal, dan, untuk subset yang ada, sebagian besar masih memerlukan pekerjaan debug yang signifikan setelah mereka direproduksi, sebelum pekerjaan apa pun untuk memperbaikinya dapat dimulai. Sekalipun alih-alih mengatakan "berhasil mereproduksinya", Anda mengatakan, "berhasil mempersempit tes unit yang jelas-jelas melatih bug", saya akan mengatakan pekerjaan debug belum berakhir. Bagi saya, debugging sudah selesai setelah saya berdua memiliki perbaikan, saya dapat membuktikan perbaikan masalah, dan saya memiliki bukti yang dapat diandalkan bahwa perbaikan saya adalah apa yang sebenarnya memperbaiki sesuatu.
blueberryfields
Saya setuju bahwa ini adalah pekerjaan yang cukup banyak untuk memperbaikinya. Saya memang menggunakan sarkasme dalam kata-kata saya "langkah sederhana untuk memperbaikinya", tetapi itu tidak muncul dengan baik dalam tipe.
4

Cobalah untuk mengurangi test case. Ketika cukup kecil biasanya lebih mudah untuk menemukan kode yang sesuai yang menyebabkan masalah.

Kemungkinan check-in baru menyebabkan masalah dan build harian sebelumnya baik-baik saja. Dalam hal itu log perubahan Anda dari kontrol sumber akan membantu Anda memutuskan siapa yang akan ditangkap.

Juga, jika Anda menggunakan C / C ++, pertimbangkan menjalankan valgrind atau memurnikan untuk mengisolasi masalah terkait memori.

Fanatic23
sumber
2

Bagian tersulit dari debugging adalah mengisolasi masalah, terutama ketika masalahnya terkubur di bawah beberapa lapisan. Di kampus saya belajar rekaman musik, dan anehnya ada kelas Studio Elektronik yang langsung berlaku di sini. Saya akan menggunakan debugging lingkungan studio sebagai ilustrasi dari proses debugging sistematis.

  1. Uji meter Anda. Menggunakan nada uji pada tegangan terkalibrasi yang dikenal, meter harus membaca "U" (gain satu). Terjemahan: Jika alat Anda rusak, Anda tidak dapat menggunakannya untuk mencari tahu apa yang salah.
  2. Tes setiap komponen / tahap gain bekerja mundur dari akhir. Dengan menggunakan nada tes yang sama yang diterapkan pada input stage, seharusnya tidak ada perubahan pada output stage. Terjemahan: Dengan mengisolasi setiap objek dari output ke belakang, kami membangun kepercayaan pada kode kami sampai kami menemukan tempat di mana ia berantakan. Jika diperlukan beberapa lapisan agar alat Anda memberi sinyal masalah, Anda perlu tahu bahwa lapisan di antaranya tidak berkontribusi terhadapnya.

Kode debug sebenarnya tidak terlalu berbeda. Debugging jauh lebih mudah ketika kode melempar pengecualian. Anda dapat melacak mundur dari jejak tumpukan pengecualian itu dan mengatur titik istirahat di posisi kunci. Biasanya hanya setelah Anda menetapkan variabel, atau pada baris yang memanggil metode yang melempar pengecualian. Anda mungkin menemukan bahwa satu atau beberapa nilai tidak benar. Jika itu tidak benar (nol ketika seharusnya tidak ada, atau nilainya di luar kisaran), maka ini merupakan proses menemukan mengapa itu tidak benar. Titik istirahat dalam IDE setara dengan titik uji elektronik (dirancang untuk probe meter untuk memeriksa rangkaian).

Sekarang, begitu saya telah melalui bagian sulit menemukan di mana masalah saya yang sebenarnya, saya akan menulis beberapa unit test untuk memeriksanya di masa depan.

Berin Loritsch
sumber
2

Dengan bug jahat yang saya susah payah lacak pada sore hari, strategi saya yang paling efektif adalah berdiri dan berjalan pergi selama beberapa menit. Biasanya ide-ide baru tentang sumber kesalahan yang mungkin mulai mengalir setelah hanya 30 detik.

Jay
sumber
2

Untuk pendekatan yang lebih praktis:

  1. Jika bug terkait dengan pengecualian tidak tertangani - lihat jejak tumpukan. Referensi kosong, indeks di luar batas, dll. Dan pengecualian yang Anda tentukan sendiri adalah yang paling umum, Anda dapat menetapkan bug ini untuk junior dev, yang mungkin mudah dan exp pembelajaran yang bagus.

  2. Jika itu tidak terjadi pada setiap mesin, itu mungkin suatu bentuk kondisi ras / masalah threading. Ini sangat menyenangkan untuk dilacak, letakkan programmer senior yang bosan di atasnya. Banyak penebangan, pengetahuan yang baik, dan alat yang bagus untuk menyelesaikan ini

  3. Kelas bug besar lainnya adalah ketika tim pengujian atau klien tidak menyukai perilaku tertentu. Misalnya, mereka tidak suka Anda memutuskan untuk menampilkan ID pengguna atau ketika mencari Anda tidak mendapatkan pelengkapan otomatis. Ini adalah bug asli, pertimbangkan memiliki manajemen produk yang lebih baik dan pengembang dengan pandangan yang lebih luas. Perlu waktu yang relatif singkat bagi pengembang untuk "memperbaiki" ini jika ia membangun sistem dengan mempertimbangkan ekspansi.

  4. 80% dari semua bug lainnya diselesaikan dengan memiliki sistem logging yang baik dan mengumpulkan cukup info untuk menyelesaikannya. Gunakan penelusuran bawaan dengan beberapa tingkat, sistem pencatatan yang rumit seperti Log4Net / Log4J

  5. bug kinerja adalah kategori mereka sendiri, aturan golder di sini adalah "ukur dulu, perbaiki nanti!", dan Anda akan terkejut melihat berapa banyak pengembang yang hanya menebak di mana masalahnya dan langsung masuk untuk memperbaikinya hanya untuk melihat kemudian hanya penurunan 3-4% dalam waktu respons.

Bogdan Gavril MSFT
sumber
Jika saya dapat memberi +1 pada masing-masing dari 5 itu secara individual, saya akan melakukannya!
jmort253
1

Saya memiliki dua pendekatan:

  1. Bagilah masalah yang diberikan di bagian yang lebih kecil dan kemudian taklukkan masing-masing bagian yang lebih kecil dengan mengikuti Divide and ConquerParadigma.
  2. Setiap kali saya ragu mengenai nilai apa pun daripada saya hanya mencetak nilai-nilai variabel untuk melihat apa yang sebenarnya masuk dan keluar dari variabel.

Pendekatan ini telah banyak membantu saya.

Rachel
sumber