Saya telah menemukan sepotong kode seperti ini di salah satu proyek kami:
SomeClass QueryServer(string args)
{
try
{
return SomeClass.Parse(_server.Query(args));
}
catch (Exception)
{
return null;
}
}
Sejauh yang saya mengerti, menekan kesalahan seperti ini adalah praktik yang buruk, karena menghancurkan informasi yang berguna dari pengecualian server asli dan membuat kode berlanjut ketika sebenarnya harus diakhiri.
Kapan tepat untuk sepenuhnya menekan semua kesalahan seperti ini?
programming-practices
language-agnostic
error-handling
pengguna626528
sumber
sumber
Jawaban:
Bayangkan kode dengan ribuan file menggunakan banyak perpustakaan. Bayangkan mereka semua diberi kode seperti ini.
Bayangkan, misalnya, pembaruan server Anda menyebabkan satu file konfigurasi hilang; dan sekarang semua yang Anda miliki adalah jejak stack adalah pengecualian pointer nol ketika Anda mencoba menggunakan kelas itu: bagaimana Anda mengatasinya? Ini bisa memakan waktu berjam-jam, di mana setidaknya hanya mencatat jejak tumpukan mentah dari file yang tidak ditemukan [path file] dapat memungkinkan Anda untuk menyelesaikan sementara.
Atau bahkan lebih buruk: kegagalan di salah satu perpustakaan yang Anda gunakan setelah pembaruan yang membuat kode Anda macet nanti. Bagaimana Anda bisa melacak ini kembali ke perpustakaan?
Bahkan tanpa penanganan kesalahan yang kuat hanya melakukan
atau
dapat menghemat waktu Anda.
Tetapi ada beberapa kasus di mana Anda mungkin benar-benar ingin mengabaikan pengecualian dan mengembalikan nol seperti ini (atau tidak melakukan apa-apa). Terutama jika Anda mengintegrasikan dengan beberapa kode warisan yang dirancang dengan buruk dan pengecualian ini diharapkan sebagai kasus normal.
Bahkan ketika melakukan ini, Anda seharusnya bertanya-tanya apakah Anda benar-benar mengabaikan pengecualian atau "penanganan yang tepat" untuk kebutuhan Anda. Jika pengembalian nol adalah "penanganan yang benar" pengecualian Anda dalam kasus yang diberikan, maka lakukanlah. Dan tambahkan komentar mengapa ini adalah hal yang tepat untuk dilakukan.
Praktik terbaik adalah hal yang harus diikuti dalam sebagian besar kasus, mungkin 80%, mungkin 99%, tetapi Anda akan selalu menemukan satu kasus tepi di mana mereka tidak berlaku. Dalam hal itu, tinggalkan komentar mengapa Anda tidak mengikuti latihan untuk orang lain (atau bahkan diri Anda sendiri) yang akan membaca kode Anda beberapa bulan kemudian.
sumber
Ada kasus di mana pola ini berguna - tetapi mereka biasanya digunakan ketika pengecualian yang dihasilkan seharusnya tidak pernah terjadi (yaitu ketika pengecualian digunakan untuk perilaku normal).
Misalnya, bayangkan Anda memiliki kelas yang membuka file, menyimpannya di objek yang dikembalikan. Jika file tidak ada, Anda dapat menganggap itu bukan kasus kesalahan, Anda mengembalikan nol dan membiarkan pengguna membuat file baru sebagai gantinya. Metode buka-file dapat mengeluarkan pengecualian di sini untuk menunjukkan tidak ada file, jadi dengan diam-diam menangkapnya mungkin merupakan situasi yang valid.
Namun, ini tidak sering Anda ingin melakukan ini, dan jika kode dikotori dengan pola seperti itu, Anda ingin menghadapinya sekarang. Paling tidak saya harapkan tangkapan diam seperti itu untuk menulis baris log mengatakan ini adalah apa yang telah terjadi (Anda telah melacak, benar) dan komentar untuk menjelaskan perilaku ini.
sumber
null
jika itu yang terbaik yang dapat ditawarkan bahasa pilihan Anda.Ini adalah 100% tergantung konteks. Jika penelepon fungsi tersebut memiliki persyaratan untuk menampilkan atau mencatat kesalahan di suatu tempat, maka itu jelas tidak masuk akal. Jika penelepon mengabaikan semua pesan kesalahan atau pengecualian, tidak masuk akal untuk mengembalikan pengecualian atau pesannya. Ketika persyaratannya adalah untuk membuat kode hanya berakhir tanpa menampilkan alasan apa pun, maka panggilan
mungkin akan cukup. Anda harus mempertimbangkan apakah ini akan membuat sulit untuk menemukan penyebab kesalahan oleh pengguna - jika itu masalahnya, ini adalah bentuk penanganan kesalahan yang salah. Namun, jika kode panggilan terlihat seperti ini
maka Anda harus berdebat dengan pengembang selama tinjauan kode. Jika seseorang menerapkan bentuk penanganan yang tidak salah hanya karena dia terlalu malas untuk mencari tahu tentang persyaratan yang benar, maka kode ini tidak boleh diproduksi, dan pembuat kode harus diajarkan tentang kemungkinan konsekuensi dari kemalasan semacam itu. .
sumber
Pada tahun-tahun saya habiskan untuk pemrograman dan pengembangan sistem, hanya ada dua situasi di mana saya menemukan pola tersebut berguna (dalam kedua kasus supresi terkandung juga pencatatan pengecualian yang dilemparkan, saya tidak menganggap tangkapan biasa dan
null
kembali sebagai praktik yang baik. ).Dua situasi adalah sebagai berikut:
1. Saat pengecualian tidak dianggap sebagai kondisi luar biasa
Ini adalah ketika Anda melakukan operasi pada beberapa data, yang mungkin melempar, Anda tahu itu mungkin melempar tetapi Anda masih ingin aplikasi Anda tetap berjalan, karena Anda tidak memerlukan data yang diproses. Jika Anda menerimanya, itu baik, jika tidak, itu juga baik.
Beberapa atribut opsional suatu kelas mungkin muncul dalam pikiran.
2. Saat Anda menyediakan implementasi perpustakaan yang baru (lebih baik, lebih cepat?) Menggunakan antarmuka yang sudah digunakan dalam suatu aplikasi
Bayangkan Anda memiliki aplikasi menggunakan semacam perpustakaan lama, yang tidak membuang pengecualian tetapi kembali
null
karena kesalahan. Jadi, Anda membuat adaptor untuk pustaka ini, cukup banyak menyalin API asli pustaka, dan menggunakan antarmuka baru (masih non-melempar) dalam aplikasi Anda dan menanganinull
pemeriksaan sendiri.Versi baru pustaka hadir, atau mungkin pustaka yang sama sekali berbeda menawarkan fungsi yang sama, yang alih-alih kembali
null
, melempar pengecualian dan Anda ingin menggunakannya.Anda tidak ingin membocorkan pengecualian ke aplikasi utama Anda, jadi Anda menekan dan mencatatnya di adaptor yang Anda buat untuk membungkus ketergantungan baru ini.
Kasus pertama bukan masalah, itu adalah perilaku kode yang diinginkan. Namun, dalam situasi kedua, jika di mana-mana nilai
null
kembali adaptor perpustakaan benar-benar berarti kesalahan, refactoring API untuk melempar pengecualian dan menangkapnya alih-alih mengeceknull
mungkin (dan biasanya kode-bijaksana) ide yang bagus.Saya pribadi menggunakan pengecualian supresi hanya untuk kasus pertama. Saya hanya menggunakannya untuk kasus kedua, ketika kami tidak memiliki anggaran untuk membuat sisa aplikasi berfungsi dengan pengecualian, bukan
null
s.sumber
Walaupun tampaknya logis untuk mengatakan bahwa program seharusnya hanya menangkap pengecualian, mereka tahu cara menangani, dan tidak mungkin tahu cara menangani pengecualian yang tidak diantisipasi oleh programmer, klaim seperti itu mengabaikan fakta bahwa banyak operasi dapat gagal dalam suatu hampir tidak terbatas jumlah cara yang tidak memiliki efek samping, dan bahwa dalam banyak kasus penanganan yang tepat untuk sebagian besar kegagalan tersebut akan identik; detail pasti dari kegagalan itu tidak akan relevan, dan akibatnya tidak masalah apakah programmer mengantisipasi mereka.
Jika, misalnya, tujuan fungsi adalah untuk membaca file dokumen ke objek yang sesuai dan membuat jendela dokumen baru untuk menunjukkan objek itu atau melaporkan kepada pengguna bahwa file tidak dapat dibaca, upaya untuk memuat file dokumen tidak valid seharusnya tidak crash aplikasi - itu seharusnya bukan menampilkan pesan yang menunjukkan masalah tetapi biarkan sisa aplikasi terus berjalan normal kecuali untuk beberapa alasan upaya untuk memuat dokumen telah merusak keadaan sesuatu yang lain dalam sistem .
Pada dasarnya, penanganan eksepsi yang tepat sering kali tidak terlalu bergantung pada tipe eksepsi daripada lokasi di mana ia dilemparkan; Jika sumber daya dijaga oleh kunci baca-tulis, dan pengecualian dilemparkan dalam metode yang telah memperoleh kunci untuk membaca, perilaku yang tepat umumnya harus melepaskan kunci karena metode tidak bisa melakukan apa pun untuk sumber daya . Jika pengecualian dilemparkan saat kunci diperoleh untuk menulis, kunci harus sering tidak valid, karena sumber daya yang dijaga mungkin dalam keadaan tidak valid; jika primitif penguncian tidak memiliki status "tidak valid", seseorang harus menambahkan bendera untuk melacak pembatalan tersebut. Melepaskan kunci tanpa membatalkannya adalah buruk karena kode lain dapat melihat objek yang dijaga dalam keadaan tidak valid. Namun, meninggalkan kunci tergantung, bukan ta solusi yang tepat juga. Solusi yang tepat adalah dengan membatalkan kunci sehingga segala upaya yang tertunda atau di masa depan akuisisi akan segera gagal.
Jika ternyata sumber daya yang tidak valid ditinggalkan sebelum ada upaya untuk menggunakannya, tidak ada alasan untuk membatalkan aplikasi. Jika sumber daya yang tidak valid sangat penting untuk kelanjutan operasi aplikasi, aplikasi harus diturunkan tetapi sumber daya yang tidak valid kemungkinan akan membuat itu terjadi. Kode yang menerima pengecualian asli sering kali tidak memiliki cara untuk mengetahui situasi mana yang berlaku, tetapi jika itu membatalkan sumber daya, ia dapat memastikan bahwa tindakan yang benar akan berakhir diambil dalam kedua kasus tersebut.
sumber
Menelan kesalahan semacam ini tidak terlalu bermanfaat bagi siapa pun. Ya, penelepon asli mungkin tidak peduli tentang pengecualian tetapi orang lain mungkin .
Lalu apa yang mereka lakukan? Mereka akan menambahkan kode untuk menangani pengecualian untuk melihat rasa pengecualian apa yang mereka dapatkan kembali. Besar. Tetapi jika pawang pengecualian dibiarkan masuk, penelepon asli tidak lagi mendapat null kembali dan ada yang rusak di tempat lain.
Bahkan jika Anda menyadari bahwa beberapa kode hulu dapat menimbulkan kesalahan dan dengan demikian mengembalikan nol, itu akan menjadi inert serius bagi Anda untuk tidak setidaknya mencoba untuk mencegah pengecualian dalam kode panggilan IMHO.
sumber
Saya telah melihat contoh di mana perpustakaan pihak ketiga berpotensi memiliki metode yang berguna, kecuali bahwa mereka melempar pengecualian dalam beberapa kasus yang seharusnya bekerja untuk saya. Apa yang dapat saya?
Misalnya, metode perpustakaan
mengembalikan foo pertama, tetapi jika tidak ada itu melempar pengecualian. Tapi yang saya butuhkan adalah metode untuk mengembalikan foo pertama atau nol. Jadi saya menulis yang ini:
Tidak rapi. Namun terkadang solusi pragmatis.
sumber