Pengecualian "Kesalahan pemrograman" - Apakah pendekatan saya masuk akal?

9

Saat ini saya mencoba untuk meningkatkan penggunaan pengecualian, dan menemukan perbedaan penting antara pengecualian yang menandakan kesalahan pemrograman (misalnya seseorang lulus nol sebagai argumen, atau memanggil metode pada objek setelah dibuang) dan yang menandakan kegagalan dalam operasi yang bukan kesalahan pemanggil (mis. pengecualian I / O).

Bagaimana seharusnya kedua jenis pengecualian ini diperlakukan secara berbeda? Apakah Anda berpikir bahwa pengecualian kesalahan perlu didokumentasikan secara eksplisit, atau cukup untuk mendokumentasikan prasyarat yang relevan? Dan dapatkah Anda meninggalkan dokumentasi tentang prasyarat atau pengecualian kesalahan jika harus jelas (misalnya, ObjectDisposedExceptionketika memanggil metode pada objek yang dibuang)

Medo42
sumber
Saya biasanya membedakan kategori pengecualian lain: pengecualian bisnis. Ini merujuk pada kondisi kesalahan pengguna tertarik pada detail. Saya biasanya membuat pengecualian itu dicentang.
beluchin

Jawaban:

2

Saya pikir Anda berada di jalur yang benar. Baik melempar, menangkap, atau mendokumentasikan semua pengecualian yang berpotensi dibuang sangat masuk akal. Ada saat-saat di mana keketatan produk membutuhkan tingkat pengecualian pekerjaan dan dokumentasi yang lebih tinggi (misalnya aspek kritis keselamatan tertentu dari suatu sistem).

Strategi menjadi lebih defensif, menggunakan konsep kontrak untuk mengidentifikasi prasyarat (dan pascakondisi) pada penelepon hilir (misalnya apa pun yang menyerupai anggota publik atau yang dilindungi) sering kali akan lebih efektif dan lebih fleksibel. Ini tidak hanya berlaku untuk implementasi, tetapi juga untuk dokumentasi. Jika pengembang tahu apa yang diharapkan, mereka lebih cenderung mengikuti aturan dan kecil kemungkinannya akan bingung atau menyalahgunakan kode yang Anda tulis.

Beberapa hal umum yang harus didokumentasikan termasuk kasus parameter nol. Seringkali ada konsekuensi untuk penggunaannya yang mendorong hasil ke sesuatu yang biasanya tidak diharapkan, tetapi diizinkan dan digunakan untuk berbagai alasan, kadang-kadang untuk fleksibilitas. Sebagai konsumen anggota yang memiliki parameter yang memungkinkan nilai nol, atau khusus, non-rasional lainnya (seperti waktu negatif, atau jumlah negatif), saya berharap melihatnya diidentifikasi dan dijelaskan.

Untuk parameter non null, sebagai konsumen anggota publik atau yang dilindungi, saya ingin tahu bahwa nol tidak diperbolehkan. Saya ingin tahu apa kisaran nilai yang valid dalam konteks yang diberikan. Saya ingin tahu konsekuensi dari penggunaan nilai yang berada di luar rentang normal, tetapi dinyatakan valid dalam konteks panggilan yang berbeda (misalnya nilai tipe umumnya berlaku untuk operasi apa pun, tetapi tidak di sini - seperti parameter boolean yang tidak dapat mengharapkan false sebagai nilai yang valid.

Sejauh platform, atau antarmuka terkenal, saya tidak berpikir Anda harus pergi ke ekstrim dalam mendokumentasikannya. Namun, karena Anda memiliki kesempatan sebagai pengembang untuk memvariasikan implementasi dari panduan platform apa pun, catat bagaimana mengikuti panduan tersebut yang mungkin bernilai.

Khusus untuk IDisposable, seringkali implementasi antarmuka ini menawarkan metode alternatif yang lebih disukai daripada proses pembuangan eksplisit. Dalam kasus ini, sorot metode yang disukai, dan perhatikan bahwa pembuangan eksplisit tidak disukai.

JustinC
sumber
Saya memahami perlunya mendokumentasikan nilai mana yang diizinkan, tetapi jika Anda melihat suatu fungsi performReadCommand(ICommand cmd, int replySizeBytes)- apakah Anda berharap bahwa nol akan diterima untuk cmd, atau nilai negatif untuk replySizeBytes? Dokumentasi IMO hanya diperlukan jika nilai-nilai itu benar-benar diizinkan, dan Anda mungkin harus menjawab apakah 0 valid untuk replySizeBytes.
Medo42
Keduanya bisa "valid" tergantung pada implementasinya. Anda atau saya, dan bahkan semua orang di sini tidak akan mengharapkan nilai nol atau negatif sesuai untuk tanda tangan itu, tetapi mereka bisa saja. Pertimbangkan lingkungan di mana pembaca adalah proses pemblokiran, persisten, dan ketika cmd adalah null bisa berarti tidak mengubah perintah yang digunakan oleh pembaca, dan melanjutkan dengan pembacaan berikutnya menggunakan perintah sebelumnya. Idealnya dalam hal ini tanda tangan metode yang lebih tepat yang menonaktifkan cmd sebagai parameter akan didefinisikan dan digunakan, tetapi mungkin tidak.
JustinC
2

Inilah pikiran saya sendiri. Perhatikan bahwa saya tidak terlalu yakin ini adalah cara terbaik untuk pergi, itulah sebabnya saya membuat pertanyaan ini sejak awal.

Sejauh yang saya mengerti, tidak masuk akal bagi seorang penelepon segera untuk benar-benar menangani pengecualian kesalahan pemrograman, ia malah harus memastikan bahwa prasyarat dipenuhi. Hanya penangan pengecualian "luar" di batas tugas yang dapat menangkapnya, sehingga mereka dapat menjaga sistem tetap berjalan jika tugas gagal.

Untuk memastikan bahwa kode klien dapat dengan bersih menangkap pengecualian "kegagalan" tanpa menangkap pengecualian kesalahan karena kesalahan, saya membuat kelas pengecualian saya sendiri untuk semua pengecualian kegagalan sekarang, dan mendokumentasikannya dalam metode yang membuangnya. Saya akan membuat mereka memeriksa pengecualian di Jawa.

Sampai baru-baru ini, saya mencoba mendokumentasikan semua pengecualian yang bisa dilempar metode, tetapi terkadang membuat daftar tanpa disadari yang perlu didokumentasikan dalam setiap metode hingga rantai panggilan sampai Anda dapat menunjukkan bahwa kesalahan tidak akan terjadi. Sebagai gantinya, saya sekarang mendokumentasikan prasyarat dalam deskripsi ringkasan / parameter dan bahkan tidak menyebutkan apa yang terjadi jika tidak dipenuhi. Idenya adalah bahwa orang seharusnya tidak mencoba menangkap pengecualian ini secara eksplisit, jadi tidak perlu mendokumentasikan tipe mereka.

Untuk mendokumentasikan prasyarat, menyatakan yang jelas hanya akan menciptakan kekacauan yang tidak perlu - jika melewati nol ke suatu metode tidak masuk akal, penelepon harus mengharapkan pengecualian jika ia meneruskan null, bahkan jika itu tidak didokumentasikan. Hal yang sama berlaku untuk kasus ObjectDisposedException - antarmuka ini sangat banyak digunakan sehingga seseorang yang menelepon Buang akan menyadari tanggung jawab untuk memastikan tidak ada yang akan terus menggunakan objek.

Medo42
sumber
1

Aturan praktis yang masuk akal:

  1. Tangkap setiap pengecualian yang dapat Anda perbaiki.
  2. Tangkap, komentari, dan kaji ulang pengecualian apa pun yang tidak dapat Anda perbaiki tetapi dapat mengatakan sesuatu yang bermanfaat.
  3. Jangan sampai ada pengecualian yang tidak dapat Anda proseskan atau diagnosa lebih baik dari yang seharusnya.

Anda mungkin ingin memiliki pengendali pengecualian non-fatal tingkat atas untuk menjebak apa pun yang tidak dapat ditangani di bawah ini untuk mencegah aplikasi Anda jatuh, tetapi itu akan sangat bergantung pada aplikasi khusus Anda. Misalnya, aplikasi iOS lebih suka menjebak sebanyak mungkin; aplikasi command-line mungkin benar-benar OK jika hampir tidak ada pengecualian sama sekali.

Joe McMahon
sumber
0

Bahkan Java tidak "mendokumentasikan" semua pengecualian. Terlepas dari persyaratan bahwa setiap thrown pengecualian disebutkan dalam throwsklausa, setiap baris kode dapat melempar RuntimeExceptiontanpa perlu mendeklarasikannya dalam tanda tangan metode.

Ross Patterson
sumber
Ini bertentangan dengan saran populer - khususnya, Java Efektif, edisi ke-2, Butir 62 adalah "Dokumentasikan semua pengecualian yang dilemparkan oleh setiap metode". Faktanya, Bloch mengakui bahwa pengecualian yang tidak dicentang pada umumnya untuk kesalahan pemrograman, tetapi mereka juga harus didokumentasikan dengan hati-hati, karena itu adalah "cara terbaik" untuk mendokumentasikan prasyarat dari suatu metode. Saya tidak yakin apakah saya setuju. Jika saya mendokumentasikan eksekusi, saya menjadikannya bagian dari kontrak antarmuka dan mungkin harus menambahkan kode agar tetap sama jika implementasi saya berubah.
Medo42
1
Untuk setiap ahli, ada ahli kontra. Bruce Eckel, penulis Thinking in Java yang agak terkenal , pernah berada di kemah pro-pengecekan, dan telah mengubah banyak pihak. Ada diskusi yang bagus antara Eckels dan Anders Hejlsberg , pencipta C #, yang tidak memeriksa pengecualian.
Ross Patterson
0

Cara standar untuk melakukannya adalah dengan pendekatan java. Kesalahan pemrograman harus dikecualikan pengecualian dan tidak boleh ditangkap untuk memastikan kegagalan cepat. Kesalahan kontrak adalah pengecualian yang diperiksa dan harus ditangani dengan tepat oleh klien.

J.Hworth
sumber
2
Apakah Anda menganggap (mis. ) NULL yang dihitung (atau nilai kesalahan) sebagai kesalahan pemrograman atau kesalahan kontrak ? Saya setuju dengan perbedaan Anda, tetapi batasannya tidak begitu jelas :)
Andrew
Jika nol dihitung dari argumen yang telah diteruskan (seperti argumen nol, atau sesuatu yang tidak valid), itu adalah kesalahan kontrak. Jika nol dihitung karena sepotong kode buruk, itu kesalahan pemrograman. Jika nol seharusnya dihitung, itu bukan kesalahan. Saya tidak benar-benar melihat ambiguitas dalam contoh ini.
J.Ashworth