Apa yang dimaksud dengan 'jumlah yang baik' untuk diterapkan untuk perpustakaan saya?


20

Saya selalu bertanya-tanya berapa banyak kelas pengecualian yang harus saya terapkan dan lontarkan untuk berbagai perangkat lunak saya. Perkembangan khusus saya biasanya terkait C ++ / C # / Java, tapi saya yakin ini adalah pertanyaan untuk semua bahasa.

Saya ingin memahami jumlah pengecualian yang berbeda untuk dilemparkan, dan apa yang diharapkan komunitas pengembang dari perpustakaan yang baik.

Pertukaran yang saya lihat meliputi:

  • Kelas pengecualian lainnya dapat memungkinkan tingkat penanganan kesalahan yang sangat baik untuk pengguna API (cenderung konfigurasi pengguna atau kesalahan data, atau file tidak ditemukan)
  • Kelas pengecualian lainnya memungkinkan informasi spesifik kesalahan untuk dimasukkan dalam pengecualian, bukan hanya pesan string atau kode kesalahan
  • Semakin banyak kelas pengecualian dapat berarti lebih banyak pemeliharaan kode
  • Semakin banyak kelas pengecualian dapat berarti API kurang mudah didekati oleh pengguna

Skenario yang ingin saya pahami penggunaan pengecualian termasuk:

  • Selama tahap 'konfigurasi', yang mungkin termasuk memuat file atau mengatur parameter
  • Selama fase ketik 'operasi' di mana perpustakaan mungkin menjalankan tugas dan melakukan beberapa pekerjaan, mungkin di utas lainnya

Pola pelaporan kesalahan lainnya tanpa menggunakan pengecualian, atau lebih sedikit pengecualian (sebagai perbandingan) dapat mencakup:

  • Perkecualian lebih sedikit, tetapi menyematkan kode kesalahan yang dapat digunakan sebagai pencarian
  • Mengembalikan kode kesalahan dan menandai langsung dari fungsi (terkadang tidak dimungkinkan dari utas)
  • Menerapkan suatu peristiwa atau sistem panggilan balik jika terjadi kesalahan (menghindari tumpukan yang tidak berujung)

Sebagai pengembang, apa yang Anda sukai untuk dilihat?

Jika ada banyak BANYAK pengecualian, apakah Anda repot-repot menangani kesalahan secara terpisah?

Apakah Anda memiliki preferensi untuk jenis penanganan kesalahan tergantung pada tahap operasi?



5
"API kurang mudah didekati oleh pengguna" - dapat ditangani dengan memiliki beberapa kelas pengecualian yang semuanya mewarisi dari kelas dasar umum untuk API. Kemudian tepat saat Anda memulai, Anda dapat melihat dari mana API pengecualian berasal tanpa harus khawatir tentang semua detail. Pada saat Anda menyelesaikan program pertama Anda menggunakan API, maka jika Anda memerlukan lebih banyak informasi tentang kesalahan maka Anda mulai melihat apa arti sebenarnya dari berbagai pengecualian. Tentu saja Anda secara bersamaan harus bermain dengan baik dengan hierarki pengecualian standar bahasa yang Anda gunakan.
Steve Jessop

poin terkait Steve
Fuzz

Jawaban:


18

Saya tetap sederhana.

Pustaka memiliki tipe pengecualian dasar yang diperluas dari std ::: runtime_error (yang berasal dari C ++ berlaku sesuai dengan bahasa lain). Pengecualian ini membutuhkan string pesan sehingga kami dapat login; setiap titik lemparan memiliki pesan unik (biasanya dengan ID unik).

Itu saja.

Catatan 1 : Dalam situasi di mana seseorang menangkap pengecualian dapat memperbaiki pengecualian dan memulai kembali tindakan. Saya akan menambahkan pengecualian turunan untuk hal-hal yang berpotensi diperbaiki secara unik di lokasi terpencil. Tapi ini sangat jarang (Ingat penangkap tidak mungkin dekat dengan titik lemparan sehingga memperbaiki masalah akan sulit (tetapi semuanya tergantung pada situasi)).

Catatan 2 : Terkadang perpustakaan sangat sederhana sehingga tidak layak untuk memberikan pengecualiannya sendiri dan std :: runtime_error akan melakukannya. Hanya penting untuk memiliki pengecualian jika kemampuan untuk membedakannya dari std :: runtime_error dapat memberikan informasi yang cukup kepada pengguna untuk melakukan sesuatu dengannya.

Catatan 3 : Dalam suatu kelas saya biasanya lebih suka kode kesalahan (tetapi ini tidak akan pernah keluar di API publik kelas saya).

Melihat trade off Anda:

Pertukaran yang saya lihat meliputi:

Kelas pengecualian lainnya dapat memungkinkan tingkat penanganan kesalahan yang sangat baik untuk pengguna API (cenderung konfigurasi pengguna atau kesalahan data, atau file tidak ditemukan)

Apakah lebih banyak pengecualian benar-benar memberi Anda kendali butir yang lebih baik? Pertanyaannya menjadi dapatkah kode penangkapan benar-benar memperbaiki kesalahan berdasarkan pengecualian. Saya yakin ada situasi seperti itu dan dalam kasus ini Anda harus memiliki pengecualian lain. Tetapi semua pengecualian yang telah Anda sebutkan di atas satu-satunya koreksi yang berguna adalah menghasilkan peringatan besar dan menghentikan aplikasi.

Kelas pengecualian lainnya memungkinkan informasi spesifik kesalahan untuk dimasukkan dalam pengecualian, bukan hanya pesan string atau kode kesalahan

Ini adalah alasan bagus untuk menggunakan pengecualian. Tetapi informasi tersebut harus bermanfaat bagi orang yang menyimpannya. Bisakah mereka menggunakan informasi untuk melakukan beberapa tindakan korektif? Jika objek bersifat internal ke pustaka Anda dan tidak dapat digunakan untuk mempengaruhi API apa pun maka informasi tersebut tidak berguna. Anda harus sangat spesifik bahwa informasi yang dilemparkan memiliki nilai berguna bagi orang yang dapat menangkapnya. Orang yang menangkapnya biasanya berada di luar API publik Anda, jadi sesuaikan informasi Anda sehingga dapat digunakan dengan hal-hal di API publik Anda.

Jika yang bisa mereka lakukan hanyalah mencatat pengecualian maka yang terbaik adalah hanya membuang pesan kesalahan daripada banyak data. Sebagai penangkap biasanya akan membangun pesan kesalahan dengan data. Jika Anda membuat pesan kesalahan maka itu akan konsisten di semua penangkap, jika Anda mengizinkan penangkap untuk membangun pesan kesalahan Anda bisa mendapatkan kesalahan yang sama dilaporkan secara berbeda tergantung pada siapa yang memanggil dan menangkap.

Perkecualian lebih sedikit, tetapi menyematkan kode kesalahan yang dapat digunakan sebagai pencarian

Anda harus menentukan cuaca kode kesalahan dapat digunakan secara bermakna. Jika bisa maka Anda harus memiliki pengecualian sendiri. Jika tidak, pengguna Anda sekarang perlu menerapkan pernyataan switch di dalam tangkapan (yang mengalahkan seluruh titik menangkap secara otomatis menangani hal-hal).

Jika tidak bisa maka mengapa tidak menggunakan pesan kesalahan dalam pengecualian (tidak perlu membagi kode dan pesan itu membuat sulit untuk melihat ke atas).

Mengembalikan kode kesalahan dan menandai langsung dari fungsi (terkadang tidak dimungkinkan dari utas)

Mengembalikan kode kesalahan sangat bagus secara internal. Ini memungkinkan Anda untuk memperbaiki bug di sana dan kemudian dan Anda harus memastikan Anda memperbaiki semua kode kesalahan dan akun untuk mereka. Tapi membocorkannya di API publik Anda adalah ide yang buruk. Masalahnya adalah bahwa pemrogram sering lupa memeriksa status kesalahan (setidaknya dengan pengecualian kesalahan yang tidak dicentang akan memaksa aplikasi untuk keluar dari kesalahan yang tidak ditangani umumnya akan merusak semua data Anda).

Menerapkan suatu peristiwa atau sistem panggilan balik jika terjadi kesalahan (menghindari tumpukan yang tidak berujung)

Metode ini sering digunakan bersama dengan mekanisme penanganan kesalahan lainnya (bukan sebagai alternatif). Pikirkan program windows Anda. Pengguna memulai tindakan dengan memilih item menu. Ini menghasilkan tindakan pada antrian acara. Antrian acara akhirnya memberikan utas untuk menangani tindakan. Thread seharusnya menangani aksi dan akhirnya kembali ke thread pool dan menunggu tugas lain. Di sini pengecualian harus ditangkap di pangkalan oleh utas yang ditugaskan untuk pekerjaan itu. Hasil menangkap pengecualian biasanya akan menghasilkan acara yang dibuat untuk loop utama yang akhirnya akan menghasilkan pesan kesalahan yang ditampilkan kepada pengguna.

Tetapi kecuali Anda dapat melanjutkan menghadapi pengecualian, tumpukan akan terlepas (setidaknya untuk utas).


+1; "Jika tidak, pengguna Anda sekarang perlu menerapkan pernyataan switch di dalam tangkapan (yang mengalahkan seluruh titik menangkap secara otomatis menangani hal-hal)." - Panggil stack unwinding (jika Anda masih dapat menggunakannya) dan penanganan kesalahan paksa masih merupakan manfaat besar. Tapi itu pasti akan mengurangi kemampuan untuk melakukan panggilan stack unwinding ketika Anda harus menangkapnya di tengah dan rethrow.
Merlyn Morgan-Graham

9

Saya biasanya mulai dengan:

  1. Kelas pengecualian untuk bug argumen . Misalnya, "argumen tidak diperbolehkan menjadi null", "argumen harus positif", dan seterusnya. Java dan C # memiliki kelas yang telah ditentukan untuk mereka; di C ++ saya biasanya membuat hanya satu kelas, berasal dari std :: exception.
  2. Kelas pengecualian untuk bug prasyarat . Itu untuk tes yang lebih kompleks, seperti "indeks harus lebih kecil dari ukuran".
  3. Kelas pengecualian untuk bug pernyataan . Itu adalah untuk memeriksa negara bagian untuk metode setengah jalan konstistensi. Misalnya ketika mengulangi daftar untuk menghitung elemen yang negatif, nol, atau positif, pada akhirnya ketiganya akan bertambah hingga ukuran.
  4. Satu kelas pengecualian dasar untuk perpustakaan itu sendiri. Pada awalnya, lemparkan saja kelas ini. Hanya ketika kebutuhan muncul, mulailah menambahkan sub-kelas.
  5. Saya lebih suka untuk tidak membungkus pengecualian, tetapi saya tahu bahwa pendapat berbeda tentang hal ini (dan sangat berkorelasi dengan bahasa yang digunakan). Jika Anda membungkus, Anda perlu kelas pengecualian pembungkus tambahan .

Karena kelas untuk 3 kasus pertama adalah alat bantu debug, mereka tidak dimaksudkan untuk ditangani oleh kode. Alih-alih, mereka harus ditangkap hanya oleh penangan tingkat atas yang menampilkan info sedemikian rupa sehingga pengguna dapat menyalin-menempelkannya ke pengembang (atau bahkan lebih baik: tekan tombol "kirim laporan"). Jadi sertakan info yang berguna untuk pengembang: file, fungsi, nomor baris, dan beberapa pesan yang dengan jelas mengidentifikasi pemeriksaan mana yang gagal.

Karena 3 kasus pertama adalah sama untuk setiap proyek, di C ++ saya biasanya hanya menyalinnya dari proyek sebelumnya. Karena banyak yang melakukan hal yang persis sama, para perancang C # dan Java menambahkan kelas standar untuk kasus-kasus itu ke pustaka standar. [UPDATE:] Untuk pemrogram malas: satu kelas bisa cukup dan dengan sedikit keberuntungan perpustakaan standar Anda sudah memiliki kelas pengecualian yang sesuai. Saya lebih suka menambahkan info seperti nama file dan linenumber, yang tidak disediakan oleh kelas default di C ++. [Akhiri pembaruan]

Bergantung pada perpustakaan, case keempat hanya memiliki satu kelas, atau bisa menjadi beberapa kelas. Saya lebih suka pendekatan tangkas untuk memulai sederhana, menambahkan sub-kelas ketika kebutuhan muncul.

Untuk argumentasi terperinci tentang kasus keempat saya, lihat jawaban Loki Astari . Saya sepenuhnya setuju dengan jawaban terperincinya.


+1; Ada perbedaan yang pasti antara bagaimana Anda harus menulis pengecualian menulis dalam kerangka ayat bagaimana Anda harus menulis pengecualian dalam aplikasi. Perbedaannya sedikit kabur, tetapi Anda menyebutkannya (menunda ke Loki untuk kasing perpustakaan).
Merlyn Morgan-Graham
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.