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?
sumber
Jawaban:
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:
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.
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.
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 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).
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).
sumber
Saya biasanya mulai dengan:
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.
sumber