Fatalisme dalam penanganan kesalahan

Kata Pengantar


Artikel ini adalah reaksi terhadap artikel: Apa yang akan terjadi pada penanganan kesalahan di C ++ 2a . Setelah setiap paragraf, saya merasa gatal, luka sembuh terbuka dan mulai berdarah. Mungkin saya mengambil apa yang tertulis terlalu dekat dengan hati saya. Tapi saya hanya ingin melolong tentang kepicikan dan buta huruf yang ditunjukkan oleh programmer C ++ di abad ke-21. Dan bahkan pada awalnya.


Mari kita mulai.


Klasifikasi


Secara konvensional, semua situasi yang salah dalam program dapat dibagi menjadi 2 kelompok besar:
  1. Kesalahan fatal.
  2. Bukan kesalahan fatal, atau yang diharapkan.


Sekarang saya akan menemukan kesalahan. Tapi kesalahan fatal - mereka juga dalam arti yang diharapkan. Kami berharap bahwa perjalanan memori sering mengarah pada kejatuhan, tetapi mungkin tidak mengarah ke sana. Dan ini diharapkan, bukan? Ketika klasifikasi diperkenalkan, akan selalu mungkin untuk memeriksa konsistensi.


Namun demikian, ini merupakan kesalahan kecil yang sering terjadi.


Mari kita lihat kesalahan fatalnya.


Pembagian dengan 0 . Saya heran mengapa kesalahan ini fatal? Saya ingin sekali melemparkan pengecualian dalam kasus ini dan menangkapnya untuk diproses lebih lanjut. Kenapa dia fatal? Mengapa perilaku tertentu dari program saya dipaksakan pada saya, dan saya tidak dapat mempengaruhinya dengan cara apa pun? Apakah C ++ bukan tentang fleksibilitas dan tentang fakta bahwa bahasa tersebut diarahkan ke programmer? Meskipun ...


Null pointer dereferencing . Saya langsung ingat Java, ada NullPointerException yang bisa ditangani. Ada juga NullPointerException perpustakaan Poco! Jadi mengapa pengembang standar dengan keuletan si bisu-tuli mengulang mantra yang sama?


Secara umum, mengapa saya memulai topik ini? Ini sangat penting dan hanya mengungkapkan pemahaman pengembang tentang penanganan kesalahan. Ini bukan tentang penanganan kesalahan semata, ini merupakan awal dari tindakan penting. Itu selalu tentang keandalan aplikasi, tentang toleransi kesalahan, dan kadang-kadang, dalam yang paling langka dan paling terancam punah, saya bahkan akan mengatakan, jenis program yang terancam punah, tentang perilaku transaksional dan konsisten.


Dalam aspek ini, semua perselisihan tentang membagi dengan nol dan petunjuk dereferencing terlihat seperti perjuangan burung untuk remah roti. Tentunya proses yang penting. Tetapi hanya dari sudut pandang burung.


Mari kita kembali ke divisi ke fatalisme dan ketidakhadirannya ... Saya akan mulai dengan pertanyaan sederhana: jika saya menerima data yang salah melalui jaringan, apakah ini kesalahan fatal?


Jawaban sederhana dan benar: tergantung pada. Jelas bahwa dalam kebanyakan kasus ini bukan kesalahan fatal, dan semua data yang diterima melalui jaringan harus divalidasi dan 4xx dikembalikan jika datanya salah. Apakah ada kasus ketika Anda perlu crash? Dan jatuh dengan lolongan liar, sehingga SMS itu akan datang, misalnya. Ya, dan bukan satu.


Ada. Saya dapat memberikan contoh dari bidang studi saya: algoritma konsensus terdistribusi. Node menerima respons yang berisi hash dari rantai perubahan dari node lain. Dan hash ini berbeda dari yang lokal. Ini berarti ada yang tidak beres, dan melanjutkan eksekusi lebih lanjut hanya berbahaya: data mungkin akan berbeda, jika belum. Itu terjadi ketika ketersediaan layanan kurang penting daripada konsistensi. Dalam hal ini, kita harus jatuh, dan dengan suara gemuruh, sehingga semua orang mendengar. Yaitu kami menerima data melalui jaringan, mereka memvalidasi, dan jatuh. Bagi kami, kesalahan ini jauh lebih fatal. Apakah kesalahan ini terjadi? Ya, kami menulis kode dengan validasi. Bodoh mengatakan sebaliknya. Hanya kami yang tidak ingin melanjutkan program setelah itu. Diperlukan intervensi manual, otomasi tidak berfungsi.


Pilihan Fatalisme


Hal yang paling tidak jelas dalam penanganan kesalahan adalah memutuskan apa yang fatal dan apa yang tidak. Tetapi setiap programmer mengajukan pertanyaan ini kepada dirinya sendiri sepanjang seluruh kegiatan pengembangan. Karena itu, entah bagaimana ia menjawab sendiri pertanyaan ini. Jawaban yang benar berasal dari latihan karena beberapa alasan.


Namun, ini hanya bagian yang terlihat dari gunung es. Di kedalaman ada pertanyaan yang jauh lebih mengerikan. Untuk memahami kedalaman penuh, Anda perlu mengatur tugas sederhana dan mencoba menjawabnya.


Tantangan . Buat kerangka kerja untuk sesuatu.


Semuanya sederhana. Kami membuat kerangka kerja, misalnya, interaksi jaringan. Atau parsing JSON. Atau, paling buruk, XML. Pertanyaan segera muncul: tetapi ketika kesalahan terjadi dari soket - apakah itu kesalahan fatal atau tidak? Mengutip: haruskah saya melemparkan pengecualian, atau mengembalikan kesalahan? Apakah ini situasi yang luar biasa atau tidak? Atau dapat mengembalikan std::optional ? Atau seorang biarawati? (^ 1)


Kesimpulan paradoksnya adalah bahwa kerangka itu sendiri tidak dapat menjawab pertanyaan ini. Hanya kode yang menggunakannya yang tahu. Itu sebabnya, boost.asio library yang sangat baik, menurut saya, menggunakan kedua opsi. Bergantung pada preferensi pribadi pembuat kode dan logika yang diterapkan, satu atau lain metode penanganan kesalahan dapat dipilih. Pada awalnya, saya agak malu dengan pendekatan ini, tetapi seiring waktu, saya dijiwai dengan fleksibilitas dari pendekatan ini.


Namun, ini belum semuanya. Yang terburuk akan datang. Di sini kita sedang menulis kode aplikasi, tetapi tampaknya kita menerapkannya. Untuk kode lain, level yang lebih tinggi, kode kami akan menjadi pustaka. Yaitu pembagian ke dalam kode aplikasi / perpustakaan (kerangka kerja, dll.) adalah konvensi murni, yang tergantung pada tingkat penggunaan kembali komponen. Anda selalu dapat mengacaukan sesuatu di atas dan kode aplikasi tidak lagi seperti itu. Dan ini segera berarti bahwa pilihan apa yang valid dan apa yang tidak sudah ditentukan oleh kode yang digunakan, dan tidak digunakan.


Jika kita melompat ke samping, ternyata kadang-kadang bahkan tidak mungkin untuk memahami siapa yang menggunakan siapa. Yaitu komponen A dapat menggunakan komponen B , dan komponen B komponen A (^ 2). Yaitu siapa yang menentukan apa yang akan terjadi tidak jelas sama sekali.


Kusut terurai


Ketika Anda melihat semua aib ini, pertanyaan segera muncul: bagaimana hidup dengannya? Apa yang harus dilakukan Pedoman apa yang harus Anda pilih sendiri, agar tidak tenggelam dalam variasi?


Untuk melakukan ini, penting untuk melihat-lihat dan memahami bagaimana masalah-masalah tersebut diselesaikan di tempat lain. Namun, seseorang harus mencari dengan bijak: perlu untuk membedakan "pengumpulan prangko" dari solusi lengkap.


Apa itu pengumpulan prangko? Ini adalah istilah kolektif, yang berarti bahwa kami bertukar tujuan tetapi sesuatu yang lain. Sebagai contoh: kami memiliki tujuan - untuk menelepon dan berkomunikasi dengan orang yang dicintai. Dan kami pernah, dan membeli mainan mahal, karena "modis" dan "cantik" (^ 3). Apakah itu familier? Apakah Anda pikir itu tidak terjadi pada programmer? Jangan menyanjung diri sendiri.


Penanganan kesalahan bukanlah tujuannya. Setiap kali kita berbicara tentang penanganan kesalahan, kita segera terhenti. Karena itu adalah cara untuk mencapai suatu tujuan. Dan tujuan awalnya adalah menjadikan perangkat lunak kami andal, sederhana, dan mudah dipahami. Tujuan inilah yang harus ditetapkan dan selalu ditaati. Dan penanganan kesalahan adalah omong kosong yang tidak layak didiskusikan. Saya ingin melempar pengecualian - tetapi untuk kesehatan! Mengembalikan kesalahan - dilakukan dengan baik! Ingin monad? Selamat, Anda menciptakan ilusi kemajuan, tetapi hanya di kepala Anda sendiri (^ 4).


Kemudian saya ingin menulis bagaimana melakukannya dengan benar, tetapi saya sudah menulis. Luka sembuh dan berhenti berdarah. Singkatnya, tipsnya adalah:


  1. Pisahkan menjadi beberapa komponen dengan batas yang jelas.
  2. Di perbatasan, jelaskan apa dan bagaimana ia bisa terbang. Diinginkan agar seragam. Tetapi yang jauh lebih penting adalah.
  3. Memudahkan untuk menangani kesalahan dalam kode yang akan menggunakannya.
  4. Jika sesuatu dapat diproses secara internal tanpa memuat kode pengguna, jangan bertahan. Semakin sedikit kesalahan yang harus ditangani pengguna, semakin baik.
  5. Hormati pengguna Anda, jangan menjadi bajingan! Tulis antarmuka intuitif dengan perilaku yang diharapkan sehingga ia tidak perlu membaca komentar dan bersumpah.

Saran kelima adalah yang paling penting, karena ia menggabungkan empat yang pertama.


PS Di masa kecil, saya selalu penasaran untuk melihat sarang semut. Ribuan semut, semua orang melakukan sesuatu, merangkak tentang bisnisnya. Proses sedang aktif. Sekarang saya juga menonton dengan penuh minat. Juga di belakang sarang semut. Di mana ribuan orang melakukan hal kecil mereka. Saya bisa berharap semoga mereka beruntung dalam bisnis keras mereka!


^ 1: Orang menyukai hal-hal modis. Ketika semua orang sudah cukup bermain, programmer C ++ bangun, dan kemudian semuanya berbalik.


^ 2: Ini bisa terjadi ketika ada beberapa abstraksi di komponen B yang menghubungkannya. Lihat Pembalikan kontrol .


^ 3: Dan hari berikutnya, bam, dan layarnya mogok.


^ 4: Saya tidak menentang monad, saya menentang aspirasi, seperti, lihat, ini monad, yaitu. monoid dalam kategori monoid endofunctor! Tepuk tangan dan menyetujui anggukan terdengar. Dan di suatu tempat yang jauh, jauh, nyaris tak terdengar, seseorang orgasme.

Source: https://habr.com/ru/post/id426971/


All Articles