Apakah pengecualian sebagai aliran kontrol dianggap sebagai antipattern yang serius? Jika ya, mengapa?


129

Kembali di akhir 90-an saya bekerja sedikit dengan basis kode yang menggunakan pengecualian sebagai kontrol aliran. Ini menerapkan mesin negara hingga untuk menggerakkan aplikasi telepon. Akhir-akhir ini saya teringat akan hari-hari itu karena saya sudah melakukan aplikasi web MVC.

Mereka berdua memiliki Controlleryang memutuskan ke mana harus pergi berikutnya dan menyediakan data ke logika tujuan. Tindakan pengguna dari domain telepon sekolah lama, seperti nada DTMF, menjadi parameter untuk metode tindakan, tetapi alih-alih mengembalikan sesuatu seperti a ViewResult, mereka melemparkan a StateTransitionException.

Saya pikir perbedaan utama adalah bahwa metode tindakan adalah voidfungsi. Saya tidak ingat semua hal yang saya lakukan dengan fakta ini, tetapi saya ragu untuk mengingat banyak hal karena sejak pekerjaan itu, seperti 15 tahun yang lalu, saya tidak pernah melihat ini dalam kode produksi di pekerjaan lain . Saya berasumsi ini adalah tanda bahwa itu disebut anti-pola.

Apakah ini masalahnya, dan jika demikian, mengapa?

Pembaruan: ketika saya mengajukan pertanyaan, saya sudah memikirkan jawaban @ MasonWheeler jadi saya pergi dengan jawaban yang paling menambah pengetahuan saya. Saya pikir itu adalah jawaban yang bagus juga.



25
Tidak. Dalam Python, menggunakan pengecualian sebagai aliran kontrol dianggap "pythonic".
user16764

4
Jika saya melakukan hal yang saya Java, saya pasti tidak akan membuang pengecualian untuk itu. Saya akan berasal dari beberapa hierarki non-Exception, non-Error, Throwable.
Thomas Eding

2
Untuk menambah jawaban yang ada, berikut adalah panduan singkat yang telah membantu saya dengan baik: - Jangan pernah menggunakan pengecualian untuk "jalan bahagia". Path bahagia dapat menjadi (untuk web) seluruh permintaan, atau hanya satu objek / metode. Semua aturan waras lainnya masih berlaku, tentu saja :)
Houen

8
Bukankah pengecualian selalu mengendalikan aliran aplikasi?

Jawaban:


109

Ada diskusi terperinci tentang ini di Ward's Wiki . Umumnya, penggunaan pengecualian untuk aliran kontrol adalah anti-pola, dengan banyak situasi penting - dan bahasa-spesifik (lihat misalnya Python ) batuk pengecualian batuk .

Sebagai ringkasan singkat mengapa, pada umumnya, ini merupakan anti-pola:

  • Pengecualian pada dasarnya adalah pernyataan GOTO yang canggih
  • Pemrograman dengan pengecualian, oleh karena itu, menyebabkan lebih sulit untuk membaca, dan memahami kode
  • Sebagian besar bahasa memiliki struktur kontrol yang ada yang dirancang untuk menyelesaikan masalah Anda tanpa menggunakan pengecualian
  • Argumen untuk efisiensi cenderung diperdebatkan untuk kompiler modern, yang cenderung untuk mengoptimalkan dengan asumsi bahwa pengecualian tidak digunakan untuk aliran kontrol.

Baca diskusi di wiki Ward untuk informasi lebih mendalam.


Lihat juga duplikat dari pertanyaan ini, di sini


18
Jawaban Anda membuatnya terdengar seolah-olah pengecualian buruk untuk semua keadaan, sementara pertanyaannya difokuskan pada pengecualian sebagai kontrol aliran.
whatsisname

14
@MasonWheeler Perbedaannya adalah bahwa untuk / sementara loop berisi perubahan kontrol aliran mereka dengan jelas dan membuat kode mudah dibaca. Jika Anda melihat pernyataan for dalam kode Anda, Anda tidak perlu mencoba mencari tahu file mana yang berisi akhir dari loop. Goto tidak buruk karena beberapa dewa mengatakan mereka, mereka buruk hanya karena mereka lebih sulit untuk diikuti daripada konstruksi perulangan. Pengecualian serupa, bukan tidak mungkin tetapi cukup keras sehingga mereka dapat membingungkan hal-hal.
Bill K

24
@BillK, lalu bantah hal itu, dan jangan membuat pernyataan sederhana tentang bagaimana pengecualian adalah gotos.
Winston Ewert

6
Oke tapi serius, ada apa dengan sisi server dan aplikasi devs mengubur kesalahan dengan pernyataan tangkapan kosong di JavaScript? Ini adalah fenomena buruk yang menghabiskan banyak waktu dan saya tidak tahu bagaimana cara bertanya tanpa mengomel. Kesalahan adalah teman Anda.
Erik Reppen

12
@ mattnz: ifdan foreachjuga canggih GOTO. Terus terang, saya pikir perbandingan dengan goto tidak membantu; hampir seperti istilah yang merendahkan. Penggunaan GOTO secara intrinsik tidak jahat - ia memiliki masalah nyata, dan pengecualian mungkin berbagi, tetapi mereka mungkin tidak. Akan lebih membantu mendengar masalah-masalah itu.
Eamon Nerbonne

110

Kasus penggunaan yang dirancang untuk pengecualian adalah "Saya baru saja menghadapi situasi yang tidak dapat saya tangani dengan benar pada saat ini, karena saya tidak memiliki konteks yang cukup untuk menanganinya, tetapi rutinitas yang memanggil saya (atau sesuatu yang lebih jauh dari panggilan itu) tumpukan) harus tahu bagaimana menanganinya. "

Kasus penggunaan sekunder adalah "Saya baru saja mengalami kesalahan serius, dan saat ini keluar dari aliran kontrol ini untuk mencegah korupsi data atau kerusakan lainnya lebih penting daripada mencoba melanjutkan."

Jika Anda tidak menggunakan pengecualian karena salah satu dari dua alasan ini, mungkin ada cara yang lebih baik untuk melakukannya.


18
Namun ini tidak menjawab pertanyaan. Untuk apa mereka dirancang tidak relevan; satu-satunya hal yang relevan adalah mengapa menggunakannya untuk aliran kontrol buruk yang merupakan topik yang tidak Anda sentuh. Sebagai contoh, template C ++ dirancang untuk satu hal tetapi sangat baik untuk digunakan untuk pemrograman, suatu penggunaan yang tidak pernah diantisipasi oleh desainer.
Thomas Bonini

6
@Krelp: Para desainer tidak pernah mengantisipasi banyak hal, seperti berakhir dengan sistem template Turing-complete tanpa sengaja! Templat C ++ bukan contoh yang baik untuk digunakan di sini.
Mason Wheeler

15
@Krelp - Templat C ++ TIDAK 'sangat baik' untuk metaprogramming. Mereka adalah mimpi buruk sampai Anda memperbaikinya, dan kemudian mereka cenderung ke arah kode hanya menulis jika Anda bukan jenius templat. Anda mungkin ingin memilih contoh yang lebih baik.
Michael Kohne

Pengecualian merusak komposisi fungsi pada khususnya, dan kode singkat pada umumnya. Misalnya ketika saya tidak berpengalaman, saya menggunakan pengecualian dalam proyek, dan itu menyebabkan masalah lama, karena 1) orang harus ingat untuk menangkapnya, 2) Anda tidak dapat menulis const myvar = theFunctionkarena myvar harus dibuat dari try-catch, oleh karena itu tidak ada lagi yang konstan. Itu tidak berarti saya tidak menggunakannya dalam C # karena ini adalah arus utama di sana untuk alasan apa pun, tapi saya tetap berusaha menguranginya.
Hi-Angel

2
@AndreasBonini Apa yang mereka dirancang / dimaksudkan untuk hal-hal karena yang sering menghasilkan keputusan implementasi compiler / framework / runtime selaras dengan desain. Misalnya, melempar pengecualian bisa jauh lebih "mahal" daripada pengembalian sederhana karena mengumpulkan informasi yang dimaksudkan untuk membantu seseorang men-debug kode seperti tumpukan jejak, dll.
binki

29

Pengecualian sekuat Lanjutan dan GOTO. Mereka adalah konstruk aliran kontrol universal.

Dalam beberapa bahasa, mereka adalah satu - satunya konstruksi aliran kontrol universal. JavaScript, misalnya, tidak memiliki Lanjutan atau GOTObahkan tidak memiliki Panggilan Ekor yang Benar. Jadi, jika Anda ingin menerapkan aliran kontrol canggih dalam JavaScript, Anda harus menggunakan Pengecualian.

Proyek Microsoft Volta adalah proyek penelitian (sekarang dihentikan) untuk mengkompilasi kode .NET sewenang-wenang ke JavaScript. .NET memiliki Pengecualian yang semantiknya tidak benar-benar memetakan JavaScript, tetapi yang lebih penting, ia memiliki Threads , dan Anda harus memetakannya entah bagaimana ke JavaScript. Volta melakukan ini dengan menerapkan Kelanjutan Volta menggunakan Pengecualian JavaScript dan kemudian mengimplementasikan semua konstruksi aliran kontrol .NET dalam kaitannya dengan Kelanjutan Volta. Mereka harus menggunakan Pengecualian sebagai aliran kontrol, karena tidak ada aliran kontrol lain yang cukup kuat.

Anda menyebutkan Mesin Negara. SM sepele untuk diterapkan dengan Panggilan Ekor yang Benar: setiap negara bagian adalah subrutin, setiap transisi negara bagian adalah panggilan subrutin. SM juga dapat dengan mudah diimplementasikan dengan GOTOatau Coroutine atau Lanjutan. Namun, Java tidak memiliki salah satu dari mereka empat, tetapi tidak memiliki Pengecualian. Jadi, sangat diterima untuk menggunakan mereka sebagai aliran kontrol. (Ya, sebenarnya, pilihan yang tepat mungkin akan menggunakan bahasa dengan konstruk aliran kontrol yang tepat, tetapi kadang-kadang Anda mungkin terjebak dengan Java.)


7
Kalau saja kita memiliki rekursi ekor-panggilan yang tepat, mungkin kita bisa mendominasi pengembangan web sisi klien dengan JavaScript dan kemudian menindaklanjuti dengan menyebar ke sisi server dan ke ponsel sebagai solusi platform pan-platform utama seperti api. Sayangnya, tapi ternyata tidak begitu. Sialnya fungsi kelas satu kita, penutupan dan paradigma yang digerakkan oleh kejadian. Yang benar-benar kami butuhkan adalah yang asli.
Erik Reppen

20
@ErikReppen: Saya sadar Anda hanya bersikap sarkastik, tapi . . Saya benar - benar tidak berpikir fakta bahwa kami "telah mendominasi pengembangan web sisi klien dengan JavaScript" ada hubungannya dengan fitur bahasa. Ini memiliki monopoli di pasar itu, sehingga telah dapat lolos dengan banyak masalah yang tidak dapat dihapuskan dengan sarkasme.
ruakh

1
Ekor rekursi akan menjadi bonus yang bagus (mereka mencemari fitur fungsi untuk memilikinya di masa depan) tapi ya, saya akan mengatakan itu menang melawan VB, Flash, Applet, dll ... karena alasan terkait fitur. Jika tidak mengurangi kerumitan dan normalisasi semudah itu akan memiliki persaingan nyata di beberapa titik. Saat ini saya sedang menjalankan Node.js untuk menangani penulisan ulang 21 file konfigurasi untuk C # + Java stack yang mengerikan dan saya tahu saya bukan satu-satunya yang melakukannya. Sangat bagus dalam hal apa yang baik.
Erik Reppen

1
Banyak bahasa yang tidak memiliki goto (dianggap berbahaya!), Coroutine atau lanjutan dan menerapkan kontrol aliran yang valid hanya dengan menggunakan ifs, whiles, dan function call (atau gosubs!). Sebagian besar dari ini sebenarnya dapat digunakan untuk meniru satu sama lain, sama seperti kelanjutan dapat digunakan untuk mewakili semua hal di atas. (Sebagai contoh, Anda dapat menggunakan beberapa saat untuk melakukan if, meskipun itu cara yang salah untuk kode). Jadi tidak ada pengecualian TIDAK diperlukan untuk melakukan kontrol aliran lanjutan.
Shayne

2
Yah ya Anda mungkin benar jika. "Untuk" dalam bentuk gaya C-nya namun dapat digunakan sebagai waktu yang dinyatakan canggung, dan beberapa saat kemudian dapat digunakan ditambah dengan jika untuk mengimplementasikan mesin keadaan terbatas yang kemudian dapat meniru semua bentuk kontrol aliran lainnya. Sekali lagi, cara kode bau, tapi ya. Dan lagi, kebagian dianggap berbahaya. (Dan saya berpendapat, demikian juga dengan menggunakan pengecualian dalam keadaan yang tidak biasa). Ingatlah bahwa ada bahasa yang benar-benar valid, dan sangat kuat yang tidak menyediakan goto atau pengecualian dan berfungsi dengan baik.
Shayne

19

Seperti yang disebutkan orang lain secara berulang-ulang, ( misalnya dalam pertanyaan Stack Overflow ) ini, prinsip yang paling mengejutkan adalah melarang Anda menggunakan pengecualian secara berlebihan untuk tujuan hanya mengontrol aliran. Di sisi lain, tidak ada aturan yang 100% benar, dan selalu ada kasus di mana pengecualian adalah "alat yang tepat" - sama seperti gotoitu sendiri, omong-omong, yang dikirimkan dalam bentuk breakdan continuedalam bahasa seperti Jawa, yang sering kali merupakan cara sempurna untuk melompat keluar dari lilitan bersarang, yang tidak selalu dapat dihindari.

Posting blog berikut menjelaskan kasus penggunaan yang agak rumit tetapi juga menarik untuk non-lokal ControlFlowException :

Ini menjelaskan bagaimana di dalam jOOQ (pustaka abstraksi SQL untuk Java) (penafian: Saya bekerja untuk vendor), pengecualian seperti itu kadang-kadang digunakan untuk membatalkan proses rendering SQL lebih awal ketika beberapa kondisi "langka" terpenuhi.

Contoh dari kondisi tersebut adalah:

  • Nilai ikatan terlalu banyak ditemui. Beberapa database tidak mendukung angka mengikat nilai acak dalam pernyataan SQL mereka (SQLite: 999, Ingres 10.1.0: 1024, Sybase ASE 15.5: 2000, SQL Server 2008: 2100). Dalam kasus-kasus tersebut, JOOQ membatalkan fase rendering SQL dan merender kembali pernyataan SQL dengan nilai-nilai binding yang digarisbawahi. Contoh:

    // Pseudo-code attaching a "handler" that will
    // abort query rendering once the maximum number
    // of bind values was exceeded:
    context.attachBindValueCounter();
    String sql;
    try {
    
      // In most cases, this will succeed:
      sql = query.render();
    }
    catch (ReRenderWithInlinedVariables e) {
      sql = query.renderWithInlinedBindValues();
    }

    Jika kami secara eksplisit mengekstraksi nilai ikat dari kueri AST untuk menghitungnya setiap waktu, kami akan membuang siklus CPU yang berharga untuk 99,9% kueri yang tidak mengalami masalah ini.

  • Beberapa logika hanya tersedia secara tidak langsung melalui API yang kami ingin jalankan hanya "sebagian". The UpdatableRecord.store()metode menghasilkan INSERTatau UPDATEpernyataan, tergantung pada Record's bendera internal. Dari "luar", kita tidak tahu jenis logika apa yang terkandung store()(misalnya penguncian optimistis, penanganan pendengar acara, dll.) Sehingga kami tidak ingin mengulangi logika itu ketika kami menyimpan beberapa catatan dalam pernyataan kumpulan, di mana kami ingin store()hanya menghasilkan pernyataan SQL, tidak benar-benar menjalankannya. Contoh:

    // Pseudo-code attaching a "handler" that will
    // prevent query execution and throw exceptions
    // instead:
    context.attachQueryCollector();
    
    // Collect the SQL for every store operation
    for (int i = 0; i < records.length; i++) {
      try {
        records[i].store();
      }
    
      // The attached handler will result in this
      // exception being thrown rather than actually
      // storing records to the database
      catch (QueryCollectorException e) {
    
        // The exception is thrown after the rendered
        // SQL statement is available
        queries.add(e.query());                
      }
    }

    Jika kami telah meng-eksternal-kan store()logikanya ke dalam API "yang dapat digunakan kembali" yang dapat dikustomisasi untuk tidak mengeksekusi SQL, kami akan mencari cara membuat API yang agak sulit dipertahankan dan sulit digunakan kembali.

Kesimpulan

Pada intinya, penggunaan non-lokal gotoini sesuai dengan apa yang dikatakan Mason Wheeler dalam jawabannya:

"Saya baru saja menghadapi situasi yang tidak dapat saya tangani dengan benar pada saat ini, karena saya tidak memiliki konteks yang cukup untuk menanganinya, tetapi rutinitas yang memanggil saya (atau sesuatu yang lebih jauh dari tumpukan panggilan) harus tahu bagaimana menanganinya . "

Kedua penggunaan ControlFlowExceptionsagak mudah diimplementasikan dibandingkan dengan alternatif mereka, memungkinkan kami untuk menggunakan kembali berbagai logika tanpa refactoring keluar dari internal yang relevan.

Tapi perasaan ini menjadi sedikit kejutan bagi pemelihara masa depan tetap ada. Kode terasa agak rumit dan meskipun itu adalah pilihan yang tepat dalam kasus ini, kami selalu memilih untuk tidak menggunakan pengecualian untuk aliran kontrol lokal , di mana mudah untuk menghindari menggunakan percabangan biasa if - else.


11

Menggunakan pengecualian untuk aliran kontrol umumnya dianggap sebagai anti-pola, tetapi ada pengecualian (tidak ada permainan kata pun yang dimaksudkan).

Telah dikatakan ribuan kali, bahwa pengecualian dimaksudkan untuk kondisi luar biasa. Koneksi basis data yang rusak adalah kondisi yang luar biasa. Pengguna memasukkan huruf dalam bidang input yang seharusnya hanya memperbolehkan angka tidak .

Bug dalam perangkat lunak Anda yang menyebabkan suatu fungsi dipanggil dengan argumen ilegal, misalnya nulljika tidak memungkinkan, adalah kondisi yang luar biasa.

Dengan menggunakan pengecualian untuk sesuatu yang tidak luar biasa, Anda menggunakan abstraksi yang tidak pantas untuk masalah yang Anda coba selesaikan.

Tetapi bisa juga ada penalti kinerja. Beberapa bahasa memiliki implementasi penanganan pengecualian yang kurang lebih efisien, jadi jika bahasa pilihan Anda tidak memiliki penanganan pengecualian yang efisien, itu bisa sangat mahal, dari segi kinerja *.

Tetapi bahasa lain, misalnya Ruby, memiliki sintaks seperti pengecualian untuk aliran kontrol. Situasi yang luar biasa ditangani oleh raise/ rescueoperator. Tetapi Anda dapat menggunakan throw/ catchuntuk konstruksi aliran kontrol pengecualian-suka **.

Jadi, meskipun pengecualian umumnya tidak digunakan untuk aliran kontrol, bahasa pilihan Anda mungkin memiliki idiom lain.

* Sebagai contoh dari penggunaan pengecualian yang mahal: Saya pernah mengatur untuk mengoptimalkan aplikasi Formulir Web ASP.NET yang berkinerja buruk. Ternyata, rendering dari sebuah meja besar memanggil int.Parse()sekitar. seribu string kosong pada halaman rata-rata, menghasilkan sekitar. seribu pengecualian sedang ditangani. Dengan mengganti kode dengan int.TryParse()saya mencukur satu detik! Untuk setiap permintaan satu halaman!

** Ini bisa sangat membingungkan bagi seorang programmer yang datang ke Ruby dari bahasa lain, karena keduanya throwdan catchmerupakan kata kunci yang terkait dengan pengecualian dalam banyak bahasa lain.


1
+1 untuk "Dengan menggunakan pengecualian untuk sesuatu yang tidak luar biasa, Anda menggunakan abstraksi yang tidak pantas untuk masalah yang Anda coba selesaikan."
Giorgio

8

Sangat mungkin untuk menangani kondisi kesalahan tanpa menggunakan pengecualian. Beberapa bahasa, terutama C, bahkan tidak memiliki pengecualian, dan orang masih berhasil membuat aplikasi yang cukup rumit dengannya. Alasan pengecualian berguna adalah mereka memungkinkan Anda untuk secara ringkas menentukan dua aliran kontrol independen pada dasarnya dalam kode yang sama: satu jika terjadi kesalahan dan satu jika tidak. Tanpa mereka, Anda berakhir dengan kode di semua tempat yang terlihat seperti ini:

status = getValue(&inout);
if (status < 0)
{
    logError("message");
    return status;
}

doSomething(*inout);

Atau setara dalam bahasa Anda, seperti mengembalikan tupel dengan satu nilai sebagai status kesalahan, dll. Seringkali orang yang menunjukkan seberapa mahal penanganan pengecualian, mengabaikan semua ifpernyataan tambahan seperti di atas yang harus Anda tambahkan jika Anda tidak t gunakan pengecualian.

Meskipun pola ini paling sering terjadi ketika menangani kesalahan atau "kondisi luar biasa" lainnya, menurut saya jika Anda mulai melihat kode boilerplate seperti ini dalam keadaan lain, Anda memiliki argumen yang cukup bagus untuk menggunakan pengecualian. Bergantung pada situasi dan implementasinya, saya dapat melihat pengecualian digunakan secara sah di mesin negara, karena Anda memiliki dua aliran kontrol ortogonal: satu yang mengubah negara dan satu untuk peristiwa yang terjadi di dalam negara.

Namun, situasi itu jarang terjadi, dan jika Anda akan membuat pengecualian (pun intended) pada aturan, Anda sebaiknya bersiap untuk menunjukkan keunggulannya terhadap solusi lain. Penyimpangan tanpa pembenaran seperti itu dengan tepat disebut sebagai anti-pola.


2
Selama pernyataan jika hanya gagal pada keadaan 'luar biasa', logika prediksi cabang CPU modern membuat biayanya dapat diabaikan. Ini adalah satu tempat di mana makro benar-benar dapat membantu, selama Anda berhati-hati dan jangan mencoba melakukan terlalu banyak di dalamnya.
James

5

Dalam Python, pengecualian digunakan untuk penghentian generator dan iterasi. Python memiliki coba / kecuali blok yang sangat efisien, tetapi sebenarnya menaikkan pengecualian memiliki beberapa overhead.

Karena kurangnya jeda multi-level atau pernyataan goto dalam Python, saya terkadang menggunakan pengecualian:

class GOTO(Exception):
  pass

try:
  # Do lots of stuff
  # in here with multiple exit points
  # each exit point does a "raise GOTO()"
except GOTO:
  pass
except Exception as e:
  #display error

6
Jika Anda harus menghentikan perhitungan di suatu tempat dalam pernyataan yang bersarang mendalam dan pergi ke beberapa kode kelanjutan umum, jalur eksekusi tertentu ini sangat mungkin dapat difaktorkan sebagai fungsi, dengan returnmenggantikannya goto.
9000

3
@ 9000 Saya baru saja akan berkomentar hal yang sama ... Tolong try:blok 1 atau 2 baris tolong, tidak pernah try: # Do lots of stuff.
wim

1
@ 9000, dalam beberapa kasus, tentu saja. Tetapi kemudian Anda kehilangan akses ke variabel lokal, dan Anda memindahkan kode Anda ke tempat lain, ketika prosesnya adalah proses linear yang koheren.
gahooa

4
@ gahooa: Dulu aku berpikir seperti kamu. Itu pertanda buruknya struktur kode saya. Ketika saya menaruh lebih banyak pemikiran di dalamnya, saya perhatikan bahwa konteks lokal dapat diurai dan seluruh kekacauan dibuat menjadi fungsi pendek dengan beberapa parameter, beberapa baris kode, dan makna yang sangat tepat. Saya tidak pernah melihat ke belakang.
9000

4

Mari kita gambarkan penggunaan Pengecualian seperti itu:

Algoritma mencari secara rekursif sampai sesuatu ditemukan. Jadi, kembali dari rekursi, kita harus memeriksa hasilnya untuk ditemukan, dan kembali lagi, jika tidak, lanjutkan. Dan itu berulang kali kembali dari kedalaman rekursi.

Selain membutuhkan boolean tambahan found(untuk dikemas dalam kelas, di mana jika tidak mungkin hanya int akan dikembalikan), dan untuk kedalaman rekursi, penutupan yang sama terjadi.

Seperti unwinding dari panggilan stack hanya apa pengecualian adalah untuk. Jadi menurut saya cara pengkodean yang tidak seperti goto, lebih cepat dan tepat. Tidak diperlukan, penggunaan yang jarang, mungkin gaya yang buruk, tetapi to-the-point. Sebanding dengan operasi pemotongan Prolog.


Hmm, apakah downvoting untuk posisi yang memang bertentangan, atau untuk argumen yang tidak memadai atau pendek? Saya sangat ingin tahu.
Joop Eggen

Saya menghadapi kesulitan ini, saya berharap Anda dapat melihat apa yang Anda pikirkan dari pertanyaan saya berikut? Secara rekursif menggunakan pengecualian untuk mengakumulasi alasan (pesan) untuk pengecualian tingkat atas codereview.stackexchange.com/questions/107862/…
CL22

@Jodes Saya baru saja membaca teknik menarik Anda, tapi saya cukup sibuk untuk saat ini. Berharap orang lain akan menjelaskan masalah ini.
Joop Eggen

4

Pemrograman adalah tentang pekerjaan

Saya pikir cara termudah untuk menjawab ini adalah untuk memahami kemajuan yang telah dibuat OOP selama bertahun-tahun. Segala sesuatu yang dilakukan dalam OOP (dan sebagian besar paradigma pemrograman, dalam hal ini) dimodelkan sekitar membutuhkan pekerjaan yang dilakukan .

Setiap kali suatu metode dipanggil, penelepon itu mengatakan, "Saya tidak tahu bagaimana melakukan pekerjaan ini, tetapi Anda tahu caranya, jadi Anda melakukannya untuk saya."

Ini menimbulkan kesulitan: apa yang terjadi ketika metode yang dipanggil umumnya tahu bagaimana melakukan pekerjaan, tetapi tidak selalu? Kami membutuhkan cara untuk berkomunikasi, "Saya ingin membantu Anda, saya benar-benar melakukannya, tetapi saya tidak bisa melakukannya."

Metodologi awal untuk mengomunikasikannya adalah mengembalikan nilai "sampah". Mungkin Anda mengharapkan bilangan bulat positif, sehingga metode yang dipanggil mengembalikan angka negatif. Cara lain untuk mencapai ini adalah dengan menetapkan nilai kesalahan di suatu tempat. Sayangnya, kedua cara ini menghasilkan kode boiler -let-me-check-over-di sini-untuk-memastikan-semuanya-halal . Ketika hal-hal menjadi lebih rumit, sistem ini berantakan.

Analogi Luar Biasa

Katakanlah Anda memiliki tukang kayu, tukang ledeng, dan tukang listrik. Anda ingin tukang ledeng untuk memperbaiki wastafel Anda, jadi dia memeriksanya. Tidak terlalu berguna jika dia hanya memberi tahu Anda, "Maaf, saya tidak bisa memperbaikinya. Sudah rusak." Sial, bahkan lebih buruk jika dia melihat, pergi, dan mengirimi Anda surat yang mengatakan ia tidak bisa memperbaikinya. Sekarang Anda harus memeriksa surat Anda bahkan sebelum Anda tahu dia tidak melakukan apa yang Anda inginkan.

Apa yang Anda inginkan adalah meminta dia memberi tahu Anda, "Dengar, saya tidak bisa memperbaikinya karena sepertinya pompa Anda tidak berfungsi."

Dengan informasi ini, Anda dapat menyimpulkan bahwa Anda ingin tukang listrik melihat masalahnya. Mungkin tukang listrik akan menemukan sesuatu yang berhubungan dengan tukang kayu, dan Anda harus memperbaikinya.

Heck, Anda mungkin bahkan tidak tahu Anda membutuhkan tukang listrik, Anda mungkin tidak tahu siapa yang Anda butuhkan. Anda hanya manajemen menengah dalam bisnis perbaikan rumah, dan fokus Anda adalah plumbing. Jadi, Anda memberi tahu bos tentang masalahnya, lalu dia memberi tahu tukang listrik untuk memperbaikinya.

Inilah yang menjadi pemodelan pengecualian: mode kegagalan kompleks dengan cara yang terpisah. Tukang ledeng tidak perlu tahu tentang tukang listrik - dia bahkan tidak perlu tahu bahwa seseorang yang berada di rantai dapat memperbaiki masalahnya. Dia hanya melaporkan masalah yang dia temui.

Jadi ... sebuah pola anti?

Oke, jadi memahami titik pengecualian adalah langkah pertama. Selanjutnya adalah memahami apa itu pola anti.

Untuk memenuhi syarat sebagai anti-pola, perlu

  • menyelesaikan masalah
  • memiliki konsekuensi negatif yang pasti

Poin pertama mudah dipenuhi - sistem bekerja, kan?

Poin kedua lebih lengket. Alasan utama untuk menggunakan pengecualian sebagai aliran kontrol normal buruk adalah karena itu bukan tujuan mereka. Setiap fungsionalitas yang diberikan dalam suatu program harus memiliki tujuan yang relatif jelas, dan mengkooptasi tujuan itu menyebabkan kebingungan yang tidak perlu.

Tapi itu bukan kerugian yang pasti . Ini cara yang buruk untuk melakukan sesuatu, dan aneh, tetapi anti-pola? Tidak. Hanya ... aneh.


Ada satu konsekuensi buruk, setidaknya dalam bahasa menyediakan jejak tumpukan penuh. Karena kode ini sangat dioptimalkan dengan banyak inlining, jejak stack nyata dan yang ingin dilihat pengembang sangat berbeda dan oleh karena itu pembuatan jejak stack mahal. Pengecualian yang terlalu sering digunakan sangat buruk untuk kinerja dalam bahasa tersebut (Java, C #).
maaartinus

"Ini cara yang buruk untuk melakukan sesuatu" - Bukankah itu cukup untuk mengklasifikasikannya sebagai anti-pola?
Maybe_Factor

@ Maybe_Factor Per definisi pola semut, no.
MirroredFate
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.