Parameter untuk mengontrol apakah akan melempar pengecualian atau mengembalikan null - praktik yang baik?

24

Saya sering menemukan metode / fungsi yang memiliki parameter boolean tambahan yang mengontrol apakah pengecualian dilemparkan pada kegagalan, atau null dikembalikan.

Sudah ada diskusi tentang yang mana yang merupakan pilihan yang lebih baik dalam hal ini, jadi jangan fokus pada hal ini di sini. Lihat mis. Mengembalikan nilai sulap, melemparkan pengecualian atau mengembalikan false pada kegagalan?

Sebagai gantinya, mari kita asumsikan bahwa ada alasan bagus mengapa kita ingin mendukung keduanya.

Secara pribadi saya pikir metode seperti itu lebih baik harus dibagi menjadi dua: Satu yang melempar pengecualian pada kegagalan, yang lain mengembalikan nol pada kegagalan.

Jadi, mana yang lebih baik?

A: Satu metode dengan $exception_on_failureparameter.

/**
 * @param int $id
 * @param bool $exception_on_failure
 *
 * @return Item|null
 *   The item, or null if not found and $exception_on_failure is false.
 * @throws NoSuchItemException
 *   Thrown if item not found, and $exception_on_failure is true.
 */
function loadItem(int $id, bool $exception_on_failure): ?Item;

B: Dua metode yang berbeda.

/**
 * @param int $id
 *
 * @return Item|null
 *   The item, or null if not found.
 */
function loadItemOrNull(int $id): ?Item;

/**
 * @param int $id
 *
 * @return Item
 *   The item, if found (exception otherwise).
 *
 * @throws NoSuchItemException
 *   Thrown if item not found.
 */
function loadItem(int $id): Item;

EDIT: C: Ada yang lain?

Banyak orang menyarankan opsi lain, atau mengklaim bahwa A dan B cacat. Saran atau pendapat semacam itu disambut baik, relevan dan bermanfaat. Jawaban lengkap dapat berisi informasi tambahan seperti itu, tetapi juga akan menjawab pertanyaan utama apakah parameter untuk mengubah tanda tangan / perilaku adalah ide yang bagus.

Catatan

Jika seseorang bertanya-tanya: Contohnya dalam PHP. Tapi saya pikir pertanyaannya berlaku lintas bahasa asalkan mirip dengan PHP atau Java.

donquixote
sumber
5
Meskipun saya harus bekerja di PHP dan saya cukup mahir, itu hanya bahasa yang buruk, dan perpustakaan standarnya ada di semua tempat. Baca eev.ee/blog/2012/04/09/php-a-fractal-of-bad-design untuk referensi. Jadi tidak terlalu mengejutkan bahwa beberapa pengembang PHP mengadopsi kebiasaan buruk. Tapi saya belum melihat bau desain khusus ini.
Polygnome
Saya kehilangan poin penting dalam jawaban yang diberikan: kapan Anda akan menggunakan satu atau yang lain. Anda akan menggunakan metode pengecualian jika item tidak ditemukan akan menjadi tak terduga dan dianggap sebagai kesalahan (waktu panik). Anda akan menggunakan metode Try ... jika item yang hilang bukan tidak mungkin dan tentu saja bukan kesalahan tetapi hanya kemungkinan Anda termasuk dalam kontrol aliran normal Anda.
Martin Maat
1
@ Polygnome Anda benar, fungsi pustaka standar ada di semua tempat, dan ada banyak kode yang buruk, dan ada masalah satu-proses-per-permintaan. Tetapi semakin baik dengan setiap versi. Jenis dan model objek melakukan semua atau sebagian besar hal yang dapat diharapkan seseorang darinya. Saya ingin melihat obat generik, co-dan contravariance, jenis panggilan balik yang menentukan tanda tangan, dll. Banyak dari ini sedang dibahas atau dalam cara untuk dilaksanakan. Saya pikir arahan keseluruhan baik, meskipun kebiasaan perpustakaan standar tidak akan hilang dengan mudah.
donquixote
4
Satu saran: alih-alih loadItemOrNull(id), pertimbangkan apakah loadItemOr(id, defaultItem)masuk akal untuk Anda. Jika item adalah String atau angka, itu sering terjadi.
user949300

Jawaban:

35

Anda benar: dua metode jauh lebih baik untuk itu, karena beberapa alasan:

  1. Di Jawa, tanda tangan dari metode yang berpotensi melempar pengecualian akan mencakup pengecualian ini; metode lain tidak. Itu membuatnya sangat jelas apa yang diharapkan dari yang satu dan yang lain.

  2. Dalam bahasa seperti C # di mana tanda tangan metode tidak memberi tahu apa pun tentang pengecualian, metode publik masih harus didokumentasikan, dan dokumentasi tersebut mencakup pengecualian. Mendokumentasikan metode tunggal tidak akan mudah.

    Contoh Anda sempurna: komentar di bagian kedua kode terlihat jauh lebih jelas, dan saya bahkan akan menyingkat "Item, jika ditemukan (pengecualian sebaliknya)." Ke bawah ke "Item." - adanya pengecualian potensial dan deskripsi yang Anda berikan padanya cukup jelas.

  3. Dalam kasus metode tunggal, ada beberapa kasus di mana Anda ingin beralih nilai parameter boolean saat runtime , dan jika Anda melakukannya, itu berarti pemanggil harus menangani kedua kasus ( nullrespons dan pengecualian). ), membuat kode jauh lebih sulit daripada yang seharusnya. Karena pilihan dibuat bukan pada saat runtime, tetapi ketika menulis kode, dua metode masuk akal.

  4. Beberapa kerangka kerja, seperti .NET Framework, telah menetapkan konvensi untuk situasi ini, dan mereka menyelesaikannya dengan dua metode, seperti yang Anda sarankan. Satu-satunya perbedaan adalah bahwa mereka menggunakan pola yang dijelaskan oleh Ewan dalam jawabannya , jadi berikan int.Parse(string): intpengecualian, sementara int.TryParse(string, out int): booltidak. Konvensi penamaan ini sangat kuat di komunitas .NET dan harus diikuti setiap kali kode cocok dengan situasi yang Anda jelaskan.

Arseni Mourzenko
sumber
1
Terima kasih, ini jawaban yang saya cari! Tujuannya adalah saya memulai diskusi tentang ini untuk Drupal CMS, drupal.org/project/drupal/issues/2932772 , dan saya tidak ingin ini menjadi tentang preferensi pribadi saya, tetapi mendukungnya dengan umpan balik dari orang lain.
donquixote
4
Sebenarnya tradisi lama setidaknya. NET adalah TIDAK menggunakan dua metode, tetapi memilih pilihan yang tepat untuk tugas yang tepat. Pengecualian untuk keadaan luar biasa, bukan untuk menangani aliran kontrol yang diharapkan. Gagal mengurai string menjadi integer? Bukan situasi yang sangat tidak terduga atau luar biasa. int.Parse()dianggap sebagai keputusan desain yang sangat buruk, itulah sebabnya tim .NET terus maju dan mengimplementasikan TryParse.
Voo
1
Menyediakan dua metode alih-alih memikirkan jenis kasus penggunaan yang sedang kita tangani, adalah jalan keluar yang mudah: Jangan memikirkan apa yang Anda lakukan, alih-alih berikan tanggung jawab pada semua pengguna API Anda. Tentu itu berfungsi, tapi itu bukan ciri khas desain API yang baik (atau desain apa pun untuk masalah ini. Baca misalnya pendapat Joel mengenai hal ini .
Voo
@Vo Poin valid. Memang memberikan dua metode menempatkan pilihan pada penelepon. Mungkin untuk beberapa nilai parameter item diharapkan ada, sedangkan untuk nilai parameter lainnya item yang tidak ada dianggap sebagai kasus biasa. Mungkin komponen tersebut digunakan dalam satu aplikasi di mana item selalu diharapkan ada, dan dalam aplikasi lain di mana item yang tidak ada dianggap normal. Mungkin penelepon memanggil ->itemExists($id)sebelum menelepon ->loadItem($id). Atau mungkin itu hanya pilihan yang dibuat oleh orang lain di masa lalu, dan kita harus menerima begitu saja.
donquixote
1
Alasan 1b: Beberapa bahasa (Haskell, Swift) membutuhkan nullability untuk hadir dalam tanda tangan. Secara khusus, Haskell memiliki tipe yang sama sekali berbeda untuk nilai nullable ( data Maybe a = Just a | Nothing).
John Dvorak
9

Variasi yang menarik adalah bahasa Swift. Di Swift, Anda mendeklarasikan fungsi sebagai "melempar", yaitu diizinkan untuk melempar kesalahan (serupa tetapi tidak persis sama dengan pengecualian Java). Pemanggil dapat memanggil fungsi ini dalam empat cara:

Sebuah. Dalam pernyataan coba-coba menangkap dan menangani pengecualian.

b. Jika penelepon itu sendiri dinyatakan sebagai melempar, panggil saja, dan setiap kesalahan yang dilemparkan berubah menjadi kesalahan yang dilemparkan oleh penelepon.

c. Menandai panggilan fungsi dengan try!yang berarti "Saya yakin panggilan ini tidak akan membuang". Jika fungsi yang disebut melakukan lemparan, aplikasi dijamin kecelakaan.

d. Menandai pemanggilan fungsi try?yang artinya "Saya tahu fungsi itu bisa melempar tapi saya tidak peduli kesalahan mana yang sebenarnya dilemparkan". Ini mengubah nilai kembali fungsi dari tipe " T" ke tipe " optional<T>", dan pengecualian yang dilemparkan diubah menjadi pengembalian nihil.

(a) dan (d) adalah kasus yang Anda tanyakan. Bagaimana jika fungsi tersebut dapat mengembalikan nol dan dapat melempar pengecualian? Dalam kasus itu, tipe nilai pengembalian akan menjadi " optional<R>" untuk beberapa tipe R, dan (d) akan mengubahnya menjadi " optional<optional<R>>" yang agak samar dan sulit dimengerti tetapi sepenuhnya baik - baik saja. Dan fungsi Swift dapat kembali optional<Void>, jadi (d) dapat digunakan untuk melempar fungsi yang mengembalikan Void.

gnasher729
sumber
2

Saya suka bool TryMethodName(out returnValue)pendekatannya.

Ini memberi Anda indikasi konklusif apakah metode ini berhasil atau tidak dan penamaan cocok dengan membungkus metode pengecualian melempar di blok try catch.

Jika Anda hanya mengembalikan nol, Anda tidak tahu apakah itu gagal atau nilai pengembaliannya nol.

misalnya:

//throws exceptions when error occurs
Item LoadItem(int id);

//returns false when error occurs
bool TryLoadItem(int id, out Item item)

contoh penggunaan (berarti keluar melalui referensi tanpa diinisialisasi)

Item i;
if(TryLoadItem(3, i))
{
    Print(i.Name);
}
else
{
    Print("unable to load item :(");
}
Ewan
sumber
Maaf, Anda kehilangan saya di sini. Bagaimana " bool TryMethodName(out returnValue)pendekatan" Anda terlihat dalam contoh asli?
donquixote
diedit untuk menambahkan contoh
Ewan
1
Jadi Anda menggunakan parameter referensi-alih alih-alih nilai balik, sehingga Anda memiliki nilai pengembalian gratis untuk keberhasilan bool? Apakah ada bahasa pemrograman yang mendukung kata kunci "keluar" ini?
donquixote
2
ya, maaf tidak menyadari 'keluar' khusus untuk c #
Ewan
1
tidak selalu tidak. Tetapi bagaimana jika item 3 adalah null? Anda tidak akan tahu apakah ada kesalahan atau tidak
Ewan
2

Biasanya parameter boolean menunjukkan fungsi dapat dipecah menjadi dua, dan sebagai aturan Anda harus selalu membaginya daripada melewati dalam boolean.

Maks
sumber
1
Saya tidak akan kecuali ini sebagai aturan tanpa menambahkan kualifikasi atau nuansa. Menghapus boolean sebagai argumen dapat memaksa Anda untuk menulis bodoh jika / lain di tempat lain dan karenanya Anda menyandikan data dalam kode tertulis Anda dan bukan dalam variabel.
Gerard
@ Gerard dapatkah Anda memberi saya contoh?
Maks
@ Max Ketika Anda memiliki variabel boolean b: Alih-alih memanggil foo(…, b);Anda harus menulis if (b) then foo_x(…) else foo_y(…);dan mengulangi argumen lain, atau sesuatu seperti ((b) ? foo_x : foo_y)(…)jika bahasa memiliki operator ternary dan fungsi / metode kelas satu. Dan ini bahkan mungkin diulang dari beberapa tempat yang berbeda dalam program ini.
BlackJack
@ BlackJack, ya saya mungkin setuju dengan Anda. Saya memikirkan contohnya, if (myGrandmaMadeCookies) eatThem() else makeFood()yang ya saya mungkin bungkus dengan fungsi lain seperti ini checkIfShouldCook(myGrandmaMadeCookies). Saya bertanya-tanya apakah nuansa yang Anda sebutkan berkaitan dengan apakah kita memberikan boolean tentang bagaimana kita ingin fungsi berperilaku, seperti dalam pertanyaan awal, vs. kita menyampaikan beberapa info tentang model kita, seperti pada Contoh nenek saya baru saja memberi.
Maks
1
Nuansa yang dimaksud dalam komentar saya mengacu pada "Anda harus selalu". Mungkin ulang kata itu sebagai "jika a, b dan c berlaku maka [...]". "Aturan" yang Anda sebutkan adalah paradigma yang hebat, tetapi sangat bervariasi dalam hal penggunaan.
Gerard
1

Clean Code menyarankan untuk menghindari argumen bendera boolean, karena artinya buram di situs panggilan:

loadItem(id, true) // does this throw or not? We need to check the docs ...

sedangkan metode terpisah dapat menggunakan nama ekspresif:

loadItemOrNull(id); // meaning is obvious; no need to refer to docs
meriton - mogok
sumber
1

Jika saya harus menggunakan A atau B maka saya akan menggunakan B, dua metode terpisah, untuk alasan yang disebutkan dalam jawaban Arseni Mourzenkos .

Tetapi ada metode lain 1 : Di Jawa disebut Optional, tetapi Anda dapat menerapkan konsep yang sama untuk bahasa lain di mana Anda dapat menentukan jenis Anda sendiri, jika bahasa tersebut belum menyediakan kelas yang sama.

Anda mendefinisikan metode Anda seperti ini:

Optional<Item> loadItem(int id);

Dalam metode Anda, Anda akan kembali Optional.of(item)jika Anda menemukan item atau Anda kembali Optional.empty()jika Anda tidak. Anda tidak pernah membuang 2 dan tidak pernah kembali null.

Untuk klien dari metode Anda, itu adalah sesuatu seperti null, tetapi dengan perbedaan besar yang memaksa untuk berpikir tentang kasus barang yang hilang. Pengguna tidak bisa begitu saja mengabaikan fakta bahwa mungkin tidak ada hasil. OptionalDiperlukan untuk mengeluarkan item dari tindakan eksplisit:

  • loadItem(1).get()akan melempar NoSuchElementExceptionatau mengembalikan barang yang ditemukan.
  • Ada juga yang loadItem(1).orElseThrow(() -> new MyException("No item 1"))menggunakan pengecualian khusus jika yang dikembalikan Optionalkosong.
  • loadItem(1).orElse(defaultItem)mengembalikan item yang ditemukan atau yang berlalu defaultItem(yang mungkin juga null) tanpa melemparkan pengecualian.
  • loadItem(1).map(Item::getName)akan kembali lagi Optionaldengan nama item, jika ada.
  • Ada beberapa metode lagi, lihat Javadoc untukOptional .

Keuntungannya adalah sekarang tergantung pada kode klien apa yang harus terjadi jika tidak ada item dan Anda hanya perlu menyediakan metode tunggal .


1 Saya kira itu adalah sesuatu seperti try?di jawaban gnasher729s tetapi tidak sepenuhnya jelas bagi saya karena saya tidak tahu Swift dan tampaknya menjadi fitur bahasa jadi itu khusus untuk Swift.

2 Anda dapat melempar pengecualian untuk alasan lain, misalnya jika Anda tidak tahu apakah ada item atau tidak karena Anda memiliki masalah berkomunikasi dengan database.

siegi
sumber
0

Sebagai hal lain yang setuju menggunakan dua metode, ini bisa sangat mudah diimplementasikan. Saya akan menulis contoh saya dalam C #, karena saya tidak tahu sintaks PHP.

public Widget GetWidgetOrNull(int id) {
    // All the lines to get your item, returning null if not found
}

public Widget GetWidget(int id) {
    var widget = GetWidgetOrNull(id);

    if (widget == null) {
        throw new WidgetNotFoundException();
    }

    return widget;
}
krillgar
sumber
0

Saya lebih suka dua metode, dengan cara ini, Anda tidak hanya akan memberi tahu saya Anda mengembalikan nilai, tetapi nilai mana yang tepat.

public int GetValue(); // If you can't get the value, you'll throw me an exception
public int GetValueOrDefault(); // If you can't get the value, you'll return me 0, since it's the default for ints

TryDoSomething () juga bukan pola yang buruk.

public bool TryParse(string value, out int parsedValue); // If you return me false, I won't bother checking parsedValue.

Saya lebih terbiasa melihat yang pertama dalam interaksi basis data sementara yang terakhir lebih banyak digunakan dalam hal-hal parse.

Seperti yang telah diberitahukan sebelumnya kepada Anda, parameter flag biasanya adalah bau kode (bau kode tidak berarti Anda melakukan sesuatu yang salah, hanya saja ada kemungkinan Anda salah melakukannya). Meskipun Anda menyebutkannya dengan tepat, kadang-kadang ada nuansa yang membuat sulit untuk mengetahui cara menggunakan bendera itu dan Anda akhirnya melihat ke dalam tubuh metode.

A Bravo Dev
sumber
-1

Sementara orang lain menyarankan sebaliknya, saya akan menyarankan bahwa memiliki metode dengan parameter untuk menunjukkan bagaimana kesalahan harus ditangani lebih baik daripada membutuhkan penggunaan metode terpisah untuk dua skenario penggunaan. Sementara itu mungkin diinginkan untuk juga memiliki entry point yang berbeda untuk "kesalahan melempar" versus "indikasi kesalahan kembali kesalahan" penggunaan, memiliki titik masuk yang dapat melayani kedua pola penggunaan akan menghindari duplikasi kode dalam metode wrapper. Sebagai contoh sederhana, jika seseorang memiliki fungsi:

Thing getThing(string x);
Thing tryGetThing (string x);

dan satu menginginkan fungsi yang berperilaku sama tetapi dengan x dibungkus tanda kurung, akan diperlukan untuk menulis dua set fungsi pembungkus:

Thing getThingWithBrackets(string x)
{
  getThing("["+x+"]");
}
Thing tryGetThingWithBrackets (string x);
{
  return tryGetThing("["+x+"]");
}

Jika ada argumen untuk cara menangani kesalahan, hanya satu bungkus yang akan dibutuhkan:

Thing getThingWithBrackets(string x, bool returnNullIfFailure)
{
  return getThing("["+x+"]", returnNullIfFailure);
}

Jika pembungkusnya cukup sederhana, duplikasi kode mungkin tidak terlalu buruk, tetapi jika mungkin perlu diubah, menduplikasi kode pada gilirannya akan membutuhkan duplikasi perubahan apa pun. Bahkan jika seseorang memilih untuk menambahkan titik masuk yang tidak menggunakan argumen tambahan:

Thing getThingWithBrackets(string x)
{
   return getThingWithBrackets(x, false);
}
Thing tryGetThingWithBrackets(string x)
{
   return tryGetThingWithBrackets(x, true);
}

seseorang dapat menyimpan semua "logika bisnis" dalam satu metode - metode yang menerima argumen yang menunjukkan apa yang harus dilakukan jika terjadi kegagalan.

supercat
sumber
Anda benar: Dekorator dan pembungkus, dan bahkan implementasi reguler, akan memiliki duplikasi kode ketika menggunakan dua metode.
donquixote
Tentunya menempatkan versi dengan dan tanpa pengecualian melemparkan dalam paket terpisah, dan membuat pembungkusnya menjadi umum?
Will Crawford
-1

Saya pikir semua jawaban yang menjelaskan bahwa Anda seharusnya tidak memiliki bendera yang mengontrol apakah pengecualian dilemparkan atau tidak baik. Nasihat mereka akan menjadi saran saya untuk siapa saja yang merasa perlu untuk mengajukan pertanyaan itu.

Namun, saya ingin menunjukkan bahwa ada pengecualian yang berarti untuk aturan ini. Setelah Anda cukup maju untuk mulai mengembangkan API yang akan digunakan oleh ratusan orang lainnya, ada beberapa kasus di mana Anda mungkin ingin memberikan tanda seperti itu. Saat Anda menulis API, Anda tidak hanya menulis ke pembuat puritan. Anda menulis kepada pelanggan nyata yang memiliki keinginan nyata. Bagian dari pekerjaan Anda adalah membuatnya senang dengan API Anda. Itu menjadi masalah sosial, bukan masalah pemrograman, dan terkadang masalah sosial menentukan solusi yang kurang ideal sebagai solusi pemrograman sendiri.

Anda mungkin menemukan bahwa Anda memiliki dua pengguna berbeda dari API Anda, satu di antaranya menginginkan pengecualian dan satu lagi tidak. Contoh kehidupan nyata di mana ini bisa terjadi adalah dengan perpustakaan yang digunakan baik dalam pengembangan dan pada sistem tertanam. Dalam lingkungan pengembangan, pengguna mungkin ingin memiliki pengecualian di mana-mana. Pengecualian sangat populer untuk menangani situasi yang tidak terduga. Namun, mereka dilarang dalam banyak situasi tertanam karena mereka terlalu sulit untuk menganalisis kendala waktu nyata di sekitar. Ketika Anda benar-benar peduli bukan hanya waktu rata - rata yang diperlukan untuk menjalankan fungsi Anda, tetapi waktu yang diperlukan untuk kesenangan satu orang, gagasan melepaskan tumpukan di sembarang tempat sangat tidak diinginkan.

Contoh kehidupan nyata bagi saya: perpustakaan matematika. Jika perpustakaan matematika Anda memiliki Vectorkelas yang mendukung mendapatkan vektor satuan dalam arah yang sama, Anda harus dapat membagi dengan besarnya. Jika besarnya 0, Anda memiliki situasi bagi dengan nol. Dalam pengembangan Anda ingin menangkap ini . Anda benar-benar tidak ingin pembagian mengejutkan dengan 0 berkeliaran. Melempar pengecualian adalah solusi yang sangat populer untuk ini. Ini hampir tidak pernah terjadi (itu benar-benar perilaku yang luar biasa), tetapi ketika itu terjadi, Anda ingin mengetahuinya.

Pada platform tertanam, Anda tidak ingin pengecualian itu. Akan lebih masuk akal untuk melakukan pemeriksaan if (this->mag() == 0) return Vector(0, 0, 0);. Sebenarnya, saya melihat ini dalam kode nyata.

Sekarang pikirkan dari perspektif bisnis. Anda dapat mencoba mengajarkan dua cara berbeda menggunakan API:

// Development version - exceptions        // Embeded version - return 0s
Vector right = forward.cross(up);          Vector right = forward.cross(up);
Vector localUp = right.cross(forward);     Vector localUp = right.cross(forward);
Vector forwardHat = forward.unit();        Vector forwardHat = forward.tryUnit();
Vector rightHat = right.unit();            Vector rightHat = right.tryUnit();
Vector localUpHat = localUp.unit()         Vector localUpHat = localUp.tryUnit();

Ini memuaskan pendapat sebagian besar jawaban di sini, tetapi dari perspektif perusahaan ini tidak diinginkan. Pengembang yang disematkan harus mempelajarinya gaya pengkodean, dan pengembang pengembangan harus mempelajari yang lain. Ini bisa agak sial, dan memaksa orang ke satu cara berpikir. Berpotensi lebih buruk: bagaimana Anda membuktikan bahwa versi yang disematkan tidak menyertakan pengecualian melemparkan kode? Versi melempar dapat dengan mudah berbaur, bersembunyi di suatu tempat dalam kode Anda sampai Papan Tinjauan Kegagalan yang mahal menemukannya.

Sebaliknya, jika Anda memiliki bendera yang mengaktifkan atau menonaktifkan penanganan pengecualian, kedua grup dapat mempelajari gaya pengkodean yang sama persis. Bahkan, dalam banyak kasus, Anda bahkan dapat menggunakan kode satu grup dalam proyek grup lain. Dalam kasus menggunakan kode ini unit(), jika Anda benar-benar peduli tentang apa yang terjadi dalam kasus dibagi dengan 0, Anda harus menulis tes sendiri. Jadi, jika Anda memindahkannya ke sistem tertanam, di mana Anda mendapatkan hasil yang buruk, perilaku itu "waras." Sekarang, dari perspektif bisnis, saya melatih coders saya sekali, dan mereka menggunakan API yang sama dan gaya yang sama di semua bagian bisnis saya.

Dalam sebagian besar kasus, Anda ingin mengikuti saran orang lain: gunakan idiom like tryGetUnit()atau mirip untuk fungsi yang tidak melempar pengecualian, dan sebaliknya mengembalikan nilai sentinel seperti null. Jika menurut Anda pengguna mungkin ingin menggunakan kode penanganan perkecualian dan kode penanganan nonkecualian berdampingan dalam satu program, tetap dengan tryGetUnit()notasi. Namun, ada kasus sudut di mana realitas bisnis dapat membuatnya lebih baik menggunakan bendera. Jika Anda menemukan diri Anda dalam sudut itu, jangan takut untuk melemparkan "aturan" di pinggir jalan. Untuk itulah aturannya!

Cort Ammon - Reinstate Monica
sumber