Ini adalah T terkait: Apakah penggunaan klausa akhirnya untuk melakukan pekerjaan setelah kembali gaya buruk / berbahaya?
Dalam Q yang direferensikan, kode akhirnya terkait dengan struktur yang digunakan dan perlunya pre-fetching. Pertanyaan saya sedikit berbeda, dan saya yakin itu cocok untuk audiens yang lebih luas. Contoh khusus saya adalah aplikasi C # winform, tetapi ini akan berlaku untuk C ++ / Java akhirnya digunakan juga.
Saya memperhatikan beberapa blok coba-tangkap-akhirnya di mana ada banyak kode yang tidak terkait dengan pengecualian dan penanganan / pembersihan terkubur di dalam blok. Dan saya akan mengakui bias saya terhadap memiliki blok try-catch-akhirnya yang sangat ketat dengan kode yang terkait erat dengan pengecualian dan penanganannya. Berikut adalah beberapa contoh dari apa yang saya lihat.
Blok Try akan memiliki banyak panggilan awal dan variabel yang diatur mengarah ke kode yang bisa melempar. Informasi pencatatan akan mendapatkan pengaturan dan berjalan di blok coba juga.
Akhirnya blok akan memiliki panggilan form / modul / control form (meskipun aplikasi akan segera berakhir, seperti yang dinyatakan dalam catch block), serta membuat objek baru seperti panel.
Kurang lebih:
methodName (...) { mencoba { // Banyak kode untuk metode ini ... // kode yang bisa melempar ... // Banyak lagi kode untuk metode dan pengembalian ... } menangkap (sesuatu) {// menangani pengecualian} akhirnya { // beberapa pembersihan karena pengecualian, menutup beberapa hal // lebih banyak kode untuk hal-hal yang telah dibuat (mengabaikan segala pengecualian yang bisa dilemparkan) ... // mungkin membuat beberapa objek lagi } }
Kode berfungsi, jadi ada beberapa nilai untuk itu. Tidak dienkapsulasi dengan baik dan logikanya agak berbelit-belit. Saya (dengan susah payah) akrab dengan risiko dalam mengubah kode di sekitar serta refactoring, jadi pertanyaan saya bermuara pada keinginan untuk mengetahui pengalaman orang lain dengan kode yang terstruktur serupa.
Apakah gaya buruk membenarkan membuat perubahan? Adakah yang terbakar parah dari situasi yang sama? Maukah Anda berbagi rincian pengalaman buruk itu? Biarkan itu karena saya bereaksi berlebihan dan itu tidak seburuk gaya? Dapatkan manfaat perawatan untuk membereskan semuanya?
sumber
finally
. Semua kegunaan baik tercakup dalam RAII / RRID / SBRM (mana pun yang Anda suka).finally
ada di C #). Apa yang setara dengan C ++? Apa yang saya pikirkan adalah kode setelahcatch
, dan itu berlaku sama untuk kode setelah C #finally
.Environment.FailFast()
; itu tidak dapat dieksekusi jika Anda memiliki pengecualian yang tidak tertangkap. Dan itu menjadi lebih rumit jika Anda memiliki blok iterator denganfinally
yang Anda iterate secara manual.Jawaban:
Saya telah melalui situasi yang sangat mirip ketika saya harus berurusan dengan kode Windows Forms warisan yang mengerikan yang ditulis oleh pengembang yang jelas tidak tahu apa yang mereka lakukan.
Pertama-tama, Anda tidak bertindak berlebihan. Ini kode yang salah. Seperti yang Anda katakan, blok tangkap harus tentang menggugurkan dan bersiap untuk berhenti. Ini bukan saatnya untuk membuat objek (khususnya Panel). Saya bahkan tidak bisa mulai menjelaskan mengapa ini buruk.
Yang telah dibilang...
Saran pertama saya adalah: jika tidak rusak, jangan menyentuhnya!
Jika pekerjaan Anda adalah mempertahankan kode, Anda harus melakukan yang terbaik untuk tidak merusaknya. Saya tahu ini menyakitkan (saya pernah ke sana) tetapi Anda harus melakukan yang terbaik untuk tidak merusak apa yang sudah bekerja.
Saran kedua saya adalah: jika Anda harus menambahkan lebih banyak fitur, cobalah menjaga struktur kode yang ada sebanyak mungkin agar Anda tidak melanggar kode.
Contoh: jika ada pernyataan kasus sakelar mengerikan yang Anda rasa dapat diganti dengan warisan yang tepat, Anda harus berhati-hati dan berpikir dua kali sebelum memutuskan untuk mulai memindahkan barang-barang.
Anda pasti akan menemukan situasi di mana refactoring adalah pendekatan yang tepat tetapi berhati-hatilah: kode refactoring lebih mungkin untuk memperkenalkan bug . Anda harus membuat keputusan itu dari perspektif pemilik aplikasi, bukan dari perspektif pengembang. Jadi Anda harus berpikir apakah usaha (uang) yang diperlukan untuk memperbaiki masalah itu layak dilakukan refactoring atau tidak. Saya telah melihat berkali-kali seorang pengembang menghabiskan beberapa hari memperbaiki sesuatu yang tidak benar-benar rusak hanya karena dia berpikir "kode itu jelek".
Saran ketiga saya adalah: Anda akan terbakar jika Anda memecahkan kode, tidak masalah apakah itu salah Anda atau tidak.
Jika Anda dipekerjakan untuk memberikan perawatan, tidak masalah jika aplikasi berantakan karena orang lain membuat keputusan yang buruk. Dari perspektif pengguna itu berfungsi sebelum dan sekarang Anda memecahkannya. Kamu memecahkannya!
Joel menempatkan dengan sangat baik dalam artikelnya menjelaskan beberapa alasan mengapa Anda tidak boleh menulis ulang kode warisan.
http://www.joelonsoftware.com/articles/fog0000000069.html
Jadi Anda harus merasa sangat buruk tentang kode semacam itu (dan Anda seharusnya tidak pernah menulis hal seperti itu) tetapi mempertahankannya adalah monster yang sama sekali berbeda.
Tentang pengalaman saya: Saya harus menjaga kode selama sekitar 1 tahun dan akhirnya saya bisa menulis ulang dari awal tetapi tidak sekaligus.
Apa yang terjadi adalah kode itu sangat buruk sehingga fitur-fitur baru tidak dapat diimplementasikan. Aplikasi yang ada memiliki masalah kinerja dan kegunaan yang serius. Akhirnya saya diminta untuk membuat perubahan yang akan memakan waktu 3-4 bulan (kebanyakan karena bekerja dengan kode itu membutuhkan waktu lebih lama dari biasanya). Saya pikir saya bisa menulis ulang seluruh bagian itu (termasuk mengimplementasikan fitur baru yang diinginkan) dalam waktu sekitar 5-6 bulan. Saya membawa proposisi ini kepada para pemangku kepentingan dan mereka setuju untuk menulis ulang (untungnya bagi saya).
Setelah saya menulis ulang karya ini, mereka mengerti bahwa saya bisa mengirimkan barang-barang yang jauh lebih baik daripada yang sudah mereka miliki. Jadi saya bisa menulis ulang seluruh aplikasi.
Pendekatan saya adalah menulis ulang sepotong demi sepotong. Pertama saya mengganti seluruh UI (Windows Forms), kemudian saya mulai mengganti lapisan komunikasi (panggilan Layanan Web) dan terakhir saya mengganti seluruh implementasi Server (itu adalah jenis aplikasi klien / server tebal).
Beberapa tahun kemudian dan aplikasi ini telah berubah menjadi alat kunci yang indah yang digunakan oleh seluruh perusahaan. Saya 100% yakin itu tidak akan mungkin terjadi seandainya saya tidak menulis ulang semuanya.
Meskipun saya bisa melakukannya, bagian yang penting adalah para pemangku kepentingan menyetujuinya dan saya bisa meyakinkan mereka bahwa itu sepadan dengan uang yang dikeluarkan. Jadi, sementara Anda harus mempertahankan aplikasi yang sudah ada, lakukan yang terbaik untuk tidak merusak apa pun dan jika Anda dapat meyakinkan pemilik tentang manfaat menulis ulang, maka cobalah melakukannya seperti Jack the Ripper: demi bagian.
sumber
Jika tidak perlu mengubah kode, biarkan apa adanya. Tetapi jika Anda harus mengubah kode karena Anda harus memperbaiki bug atau mengubah beberapa fungsi, Anda harus mengubahnya, apakah Anda suka atau tidak. IMHO seringkali lebih aman dan lebih rentan kesalahan, jika Anda refactor pertama menjadi potongan-potongan kecil, lebih baik dimengerti dan kemudian menambahkan fungsionalitas. Ketika Anda memiliki alat refactoring otomatis, ini dapat dilakukan relatif aman, dengan risiko yang sangat kecil untuk memperkenalkan bug baru. Dan saya sarankan Anda harus mendapatkan buku Michael Feathers
http://www.amazon.com/Working-Effectively-Legacy-Michael-Feathers/dp/0131177052
yang akan memberi Anda petunjuk berharga bagaimana membuat kode lebih dapat diuji, menambahkan tes unit dan menghindari melanggar kode saat menambahkan fitur baru.
Jika Anda melakukannya dengan benar, metode Anda semoga menjadi cukup sederhana, coba-coba-akhirnya tidak akan mengandung kode yang tidak terkait di tempat yang salah lagi.
sumber
Misalkan Anda memiliki enam metode untuk memanggil, empat di antaranya hanya boleh dipanggil jika yang pertama selesai tanpa kesalahan. Pertimbangkan dua alternatif:
vs.
Di kode kedua, Anda memperlakukan pengecualian seperti kode pengembalian. Secara konseptual, ini identik dengan:
Jika kita akan membungkus setiap metode yang dapat melempar pengecualian dalam blok coba / tangkap, apa gunanya memiliki pengecualian dalam fitur bahasa sama sekali? Tidak ada manfaatnya dan ada lagi mengetik.
Alasan mengapa kami memiliki pengecualian dalam bahasa adalah karena pada masa lalu kode pengembalian yang buruk, kami sering mengalami situasi di atas di mana kami memiliki beberapa metode yang dapat mengembalikan kesalahan, dan setiap kesalahan berarti membatalkan semua metode sepenuhnya. Di awal karir saya, di masa C dulu, saya melihat kode seperti ini di semua tempat:
Ini adalah pola yang sangat umum, dan pengecualian yang diselesaikan dengan sangat rapi memungkinkan Anda untuk kembali ke contoh pertama di atas. Aturan gaya yang mengatakan setiap metode memiliki blok pengecualian sendiri benar-benar membuang ini ke luar jendela. Lalu mengapa harus repot?
Anda harus selalu berusaha untuk membuat blok coba melampaui set kode yang secara konseptual merupakan unit. Ini harus mengelilingi kode yang jika ada kesalahan dalam unit kode, maka tidak ada gunanya menjalankan kode lain di unit kode.
Kembali ke tujuan perkecualian: ingat bahwa kode itu dibuat karena sering kali kode tidak dapat dengan mudah menangani kesalahan saat terjadi. Inti dari pengecualian adalah untuk memungkinkan Anda menangani kesalahan secara signifikan dalam kode, atau lebih jauh menumpuk. Orang-orang lupa bahwa dan dalam banyak kasus menangkap mereka secara lokal ketika mereka akan lebih baik hanya mendokumentasikan bahwa metode tersebut dapat membuang pengecualian ini. Ada terlalu banyak kode di dunia yang terlihat seperti ini:
Di sini, Anda hanya menambahkan lapisan, dan lapisan menambahkan kebingungan. Lakukan ini:
Selain itu, perasaan saya adalah bahwa jika Anda mengikuti aturan itu, dan menemukan diri Anda dengan lebih dari pasangan mencoba / menangkap blok dalam metode ini, Anda harus mempertanyakan apakah metode itu sendiri terlalu kompleks dan perlu dipecah menjadi beberapa metode .
Takeaway: blok try harus berisi set kode yang harus dibatalkan jika terjadi kesalahan di mana saja di blok. Apakah kumpulan kode ini satu baris atau seribu baris tidak masalah. (Meskipun jika Anda memiliki seribu baris dalam suatu metode, Anda punya masalah lain.)
sumber
method0
mungkin kuasi-berharap bahwa pengecualian mungkin dilemparkan, dan mereka yang tidak melakukannya. Sebagai contoh, misalkanmethod1
kadang-kadang bisa melemparInvalidArgumentException
, tetapi jika tidak, itu akan menempatkan objek ke keadaan sementara tidak valid yang akan diperbaiki olehmethod2
, yang diharapkan untuk selalu menempatkan objek kembali ke keadaan yang valid. Jika method2 melemparInvalidArgumentException
, kode yang mengharapkan untuk menangkap pengecualian seperti itumethod1
akan menangkapnya, meskipun ...