Merekomendasikan pola desain / pendekatan untuk mengekspos / mentolerir / memulihkan dari kesalahan sistem, Penanganan pengecualian (mis. Di Jawa, C ++, Perl, PHP)

13

Bisakah Anda merekomendasikan pola desain / pendekatan untuk mengekspos / mentolerir / memulihkan dari kesalahan sistem, penanganan Exception (Java, C ++, Perl, PHP)?

Beberapa kesalahan perlu dilaporkan.

Beberapa kesalahan dapat ditangani secara internal (dengan coba lagi atau tidak penting (dapat diabaikan).

Bagaimana Anda menyusun kode untuk menangkapnya?

Tetapi semua kesalahan harus dicatat.

Apa praktik terbaik yang ada?

Dan untuk mensimulasikan mereka untuk dapat sepenuhnya menguji komponen yang terkena dampaknya?

Pertanyaan spesifik non-pemrograman-bahasa umum yang berlaku untuk beberapa bahasa pemrograman modern tetapi akan menyambut contoh ilustrasi pola, pendekatan dan filosofi di Jawa, C ++, PHP dan Perl.

(Juga ditanyakan dalam stackoverflow: /programming/7432596/recommend-a-design-pattern-approach-to-exposing-tolerating-recovering-from-system tapi saya pikir itu harus ditanyakan pada programmer juga karena Saya pikir programmer Q&A mencakup masalah perangkat lunak / pemrograman yang lebih luas sedangkan stackoverflow lebih tentang implementasi teknis IMHO).

therobyouknow
sumber
2
Bagi saya pertanyaan Anda tampaknya terlalu umum dan tidak dapat dijawab secara efektif. Cobalah untuk membatasi untuk beberapa kasus yang lebih spesifik dan juga untuk jenis / lingkungan aplikasi tertentu (misalnya aplikasi GUI / server / ...).
Péter Török
Lihat juga stackoverflow.com/questions/937285/…
Péter Török
@ Péter Török, mikera memberikan jawaban yang baik, kemungkinan menerima jawaban mereka.
therobyouknow

Jawaban:

16

Gagal cepat adalah pendekatan desain yang hebat, dan mungkin bisa dihitung sebagai pola: http://en.wikipedia.org/wiki/Fail-fast

Saya juga menemukan sejumlah prinsip yang berguna:

  • Pertimbangkan pengecualian sebagai bagian dari antarmuka untuk setiap fungsi / modul - yaitu mendokumentasikannya dan jika perlu / jika bahasa Anda mendukungnya, gunakan pengecualian yang dicentang.
  • Jangan pernah memperdaya kegagalan - jika gagal, jangan mencoba melanjutkan dengan beberapa upaya untuk "mengasumsikan" bagaimana melanjutkan. Sebagai contoh, penanganan khusus untuk kasus nol sering merupakan bau kode bagi saya: jika metode Anda membutuhkan nilai bukan nol, ia harus langsung melempar pengecualian jika menemui nol (baik NullPointerException atau idealnya IllegalArgumentException yang lebih deskriptif).
  • Tulis uji unit untuk kasus luar biasa dan kasus normal - kadang-kadang tes semacam itu bisa sulit untuk dilakukan tetapi perlu dilakukan ketika Anda ingin memastikan bahwa sistem Anda kuat untuk gagal.
  • Log pada titik di mana kesalahan ditangkap dan ditangani (dengan asumsi kesalahan cukup parah untuk dicatat). Alasan untuk ini adalah itu menyiratkan Anda memahami penyebabnya dan memiliki pendekatan untuk menangani kesalahan, sehingga Anda dapat membuat pesan log bermakna .....
  • Gunakan pengecualian hanya untuk kondisi / kegagalan yang benar-benar tidak terduga. Jika fungsi Anda "gagal" dengan cara yang benar-benar diharapkan (mis. Polling untuk melihat apakah lebih banyak input tersedia, dan tidak menemukan satu pun) maka ia harus mengembalikan respons normal ("tidak ada input yang tersedia"), tidak melempar pengecualian
  • Gagal dengan anggun (kredit untuk Steven Lowe!) - bersihkan sebelum diakhiri jika memungkinkan, biasanya dengan melepas perubahan, memutar kembali transaksi atau membebaskan sumber daya dalam pernyataan "akhirnya" atau setara. Pembersihan idealnya terjadi pada tingkat yang sama di mana sumber daya dilakukan demi kejelasan dan konsistensi logis.
  • Jika Anda harus gagal, gagal dengan keras - pengecualian bahwa tidak ada bagian dari kode Anda yang dapat ditangani (yaitu disaring ke tingkat atas tanpa tertangkap + ditangani) akan menyebabkan kegagalan langsung, keras dan terlihat yang mengarahkan perhatian Anda kepadanya. Saya biasanya menghentikan program atau tugas dan menulis laporan pengecualian penuh untuk System.out.
mikera
sumber
1
juga gagal dengan anggun - bersihkan sebelum mengakhiri jika mungkin
Steven A. Lowe
+1 @mikera untuk poin yang jelas tentang apa yang harus dipertimbangkan. Jawaban yang mungkin diterima, saya akan membiarkan sedikit lebih lama bagi orang lain untuk berkontribusi.
therobyouknow
+1 @Steve A. Lowe - untuk desain yang berpusat pada pengguna. misalnya suka menyimpan file, tidak meninggalkan file temporer. Lihat pertanyaan saya tentang "kebersihan data" sebagai topik terkait dalam daftar pertanyaan saya.
therobyouknow
5

Setelah bekerja dengan pengecualian di Jawa dan .NET DAN setelah membaca banyak artikel tentang bagaimana / kapan / mengapa menangkap pengecualian, saya akhirnya menemukan langkah-langkah berikut yang saya lalui di kepala setiap kali saya melihat potensi pengecualian terjadi, atau pengecualian saya harus menangkap (Jawa) ... bahkan jika itu tidak pernah terjadi (menghela napas ...). Dan sepertinya itu berfungsi, setidaknya untuk saya:

  1. Apakah ada yang berguna yang bisa saya lakukan dengan pengecualian itu, (kecuali logging)? Jika jawabannya ya, tulis kode solusinya, dan jika solusinya dapat memberikan pengecualian, buka 2:
  2. Bungkus pengecualian di sekitar pengecualian runtime, buang, pergi ke 3.
  3. Di kelas tingkat yang lebih tinggi di mana kemungkinan basis data / proses transaksi telah dimulai, tangkap pengecualian, kembalikan transaksi, rethrow pengecualian.
  4. Di kelas tingkat atas (yang mungkin merupakan tempat di mana transaksi telah dimulai), catat pengecualian menggunakan kerangka kerja logging seperti slf4j (ditambah dengan log4j misalnya), atau log4net . Jika memungkinkan, kirim langsung email pengecualian ke daftar distribusi yang terdiri dari pengembang aplikasi.
  5. Jika ada GUI, tampilkan pesan kesalahan yang menunjukkan dengan cara yang paling ramah pengguna apa yang menyebabkan masalah; tidak menampilkan exception / stacktrace, pengguna tidak peduli dan tidak perlu tahu itu adalah NullPointerException.

Saya juga harus menambahkan langkah 0 , di mana saya sengaja melemparkan apa yang saya sebut pengecualian "bisnis" (pengecualian baru yang saya buat dengan memperluas kelas "Pengecualian") ketika beberapa perawatan kompleks tidak dapat dieksekusi karena kesalahan data, TAPI itu diketahui terjadi karena telah diidentifikasi sebagai kasus pengecualian selama analisis.

Kecuali untuk bagian logging, saya sepenuhnya setuju dengan poin yang ditulis oleh "mikera"; Saya hanya akan menambahkan bahwa pengecualian harus dicatat sekali saja.

Juga, langkah-langkah yang saya daftarkan mungkin berbeda jika apa yang Anda tulis adalah API / Framework . Di sana, melemparkan pengecualian yang dirancang dengan baik adalah wajib untuk membantu pengembang memahami kesalahan mereka.

Sedangkan untuk menguji pengecualian, menggunakan objek tiruan Anda harus dapat menguji hampir semuanya, baik itu pengecualian-al atau tidak, asalkan kelas Anda menghormati praktik terbaik "satu kelas untuk melakukan satu hal". Saya juga secara pribadi memastikan untuk menandai metode yang paling penting tetapi tersembunyi sebagai "dilindungi" daripada "pribadi" sehingga saya dapat mengujinya tanpa terlalu banyak kesulitan. Terlepas dari itu, menguji pengecualian adalah sederhana, hanya memprovokasi pengecualian dan "mengharapkan" pengecualian terjadi dengan menangkapnya. Jika Anda tidak mendapatkan pengecualian, maka Anda memiliki kesalahan unit test case.

Jalayn
sumber
+1 @Jalayn untuk log4j disebut sebagai pendekatan, ini adalah apa yang saya gunakan sehingga memperkuatnya untuk mengetahui orang lain juga.
therobyouknow
0

Bangun benda Anda dengan cara yang benar, jangan khawatir tentang faktor eksternal. Jika Anda memilih untuk mengambil keuntungan dari pengecualian, maka buatlah objek Anda melempar pengecualian jika mereka gagal dalam sesuatu.

Setelah semua objek Anda bekerja dengan benar, seharusnya cukup mudah untuk membuat hierarki tanggung jawab penanganan kesalahan yang bersih dalam desain Anda.

Yam Marcovic
sumber