
Saya tidak pernah memiliki pendapat khusus tentang penanganan kesalahan. Jika saya mulai bekerja dengan kode yang ada, saya terus melakukan tugas yang penulis kerjakan; jika saya menulis kode dari awal, saya melakukan apa yang menurut saya benar.
Tetapi baru-baru ini, saya mengalami masalah, bug yang memanifestasikan dirinya karena kesalahan "diam" dalam kode. Saya menyadari bahwa ada sesuatu untuk direnungkan. Mungkin saya tidak bisa mengubah cara saya menangani kesalahan di seluruh basis kode yang saya kerjakan, tetapi sesuatu pasti dapat dioptimalkan.
Kami mengingatkan Anda: untuk semua pembaca "Habr" - diskon 10.000 rubel saat mendaftar untuk kursus Skillbox apa pun menggunakan kode promo "Habr".
Skillbox merekomendasikan: Kursus pendidikan online "Pengembang Java Profesi" .
Tidak selalu layak memotong bahu
Langkah pertama dalam penanganan kesalahan harus memahami ketika "kesalahan" bukan "kesalahan!" Tentu saja, semua ini tergantung pada logika bisnis aplikasi Anda, tetapi secara umum, beberapa bug bersifat eksplisit dan dapat diperbaiki tanpa masalah.
- Apakah Anda memiliki rentang tanggal di mana "sebelum" adalah sebelum "dari"? Susun ulang.
- Apakah Anda memiliki nomor telepon yang dimulai dengan + atau berisi tanda hubung di mana Anda tidak mengharapkan karakter khusus muncul? Hapus mereka.
- Masalah koleksi tidak ada? Pastikan Anda menginisialisasi ini sebelum akses (menggunakan inisialisasi malas atau konstruktor).
Jangan hentikan eksekusi kode karena kesalahan yang dapat Anda perbaiki, dan, tentu saja, jangan mengganggu tindakan Anda kepada pengguna layanan atau aplikasi Anda. Jika Anda dapat memahami masalah dan menyelesaikannya dengan cepat - lakukan saja.

Kembalikan Null atau angka ajaib lainnya
Nilai nol, –1 di mana angka positif diharapkan, dan nilai sulap lainnya - semua ini adalah produk iblis, yang mentransfer tanggung jawab untuk memeriksa kesalahan ke fungsi panggilan.
Dengan mereka, kode Anda akan penuh dengan blok seperti itu yang akan membuat logika aplikasi tidak jelas:
return_value = possibly_return_a_magic_value() if return_value < 0: handle_error() else: do_something() other_return_value = possibly_nullable_value() if other_return_value is None: handle_null_value() else: do_some_other_thing()
Baik, atau lebih sederhana, tetapi juga buruk:
var item = returnSomethingWhichCouldBeNull(); var result = item?.Property?.MaybeExists; if (result.HasValue) { DoSomething(); }
Melewati nol ke metode juga merupakan masalah, meskipun dalam beberapa kode pengembang Anda mungkin menemukan tempat di mana metode dimulai dengan beberapa baris validasi input. Namun faktanya, semua ini tidak perlu. Sebagian besar bahasa modern tidak hanya menyediakan satu, tetapi beberapa alat sekaligus, yang memungkinkan Anda untuk dengan jelas menunjukkan apa yang Anda harapkan. Mereka juga melewatkan pemeriksaan yang tidak berguna, misalnya, mendefinisikan parameter sebagai bukan nol atau dengan dekorator yang sesuai.
Kode Kesalahan
Ini adalah masalah yang sama dengan nol dan nilai-nilai serupa lainnya ketika komplikasi kode yang tidak perlu ditambahkan.
Misalnya, Anda dapat menggunakan konstruksi ini untuk mengembalikan kode kesalahan:
int errorCode; var result = getSomething(out errorCode); if (errorCode != 0) { doSomethingWithResult(result); }
Hasilnya dapat ditampilkan sebagai berikut:
public class Result<T> { public T Item { get; set; }
Ini benar-benar bukan kode terbaik. Ternyata Item itu masih bisa kosong. Bahkan, tidak ada jaminan (selain perjanjian) bahwa ketika hasilnya tidak mengandung kesalahan, Anda dapat dengan aman mengakses Item.
Setelah Anda selesai dengan semua pemrosesan ini, Anda masih harus mengubah kode bug menjadi pesan kesalahan dan melakukan sesuatu dengannya. Kadang-kadang terjadi bahwa, karena kompleksitas kode yang berlebihan, pesan ini sendiri tidak ditampilkan sebagaimana mestinya.
Ada masalah yang bahkan lebih serius: jika Anda atau orang lain mengubah implementasi internal untuk menangani keadaan tidak valid baru dengan kode kesalahan baru, maka seluruh struktur akan berhenti berfungsi sama sekali.
Jika tidak berhasil pertama kali, coba lagi
Sebelum melanjutkan, ada baiknya menekankan bahwa kegagalan program "diam" itu buruk. Masalah yang tidak terduga dapat terjadi pada saat yang paling tidak tepat - misalnya, pada akhir pekan, ketika Anda tidak dapat dengan cepat memperbaiki semuanya.

Jika Anda membaca
Kode Bersih , maka kemungkinan besar Anda bertanya-tanya mengapa tidak hanya melemparkan pengecualian? Jika tidak, maka kemungkinan besar Anda berpikir bahwa pengecualian adalah akar kejahatan. Saya dulu juga berpikir begitu, tetapi sekarang saya berpikir sedikit berbeda.
Hal yang menarik, setidaknya bagi saya, adalah bahwa implementasi default untuk metode baru di C # adalah untuk meningkatkan NotImplementedException, sedangkan default untuk metode baru di Python adalah "lulus".
Akibatnya, paling sering kita memasuki pengaturan "kesalahan diam" untuk Python. Saya bertanya-tanya berapa banyak pengembang yang menghabiskan banyak waktu untuk memahami apa yang terjadi dan mengapa program tidak bekerja. Tetapi pada akhirnya, setelah berjam-jam, mereka menemukan bahwa mereka lupa menerapkan metode placeholder.
Tapi lihat ini:
public MyDataObject UpdateSomething(MyDataObject toUpdate) { if (_dbConnection == null) { throw new DbConnectionError(); } try { var newVersion = _dbConnection.Update(toUpdate); if (newVersion == null) { return null; } MyDataObject result = new MyDataObject(newVersion); return result; } catch (DbConnectionClosedException dbcc) { throw new DbConnectionError(); } catch (MyDataObjectUnhappyException dou) { throw new MalformedDataException(); } catch (Exception ex) { throw new UnknownErrorException(); } }
Tentu saja, pengecualian saja tidak akan melindungi Anda dari membuat kode yang tidak dapat dibaca dan tidak dikelola. Anda harus menerapkan pengecualian sebagai strategi yang dipikirkan dengan matang dan seimbang. Kalau tidak, jika proyek terlalu besar, aplikasi Anda mungkin dalam keadaan tidak konsisten. Sebaliknya, jika proyek terlalu kecil, Anda akan mendapatkan kekacauan.
Untuk mencegah hal ini terjadi, saya menyarankan Anda untuk mengingatnya:
Konsistensi di atas segalanya. Anda harus selalu memastikan bahwa aplikasi tersebut konsisten. Jika ini berarti Anda harus membungkus setiap pasangan garis dengan blok coba / tangkap, sembunyikan semuanya di fungsi lain.
def my_function(): try: do_this() do_that() except: something_bad_happened() finally: cleanup_resource()
Diperlukan konsolidasi kesalahan. Baik jika Anda memberikan berbagai jenis penanganan berbagai jenis kesalahan. Namun, ini untuk Anda, bukan pengguna. Bagi mereka, lempar satu-satunya pengecualian agar pengguna hanya tahu bahwa ada sesuatu yang salah. Detail adalah bidang tanggung jawab Anda.
public MyDataObject UpdateSomething(MyDataObject toUpdate) { try { var newVersion = _dbConnection.Update(toUpdate); MyDataObject result = new MyDataObject(newVersion); return result; } catch (DbConnectionClosedException dbcc) { HandleDbConnectionClosed(); throw new UpdateMyDataObjectException(); } catch (MyDataObjectUnhappyException dou) { RollbackVersion(); throw new UpdateMyDataObjectException(); } catch (Exception ex) { throw new UpdateMyDataObjectException(); } }
Perlu menangkap pengecualian segera. Mereka paling baik dicegat di tingkat terendah. Tetap konsisten dan menyembunyikan detail sepadan seperti yang dijelaskan di atas. Penanganan kesalahan harus diserahkan ke tingkat atas aplikasi. Jika semuanya dilakukan dengan benar, Anda dapat memisahkan aliran logika aplikasi itu sendiri dari aliran pemrosesan kesalahan. Ini memungkinkan Anda untuk menulis kode yang jelas dan mudah dibaca.
def my_api(): try: item = get_something_from_the_db() new_version = do_something_to_item(item) return new_version except Exception as ex: handle_high_level_exception(ex)
Itu saja untuk saat ini, dan jika Anda ingin membahas topik kesalahan dan pemrosesan mereka - Wellcome.
Skillbox merekomendasikan: