Hata atıp atmamamız gerektiğini belirten bir bayrak olması


64

Kısa süre önce, bazı eski geliştiricilerin bulunduğu bir yerde çalışmaya başladım (yaklaşık 50+ yaşında). Sistemin çökemediği havacılık ile ilgili kritik uygulamalar üzerinde çalıştılar. Sonuç olarak, eski programcı bu şekilde kodlama eğilimindedir.

Bir istisna atılıp atılmayacağını göstermek için nesnelere bir boolean yerleştirme eğilimindedir.

Örnek

public class AreaCalculator
{
    AreaCalculator(bool shouldThrowExceptions) { ... }
    CalculateArea(int x, int y)
    {
        if(x < 0 || y < 0)
        {
            if(shouldThrowExceptions) 
                throwException;
            else
                return 0;
        }
    }
}

(Projemizde yöntem başarısız olabilir, çünkü şu anda bulunamayan bir ağ cihazı kullanmaya çalışıyoruz. Alan örneği, istisna bayrağının sadece bir örneğidir)

Bana göre bu bir kod kokusu gibi görünüyor. Ünite testleri yazmak, her seferinde istisna bayrağını test etmeniz gerektiğinden biraz daha karmaşık hale gelir. Ayrıca, bir şeyler ters giderse, hemen bilmek istemez misiniz? Nasıl devam edeceğini belirlemek, arayanın sorumluluğunda mı olmalı?

Mantığı / mantığı, programımızın 1 şey yapması gerektiği, kullanıcıya verileri göstermesi gerektiğidir. Bunu yapmamıza engel olmayan herhangi bir istisna dikkate alınmamalıdır. Görmezden gelinmemeleri gerektiği, ancak kabarması ve uygun kişi tarafından ele alınması gerektiği ve bunun için bayraklarla uğraşmamaları gerektiğine katılıyorum.

Bu istisnaları ele almak için iyi bir yol mu?

Düzenleme : Sadece tasarım kararı hakkında daha fazla bağlam vermek için, bu bileşen başarısız olursa, programın hala çalışabileceğini ve asıl görevini yapabileceğinden şüpheliyim. Böylece bir istisna atmak istemeyiz (ve bunu yapmaz mıyız?) Ve kullanıcı iyi çalıştığı zaman programı kaldırsın

Düzenleme 2 : Daha da fazla bağlam vermek için, bizim durumumuzda bir ağ kartını sıfırlamak için yöntem denir. Sorun, ağ kartının bağlantısı kesildiğinde ve yeniden bağlandığında, farklı bir ip adresi atandığında ortaya çıkar, bu nedenle Sıfırlama bir istisna atar çünkü donanımı eski ip ile sıfırlamaya çalışıyoruz.


22
c # bu Try-Parse bildiri için bir sözleşmeye sahip. Daha fazla bilgi: docs.microsoft.com/en-us/dotnet/standard/design-guidelines/… Bayrak bu desenle eşleşmiyor.
Peter,

18
Bu temelde bir kontrol parametresidir ve dahili yöntemlerin çalışma şeklini değiştirir. Senaryodan bağımsız olarak bu kötüdür. martinfowler.com/bliki/FlagArgument.html , softwareengineering.stackexchange.com/questions/147977/... , medium.com/@amlcurran/...
bic

1
Peter'ın Try-Parse yorumuna ek olarak, Vexing istisnaları hakkında güzel bir makale: blogs.msdn.microsoft.com/ericlippert/2008/09/10/…
Linaith

2
"Dolayısıyla, bir istisna atmak istemeyiz (ve bununla başa çıkmaz mıyız?) Ve kullanıcının çalışması iyi olduğunda programı indirmesini istemek" - istisnaları tam olarak yakalayabileceğinizi biliyor musunuz?
user253751

1
Bunun başka bir yerde daha önce ele alındığından eminim ancak basit Alan örneği verildiğinde, bu negatif sayıların nereden geleceğini ve bu hata koşulunu başka bir yerde yapıp yapamayacağınızı merak etmeye meyilliyim (örneğin, örneğin, uzunluk ve genişlik içeren dosyayı okuyorduk); Ancak, "şu anda bulunamayan bir ağ cihazı kullanmaya çalışıyoruz." nokta tamamen farklı bir cevabı hak edebilir, bu üçüncü taraf bir API mı yoksa TCP / UDP gibi bir endüstri standardı mı?
jrh

Yanıtlar:


74

Bu yaklaşımla ilgili sorun, istisnalar asla atılmamasına rağmen (ve dolayısıyla uygulama, yakalanmayan istisnalar nedeniyle hiçbir zaman çökmez), geri gönderilen sonuçların mutlaka doğru olmaması ve kullanıcı verilerde bir sorun olduğunu asla bilemeyebilir (veya Bu problem nedir ve nasıl düzeltilir?

Sonuçların doğru ve anlamlı olması için çağrı yönteminin özel numaralar için sonucu kontrol etmesi gerekir - yani yöntemi uygularken ortaya çıkan sorunları belirtmek için kullanılan belirli dönüş değerleri. Pozitif-kesin miktarlar (benzeri alan) için geri gönderilen negatif (veya sıfır) sayılar, eski kodlarda bunun en önemli örneğidir. Çağıran yöntem bu özel numaraları kontrol etmeyi bilmiyorsa (veya unutuyorsa), işleme bir hata yapmadan devam edebilir. Veriler daha sonra kullanıcının yanlış olduğunu bildiği 0 alanını gösteren kullanıcıya gösterilir, ancak neyin yanlış gittiğini, nerede veya niçin olduğuna dair herhangi bir gösterge yoktur. Daha sonra diğer değerlerden herhangi birinin yanlış olup olmadığını merak ediyorlar ...

İstisna atılırsa, işlem durur, hata (ideal olarak) kaydedilir ve kullanıcıya bir şekilde bildirilir. Kullanıcı daha sonra yanlış olanı düzeltebilir ve tekrar deneyebilir. Uygun istisnaların ele alınması (ve test edilmesi!) Kritik uygulamaların çökmemesini veya geçersiz bir durumda kapanmasını sağlayacaktır.


1
@Quirk Chen'in Tek Sorumluluk Prensibi'ni sadece 3 veya 4 satırda ihlal etmesi çok etkileyici. Asıl sorun bu. Ayrıca, konuştuğu problem (programcı her satırdaki hataların sonuçlarını düşünememek) her zaman kontrol edilmeyen istisnalar ile bir olasılık ve sadece bazen kontrol edilen istisnalar ile bir olasılıktır. Sanırım kontrol edilen istisnalar dışında şimdiye kadar yaptığım tüm tartışmaları gördüm ve bunların hiçbiri geçerli değil.
TKK

@TKK şahsen, .NET'te kontrol edilen istisnaları gerçekten sevdiğim yerlere rastladığım bazı durumlar var. Bir API'nin, atılan istisnalar dışında hangi belgelerin doğru olduğunu doğrulayabilmesini sağlayacak bazı yüksek kaliteli statik analiz araçları olsaydı, özellikle de yerel kaynaklara erişirken büyük olasılıkla imkansız olurdu.
jrh

1
@ Evet, TypeScript'in JS'ye nasıl güvenliğini sağladığına benzer bir şey, .NET'te istisnai bir güvenlik istisnası getirmişse iyi olurdu.
TKK

47

Bu istisnaları ele almak için iyi bir yol mu?

Hayır, bence bu oldukça kötü bir uygulama. Bir istisna atmak - değer döndürmek API'de temel bir değişiklik yapmak, yöntemin imzasını değiştirmek ve yöntemin arabirim perspektifinden oldukça farklı davranmasını sağlamaktır.

Genel olarak, sınıfları ve API'lerini tasarlarken, bunu göz önünde bulundurmalıyız.

  1. Aynı programda aynı anda dolaşan farklı konfigürasyonlara sahip sınıfın birden fazla örneği olabilir ve

  2. Bağımlılık enjeksiyonuna ve herhangi bir sayıda diğer programlama uygulamasına bağlı olarak, tüketen bir müşteri nesneleri yaratabilir ve bunları başka bir başka birine kullanabilir - bu nedenle çoğu zaman nesne yaratıcıları ve nesne kullanıcıları arasında bir ayrım yaparız.

Şimdi, arayan kişinin eline verilen bir örneği kullanmak için ne yapması gerektiğini düşünün, örneğin hesaplama yöntemini çağırmak için: Arayanın hem alanın sıfır olup olmadığını hem de istisnaları yakalamak için kontrol etmesi gerekir - ah! Testle ilgili düşünceler sadece sınıfın kendisine değil, aynı zamanda arayanların hata işlemesine de ...

Tüketiciyi tüketen müşteri için her zaman işleri mümkün olduğunca kolaylaştırmalıyız; yapıcıdaki bir örnek yönteminin API'sini değiştiren bu boolean yapılandırma, tüketici müşteri programcısının (belki siz veya iş arkadaşınızın) başarının çukuruna düşmesinin tam tersidir.

Her iki API'yi de sunmak için, iki farklı sınıf sağlamak için çok daha iyi ve daha normalsiniz - biri her zaman hataya sebep olur ve biri her zaman hatayla 0 döndürür, ya da tek bir sınıfla iki farklı yöntem sunar. Bu şekilde alıcı müşteri, hataları nasıl kontrol edeceğinizi ve nasıl kontrol edeceğinizi kolayca bilir.

İki farklı sınıf veya iki farklı metot kullanarak, IDE'leri metot kullanıcıları ve refactor özellikleri, vb. Kullanabilirsiniz. İki kullanım durumu artık kapalı olmadığından çok daha kolay. Kod okuma, yazma, bakım, gözden geçirme ve test işlemleri de daha kolaydır.


Başka bir kayda göre, şahsen gerçek arayanların sadece sabit bir şekilde geçtiği boole yapılandırma parametrelerini almamamız gerektiğini düşünüyorum . Bu konfigürasyon parametreleştirmesi, gerçek bir fayda sağlamak için iki ayrı kullanım senaryosunu birleştirir.

Kod tabanınıza bir göz atın ve yapıcıdaki boole yapılandırma parametresi için bir değişken (veya sabit olmayan bir ifade) kullanılıp kullanılmadığına bakın. Şüpheliyim.


Diğer bir konu da, alanı hesaplamanın neden başarısız olabileceğini sormak. En iyisi, hesaplama yapılamıyorsa, kurucuya atmak olabilir. Bununla birlikte, nesne başlatılana kadar hesaplamanın yapılıp yapılmadığını bilmiyorsanız, o zaman bu durumları ayırt etmek için farklı sınıflar kullanmayı düşünebilirsiniz (alanı hesaplamaya hazır değil, alanı hesaplamaya hazır değil).

Başarısızlık durumunuzun uzaklaşmaya yönelik olduğunu okudum, bu yüzden geçerli olmayabilir; Düşünce için sadece biraz yiyecek.


Nasıl devam edeceğini belirlemek, arayanın sorumluluğunda mı olmalı?

Evet katılıyorum. Callee'nin 0 alanının hata koşulları altında doğru cevap olduğuna karar vermesi için erken görünüyor (özellikle 0 geçerli bir alan olduğundan, uygulamanız için geçerli olmayabilir, ancak hata ile gerçek 0 arasındaki farkı söylemenin bir yolu yoktur).


Hiç bir istisna olup olmadığını kontrol etmenize gerek yok çünkü yöntemi çağırmadan önce argümanları kontrol etmeniz gerekiyor . Sonucu sıfıra karşı kontrol etmek, 0, 0 yasal argümanları ile yasadışı olumsuz olanları birbirinden ayırmaz. API gerçekten korkunç bir IMHO.
BlackJack

Ek K MS, C99 ve C ++ iostreams için bastırıyor, bir kancanın veya bayrağın başarısızlığa verilen tepkiyi kökten değiştirdiği API örnekleridir.
Deduplicator

37

Sistemin çökemediği havacılık ile ilgili kritik uygulamalar üzerinde çalıştılar. Sonuç olarak ...

Bu, bana bu tasarımın arkasındaki motivasyon izlenimini veren ilginç bir giriştir; "sistem çökebildiği için" o zaman bazı bağlamlara istisnalar atmamaktır . Fakat eğer sistem "bir istisna nedeniyle aşağı inebilir" ise, bu açık bir göstergedir.

  • İstisnalar en azından ne de katı bir şekilde doğru bir şekilde ele alınmaz.

Bu yüzden, eğer programı kullanan program AreaCalculatorbuggy ise, iş arkadaşınız programın "erken çökmesine" izin vermemeyi, ancak bazı yanlış değerler döndürmeyi tercih eder (kimsenin fark etmesini ummamak veya hiç kimsenin onunla önemli bir şey yapmasını ummamak). Bu aslında bir hatayı gizliyor ve benim tecrübeme göre er ya da geç, kök nedenini bulmanın zorlaştığı takip hatalarına yol açacaktır.

IMHO, hiçbir koşulda çökmeyen bir program yazıyor ancak yanlış veri gösteriyor veya hesaplama sonuçları genellikle programın çökmesine izin vermekten daha iyi değildir. Tek doğru yaklaşım, arayan kişiye hatayı fark etme, onunla başa çıkma, kullanıcının yanlış davranış hakkında bilgi sahibi olup olmadığına ve herhangi bir işleme devam etmesinin güvenli olup olmadığına veya daha güvenli olup olmadığına karar vermesine izin vermektir. programı tamamen durdurmak için. Bu nedenle, aşağıdakilerden birini tavsiye ederim:

  • Bir fonksiyonun bir istisna atabileceği gerçeğini gözden kaçırmak zorlaştırır. Belgeler ve kodlama standartları burada arkadaşınızdır ve düzenli kod incelemeleri, bileşenlerin doğru kullanımını ve uygun istisnaların kullanımını desteklemelidir.

  • Ekibi "kara kutu" bileşenlerini kullanırken istisnalar beklemek ve bunlarla başa çıkmak için eğitin ve programın küresel davranışını göz önünde bulundurun.

  • Bazı nedenlerden dolayı istisna işlemeyi uygun şekilde kullanmak için çağıran kodu (veya yazan devs) alamayacağınızı düşünüyorsanız, son çare olarak, açık hata çıktısı değişkenleri olan bir API tasarlayabilirsiniz ve

    CalculateArea(int x, int y, out ErrorCode err)

    bu yüzden arayan kişinin işlevinin başarısız olabileceğini göz ardı etmesi gerçekten zorlaşıyor. Ancak bu IMHO C # oldukça çirkin; istisnaların olmadığı C'den eski bir savunma programlama tekniğidir ve normalde bugünlerde çalışmak gerekli değildir.


3
"hiçbir koşulda çökmeyen bir program yazmak, ancak yanlış veri veya hesaplama sonuçlarını göstermek, genellikle programın çökmesine izin vermekten daha iyi olmaz". Genel olarak tamamen katılıyorum, ancak havacılıkta muhtemelen uçağı seçmeyi tercih edebileceğimi hayal edebiliyorum. Uçak bilgisayarını kapatmaya kıyasla hala yanlış değerler gösteren enstrümanlar ile devam ediyorum. Daha az kritik olan tüm uygulamalar için hataları gizlememek kesinlikle daha iyidir.
Trilarion

18
@Trilarion: Uçuş bilgisayarı için bir program uygun istisna işlemesi içermiyorsa, bileşenleri istisnalar atmadan "düzeltmek" çok yanlış yönlendirilmiş bir yaklaşımdır. Program çökerse, devralabilecek yedek bir yedekleme sistemi olmalı. Eğer program çökmezse ve yanlış bir yükseklik gösteriyorsa, örneğin, pilotlar uçak bir sonraki dağa giderken “her şeyin yolunda” olduğunu düşünebilirler.
Doktor Brown

7
@Trilarion: eğer uçuş bilgisayarı yanlış bir yükseklik gösteriyorsa ve uçak bundan dolayı çarpışacaksa, size de yardım etmeyecektir (özellikle yedekleme sistemi orada olduğunda ve devralınması gerektiğinden haberdar edilmezse). Uçak bilgisayarları için yedekleme sistemleri yeni bir fikir değil, "uçak bilgisayarı yedekleme sistemleri" için google, dünyanın her yerindeki mühendislerin her zaman gereksiz yaşam sistemlerini gerçek yaşamı eleştiren herhangi bir sisteme yerleştirdiklerinden (ve sadece kaybetmediklerinden dolayı) eminim. sigorta).
Doktor Brown

4
Bu. Programın çökmesini göze alamazsanız, yanlış cevaplar vermesini sessizce veremezsiniz. Doğru cevap, her durumda uygun istisna koşullarına sahip olmaktır . Bir web sitesi için, bu beklenmeyen hataları 500'e dönüştüren global bir işleyici anlamına gelir. Ayrıca, bir öğe başarısız olursa devam etmek için işleme ihtiyacınız varsa, bir döngü içinde try/ catchiçinde olması gibi daha özel durumlar için ek işleyiciler de olabilir .
jpmc26

2
Yanlış sonuç almak her zaman en kötü başarısızlıktır; Bu bana optimizasyon kuralını hatırlatıyor: "optimize etmeden önce doğru yap, çünkü yanlış cevabı daha hızlı almak hiç kimseye fayda sağlamaz."
Toby Speight

13

Ünite testleri yazmak, her seferinde istisna bayrağını test etmeniz gerektiğinden biraz daha karmaşık hale gelir.

N parametresi ile herhangi bir fonksiyonun n-1 parametresi ile bir testten daha zor olması gerekir . Bunu saçma duruma doğru uzatın ve argüman, fonksiyonların hiçbir şekilde parametreye sahip olmaması gerektiği, çünkü bunların test edilmesini en kolay hale getirir.

Test edilmesi kolay bir kod yazmak harika bir fikir olsa da, test basitliğini kod yazması gereken kişilere yararlı olacak şekilde kod yazmanın üstüne koymak korkunç bir fikir. Sorudaki örnekte bir istisna atılıp atılmayacağını belirleyen bir anahtar varsa, bu davranışı istemek isteyen arayanların işleve ekleyerek değer vermesi mümkündür. Karmaşık ve çok karmaşık arasındaki çizginin bir yargı çağrısı olduğu; Sana söylemeye çalışan biri, her durumda geçerli olan parlak bir çizginin olduğunu söylemeye çalışır.

Ayrıca, bir şeyler ters giderse, hemen bilmek istemez misiniz?

Bu yanlış tanımına bağlı. Sorudaki örnek, "sıfırdan küçük bir boyut verilmiş ve shouldThrowExceptionsgerçek " şeklinde yanlış olarak tanımlamaktadır . shouldThrowExceptionsAnahtar farklı davranışlara neden olduğu için sıfırdan düşükse boyut verilmesi yanlış olduğunda yanlış değildir . Bu, oldukça basit, istisnai bir durum değil.

Buradaki asıl sorun, anahtarın kötü bir şekilde adlandırılmış olmasıdır, çünkü fonksiyonun ne yaptığını tanımlayıcı değildir. Daha iyi bir isim verilmiş olsaydı treatInvalidDimensionsAsZero, bu soruyu sorar mıydınız?

Nasıl devam edeceğini belirlemek, arayanın sorumluluğunda mı olmalı?

Arayan yok devam etmek için belirler. Bu durumda, ayarlayarak veya temizleyerek vaktinden önce yapar shouldThrowExceptionsve işlev durumuna göre davranır.

Örnek patolojik olarak basit bir örnektir çünkü tek bir hesaplama yapar ve geri döner. Sayı listesinin kareköklerinin toplamını hesaplamak gibi biraz daha karmaşık yaparsanız, istisnalar atmak, arayanlara çözemedikleri sorunları verebilir. Eğer bir listeye [5, 6, -1, 8, 12]girersem ve fonksiyonun üstüne bir istisna -1atarsam, fonksiyona devam etmesini söyleyemem çünkü zaten durdurulmuş ve toplamı atmış olacak. Liste çok büyük bir veri setiyse, işlevi çağırmadan önce herhangi bir negatif numara içermeyen bir kopya oluşturmak pratik olmayabilir, bu nedenle, önceden "geçersiz say" şeklinde görmezden gelmek yerine geçersiz numaralara nasıl davranılması gerektiğini söylemek zorundayım. "Geçiş yap veya belki de bu kararı vermek için çağrılan bir lambda sağla.

Mantığı / mantığı, programımızın 1 şey yapması gerektiği, kullanıcıya verileri göstermesi gerektiğidir. Bunu yapmamıza engel olmayan herhangi bir istisna dikkate alınmamalıdır. Görmezden gelinmemeleri gerektiği, ancak kabarması ve uygun kişi tarafından ele alınması gerektiği ve bunun için bayraklarla uğraşmamaları gerektiğine katılıyorum.

Yine, tek beden uyan herkese uygun bir çözüm yoktur. Örnekte, işlev, büyük olasılıkla, olumsuz boyutlarla nasıl başa çıkılacağını yazan bir özelliğe yazılmıştır. Yapmak istediğiniz son şey, "normalde burada bir istisna atılacak, ancak arayan rahatsız etmemek" diyen mesajlarla doldurarak günlüklerinizin sinyal-gürültü oranını düşürmektir.

Ve bu çok eski programcılardan biri olarak, sizden lütfen nazikçe bahçemden ayrılmanızı rica ediyorum. ;-)


Adlandırma ve niyetin son derece önemli olduğunu kabul ediyorum ve bu durumda uygun parametre adı tabloları gerçekten döndürebiliyor, yani +1, ancak 1. our program needs to do 1 thing, show data to user. Any other exception that doesn't stop us from doing so should be ignoredzihniyet kullanıcının yanlış verilere dayanarak karar vermesine yol açabilir (çünkü programın yapması gerektiği için 1 şey - kullanıcının bilinçli kararlar vermesine yardımcı olmak için) 2. gibi benzer durumlar bool ExecuteJob(bool throwOnError = false)genellikle son derece hataya açıktır ve sadece onu okuyarak akla gelmesi zor olan kodlara yol açar.
Eugene Podskal

@EugenePodskal Bence varsayım "verileri göster" anlamına gelir "doğru verileri göster". Anketör, bitmiş ürünün işe yaramadığını söylemez, sadece "yanlış" yazılabilir. İkinci noktada bazı zor veriler görmem gerekiyor. Şu anki projemde bir fırlatma / fırlatma düğmesi olmayan ve herhangi bir diğer işlevden daha fazla nedene gerek duymayan çok fazla kullanılan işlev var.
Blrfl

İyi cevap, bu mantığın OP'lerden çok daha geniş bir koşul için geçerli olduğunu düşünüyorum. BTW, cpp'in yeni özelliklerinde tam olarak bu nedenlerden dolayı atış / atış yok sürümüne sahiptir. Bazı küçük farklılıklar olduğunu biliyorum ama ...
drjpizzle

8

Güvenlik açısından kritik ve 'normal' kod, 'iyi uygulamaların' neye benzediğine dair çok farklı fikirlere yol açabilir. Çok fazla örtüşme var - bazı şeyler riskli ve her ikisinde de kaçınılması gereken - ancak yine de önemli farklılıklar var. Tepkili olması garanti edilmek için bir gereksinim eklerseniz, bu sapmalar oldukça büyük olur.

Bunlar genellikle beklediğiniz şeyler ile ilgilidir:

  • Git için yanlış cevap şunlara göre çok kötü olabilir: uzun süren / iptal / askıda kalması veya hatta çökmesi (ki bu, yanlışlıkla giriş kodunu değiştirmeye bağlı olarak etkili olmayan konulardır).

    Ancak: Kuvveti hesaplaması durduran ve hava hızı hesaplamasının önlenmesi belki kabul edilemez hale gelen bir gösterge paneli için.

Bazıları daha az açıktır:

  • Eğer bir test varsa çok , (doğru cevaplar gibi) birinci dereceden sonuçları bir endişe göreceli olarak değil büyük. Testinin bunu çözeceğini biliyorsun. Ancak eğer gizli durum ya da kontrol akışı olsaydı, bunun çok daha ince bir şeyin nedeni olmayacağını bilemezsiniz. Bu test ile ekarte etmek zordur.

  • Gösterilebilir bir şekilde güvenli olmak nispeten önemlidir. Pek çok müşteri, satın aldıkları kaynağın güvenli olup olmamasına dair nedenlerle oturup göremez. Öte yandan havacılık pazarındaysanız ...

Bu sizin örneğiniz için nasıl geçerlidir?

Bilmiyorum. Güvenlik kritik kodunda “Hiç kimsenin üretim koduna atılmaması” gibi ana kurallara sahip olabilecek daha genel durumlarda oldukça aptalca olabilecek bazı düşünce süreçleri vardır.

Bazıları gömülü olmakla, bazıları da güvenlikle ve belki diğerleri ile ilgilidir. Bazıları iyidir (sıkı performans / bellek sınırları gerekiyordu) bazıları kötüdür (istisnaları tam anlamıyla ele almıyoruz, bu yüzden risk almamak en iyisidir). Çoğu zaman neden yaptıklarını bilmek bile, soruyu gerçekten cevaplamayacak. Örneğin, kodu daha kolay denetlemenin kolay olması ile daha iyi yapmaksa, daha iyi bir uygulama mıdır? Gerçekten söyleyemezsin. Onlar farklı hayvanlardır ve farklı muamele görmeleri gerekir.

Bütün bunlar bana biraz şüpheli görünüyor dedi ama :

Güvenlik açısından kritik yazılım ve yazılım tasarım kararları, muhtemelen yazılım mühendisliği yığın değişiminde yabancı kişiler tarafından alınmamalıdır. Kötü bir sistemin parçası olsa bile, bunu yapmak için iyi bir neden olabilir. Bunların hiçbirini “düşünce için yemek” dışında okumayın.


7

Bazen bir istisna atmak en iyi yöntem değildir. Yığın gevşemesinden dolayı değil, bazen de bir istisna yakalamak, özellikle de dil veya arayüz dikişlerinde sorunlu olduğu için.

Bununla başa çıkmanın iyi bir yolu, zenginleştirilmiş bir veri türü döndürmektir. Bu veri türü, tüm mutlu yolları ve tüm mutsuz yolları tanımlamak için yeterli duruma sahiptir. Mesele şu ki, eğer bu fonksiyonla etkileşime girerseniz (üye / global / başka türlü) sonucu ele almak zorunda kalacaksınız.

Bu zenginleştirilmiş veri tipinin söylenmesi eylemi zorlamamalı. Bölgenizdeki örnekte olduğu gibi bir şey hayal edin var area_calc = new AreaCalculator(); var volume = area_calc.CalculateArea(x, y) * z;. Yararlı görünüyor volumederinlik ile çarpılan alanı içermelidir - bu bir küp, silindir vb. Olabilir ...

Peki ya area_calc servisi kapalıysa? Sonra area_calc .CalculateArea(x, y)bir hata içeren zengin bir veri türü döndürdü. Bunu çarpmak yasal mı z? Bu iyi bir soru. Kullanıcıları hemen kontrolü ele almaya zorlayabilirsiniz. Ancak bu, mantığı hata işleme ile parçalamaktadır.

var area_calc = new AreaCalculator();
var area_result = area_calc.CalculateArea(x, y);
if (area_result.bad())
{
    //handle unhappy path
}
var volume = area_result.value() * z;

vs

var area_calc = new AreaCalculator();
var volume = area_calc.CalculateArea(x, y) * z;
if (volume.bad())
{
    //handle unhappy path
}

Temelde mantık iki satıra yayılmış ve ilk durumda hata işlemeye bölünmüş, ikinci durumda ise ilgili tüm mantığı bir satırda izlemiş ve ardından hata işlemeyi takip etmişsiniz.

Bu ikinci durumda volume, zengin bir veri türüdür. Bu sadece bir sayı değil. Bu, depolamayı büyütür ve volumeyine de bir hata durumu için araştırılması gerekir. Ek olarak volume, kullanıcı hatayı işlemeyi seçmeden önce diğer hesaplamaları da besleyebilir ve bu sayede birbirinden farklı yerlerde tezahür edebilir. Bu durumun özelliklerine bağlı olarak bu iyi veya kötü olabilir.

Alternatif volumeolarak sadece düz bir veri türü olabilir - sadece bir sayı, fakat sonra hata durumuna ne olur? Değer, mutlu bir durumda ise, dolaylı olarak dönüştürülebilir. Mutsuz bir durumda olması durumunda, varsayılan / hata değeri döndürülebilir (alan 0 veya -1 için makul görünebilir). Alternatif olarak, arayüz / dil sınırının bu tarafına bir istisna atabilir.

... foo() {
   var area_calc = new AreaCalculator();
   return area_calc.CalculateArea(x, y) * z;
}
var volume = foo();
if (volume <= 0)
{
    //handle error
}

vs.

... foo() {
   var area_calc = new AreaCalculator();
   return area_calc.CalculateArea(x, y) * z;
}

try { var volume = foo(); }
catch(...)
{
    //handle error
}

Kötü veya büyük olasılıkla kötü bir değer vererek, verileri doğrulamak için kullanıcıya çok fazla yol açar. Bu bir hata kaynağıdır, çünkü derleyici ile ilgili olarak, geri dönüş değeri meşru bir tamsayıdır. Bir şey kontrol edilmezse, işler ters gittiğinde onu keşfedeceksiniz. İkinci durum, mutsuz yolları işleyebilmek için istisnalara izin verirken her iki dünyanın da en iyisini karıştırırken, mutlu yollar normal işlemeyi takip eder. Ne yazık ki kullanıcıyı istisnaları akıllıca ele almaya zorlar, ki bu da zordur.

Sadece mutsuz bir yolun açıklığa kavuşturulması, iş mantığının (istisnaların etki alanı) bilinmeyen bir durumdur, doğrulanamayan işlerin yolu, iş kurallarına (kuralların etki alanı) göre nasıl idare edileceğini bildiğiniz için mutlu bir yoldur.

Nihai çözüm, tüm senaryolara izin veren bir çözüm olacaktır (aklın içinde).

  • Kullanıcı kötü bir durumu sorgulayabilmeli ve derhal halledebilmelidir.
  • Kullanıcı, mutlu yol izlenmiş gibi zenginleştirilmiş tip üzerinde çalışabilmeli ve hata ayrıntılarını yaymalıdır.
  • Kullanıcı, mutsuz yollar için bir istisna oluşturarak, döküm yoluyla (makul olduğu kadar açık / açık) mutlu yol değerini çıkartabilir.
  • Kullanıcı mutlu yol değerini çıkarabilmeli veya varsayılanı kullanabilmelidir (verilen veya verilmeyen)

Gibi bir şey:

Rich::value_type value_or_default(Rich&, Rich::value_type default_value = ...);
bool bad(Rich&);
...unhappy path report... bad_state(Rich&);
Rich& assert_not_bad(Rich&);
class Rich
{
public:
   typedef ... value_type;

   operator value_type() { assert_not_bad(*this); return ...value...; }
   operator X(...) { if (bad(*this)) return ...propagate badness to new value...; /*operate and generate new value*/; }
}

//check
if (bad(x))
{
    var report = bad_state(x);
    //handle error
}

//rethrow
assert_not_bad(x);
var result = (assert_not_bad(x) + 23) / 45;

//propogate
var y = x * 23;

//implicit throw
Rich::value_type val = x;
var val = ((Rich::value_type)x) + 34;
var val2 = static_cast<Rich::value_type>(x) % 3;

//default value
var defaulted = value_or_default(x);
var defaulted_to = value_or_default(x, 55);

@TobySpeight Fuarı yeterince, bu şeyler bağlama duyarlıdır ve kapsamları geniş bir alana sahiptir.
Kain0_0

Bence buradaki problem 'assert_not_bad' bloğu. Bunların çözülmeye çalışılan orijinal kodla aynı yerde olacağını düşünüyorum. Bunların test edilmesinde fark edilmeleri gerekir, ancak eğer gerçekten haklılarsa, gerçek bir uçakta üretilmeden önce soyulmaları gerekir. Aksi halde bazı harika noktalar.
drjpizzle

@drjpizzle Test için bir koruma eklemek için yeterince önemliyse, üretimde çalışırken korumayı yerinde bırakmak için yeterince önemli olduğunu savunuyorum. Muhafızların varlığı kuşku uyandırıyor. Test sırasında kodun korunmasına yetecek kadar şüpheniz varsa, teknik bir nedenden dolayı şüphelisiniz. yani durum gerçekçi olarak gerçekleşebilir / gerçekleşir. Testlerin yapılması, koşulda üretimde asla ulaşılamayacağını kanıtlamaz. Bu, bir şekilde bir yerde ele alınması gereken, meydana gelebilecek bilinen bir durumun olduğu anlamına gelir. Bence bunun nasıl ele alındığı, sorun.
Kain0_0

3

C ++ açısından cevap vereceğim. Bütün temel kavramların C # 'ya transfer edilebildiğinden eminim.

Tercih ettiğiniz stil "her zaman istisnalar atıyor" gibi geliyor:

int CalculateArea(int x, int y) {
    if (x < 0 || y < 0) {
        throw Exception("negative side lengths");
    }
    return x * y;
}

Bu istisna işleme ağır olduğu için C ++ kodu için bir sorun olabilir - başarısızlık durumunun yavaş çalışmasını sağlar ve başarısızlık durumunun bellek ayırmasını sağlar (bu bazen kullanılabilir bile olmaz) ve genellikle işleri daha az öngörülebilir yapar. EH'nin ağırlığının, insanların “Kontrol akışı için istisnalar kullanma” gibi şeyler söylediğini duymasının bir nedenidir.

Bu yüzden bazı kütüphaneler (örneğin <filesystem>) C ++ 'ın "çift API" dediği şeyi veya hangi C #' nın Try-Parsedesen dediğini kullanır ( ipucu için teşekkürler Peter !)

int CalculateArea(int x, int y) {
    if (x < 0 || y < 0) {
        throw Exception("negative side lengths");
    }
    return x * y;
}

bool TryCalculateArea(int x, int y, int& result) {
    if (x < 0 || y < 0) {
        return false;
    }
    result = x * y;
    return true;
}

int a1 = CalculateArea(x, y);
int a2;
if (TryCalculateArea(x, y, a2)) {
    // use a2
}

Sorunu hemen "çift API" lerle görebilirsiniz: çok sayıda kod çoğaltması, hangi API'nin "doğru" olduğu konusunda kullanıcılara rehberlik edilmez ve kullanıcı, yararlı hata mesajları ( CalculateArea) ve speed ( TryCalculateArea) çünkü daha hızlı sürüm bizim faydalı "negative side lengths"istisnamızı alır ve onu işe yaramaz hale getirir false- “bir şeyler ters gitti, bana ne veya nerede olduğunu sorma.” (Bazı ikili API'leri gibi, daha etkileyici hata türünü kullanın int errnoC ++ 'ın ya std::error_codeama yine de size değil nerede hata oluştu - sadece o did yerde meydana gelir.)

Kodunuzun nasıl davranması gerektiğine karar veremiyorsanız, kararı her zaman arayan kişiye atabilirsiniz!

template<class F>
int CalculateArea(int x, int y, F errorCallback) {
    if (x < 0 || y < 0) {
        return errorCallback(x, y, "negative side lengths");
    }
    return x * y;
}

int a1 = CalculateArea(x, y, [](auto...) { return 0; });
int a2 = CalculateArea(x, y, [](int, int, auto msg) { throw Exception(msg); });
int a3 = CalculateArea(x, y, [](int, int, auto) { return x * y; });

Bu aslında iş arkadaşınızın yaptığı şeydir; "hata işleyicisini" global bir değişkene dönüştürmesi dışında:

std::function<int(const char *)> g_errorCallback;

int CalculateArea(int x, int y) {
    if (x < 0 || y < 0) {
        return g_errorCallback("negative side lengths");
    }
    return x * y;
}

g_errorCallback = [](auto) { return 0; };
int a1 = CalculateArea(x, y);
g_errorCallback = [](const char *msg) { throw Exception(msg); };
int a2 = CalculateArea(x, y);

Önemli parametreler Hareketli açık işlev parametreleri içine küresel devlet hemen hemen her zaman kötü bir fikirdir. Tavsiye etmiyorum. ( Sizin durumunuzda küresel bir devlet değil, sadece örnek çapında üye devlet olduğu gerçeği , kötülüğü biraz azaltıyor, ama fazlasıyla azaltıyor.)

Ayrıca, iş arkadaşınız olası hata işleme davranışlarının sayısını gereksiz yere sınırlıyor. Herhangi bir hata işleme lambasına izin vermek yerine , sadece ikisine karar verdi:

bool g_errorViaException;

int CalculateArea(int x, int y) {
    if (x < 0 || y < 0) {
        return g_errorViaException ? throw Exception("negative side lengths") : 0;
    }
    return x * y;
}

g_errorViaException = false;
int a1 = CalculateArea(x, y);
g_errorViaException = true;
int a2 = CalculateArea(x, y);

Bu, muhtemelen bu olası stratejilerden herhangi birinin “ekşi noktası” dır. Tüm esnekliği son kullanıcıdan tam olarak iki hata işleme geri çağrılarınızdan birini kullanmaya zorlayarak aldınız ; ve ortak küresel devletin tüm sorunlarına sahipsiniz; ve hala her yerde bu şartlı şube için para ödüyorsunuz.

Son olarak, C ++ 'da (ya da şartlı derlemeli herhangi bir dilde) ortak bir çözüm, kullanıcının tüm programı için karar vermesi için global olarak, derleme zamanında karar vermesi, böylece alınmamış kod hastalığının tamamen optimize edilmesini sağlamak olacaktır:

int CalculateArea(int x, int y) {
    if (x < 0 || y < 0) {
#ifdef NEXCEPTIONS
        return 0;
#else
        throw Exception("negative side lengths");
#endif
    }
    return x * y;
}

// Now these two function calls *must* have the same behavior,
// which is a nice property for a program to have.
// Improves understandability.
//
int a1 = CalculateArea(x, y);
int a2 = CalculateArea(x, y);

Bu şekilde çalışır şeyin bir örnek assertmakro hangi koşullar önişlemci makro üzerindeki davranışını C ve C ++, NDEBUG.


Biri dönerse std::optionalgelen TryCalculateArea()bunun yerine, bir derleme zamanı-bayrağıyla tek bir işlev-şablonda ikili arabiriminin iki kesiminde uygulanmasını birleştirmeye basittir.
Deduplicator

@Deduplicator: Belki bir ile std::expected. Bununla birlikte std::optional, önerilen çözümünüzü yanlış anlamadığım sürece, söylediklerimden yine de zarar görecektir: kullanıcı, yararlı hata mesajları ve hız arasında zor bir seçim yapmalıdır, çünkü daha hızlı sürüm yararlı "negative side lengths"istisnamızı alır ve işe yaramaz hale getirir false- " bir şeyler ters gitti, bana ne veya nerede olduğunu sorma. "
Quuxplusone

Bu nedenle libc ++ <filesystem> aslında OP'nin iş arkadaşının modeline çok yakın bir şey yapıyor: std::error_code *ecAPI'nin her seviyesinden aşağıya doğru yönlendiriyor ve en altta da ahlaki eşdeğeri bulunuyor if (ec == nullptr) throw something; else *ec = some error code. (Asıl ifadı verilen bir şeye özetler ErrorHandler, ancak aynı temel fikirdir.)
Quuxplusone

Bu, genişletilmiş hata bilgilerini atmadan tutmak için bir seçenek olacaktır. Uygun olabilir veya potansiyel ek maliyete değmez.
Deduplicator

1
Bu cevabın içerdiği pek çok iyi düşünce ... Kesinlikle daha fazla oy gerektirebilir :-)
cmaster

1

Meslektaşınızın modelini nereden aldığından bahsedilmesi gerektiğini düşünüyorum.

Günümüzde, C # TryGet desenine sahiptir public bool TryThing(out result). Bu, sonucun geçerli bir değer olup olmadığını size bildirirken, sonucunuzu almanızı sağlar. (Örneğin, tüm intdeğerler geçerli sonuçlar içindir Math.sum(int, int), ancak değer taşacaksa, bu belirli sonuç çöp olabilir). Bu olsa da nispeten yeni bir kalıp.

outAnahtar kelimeden önce, bir istisna (ya pahalı ve arayanın onu yakalaması ya da tüm programı öldürmesi gerekir) atmanız, özel bir yapı (sınıftan önceki sınıf ya da jeneriklerin gerçekten bir şey olduğu gerçeği için) değeri temsil etmesi gerekiyordu. ve olası hatalar (yazılım yapmak ve yazılımları kırmak için zaman harcayan) veya varsayılan bir "hata" değeri (bir hata olmayabilir) döndürür.

Meslektaşınızın kullandığı yaklaşım, onlara yeni özellikleri test ederken / hata ayıklama sırasında istisnalar konusunda başarısız olmalarını sağlarken, çalışma zamanı güvenliği ve performansı (performans, ~ 30 yıl önce her zaman kritik bir konuydu) verirken, yalnızca varsayılan bir hata değeri döndürür. Şimdi bu, yazılımın yazıldığı kalıp ve beklenen kalıp ilerliyor, bu yüzden şimdi daha iyi yollar olsa bile, bu şekilde yapmaya devam etmek doğal. Büyük olasılıkla bu kalıp yazılımın yaşından itibaren miras kaldı ya da kolejlerinizin asla uzamadığı bir kalıp (eski alışkanlıkların kırılması zor).

Diğer cevaplar zaten bunun neden kötü bir uygulama olarak kabul edildiğini kapsar, bu yüzden TryGet desenini okumanızı tavsiye etmeyi bırakacağım (belki de bir nesnenin arayan kişiye vermesi gereken şeyleri kapsayan).


outAnahtar kelimeden önce, boolsonuç için bir işaretçi alan bir işlev, yani bir refparametre yazarsınız . Bunu 1998'de VB6'da yapabilirsiniz. outAnahtar kelime yalnızca, işlev döndüğünde parametrenin atandığı kesin derlemesini alır, hepsi bu kadardır. Yine de güzel ve kullanışlı bir kalıp.
Mathieu Guindon

@MattieuGuindon Yeay, ama GetTry henüz iyi bilinen / yerleşik bir kalıp değildi ve öyleyse bile, kullanılacağından emin değilim. Ne de olsa, Y2K’ya kadar olan adayın bir kısmı, 0-99’dan daha büyük herhangi bir şeyin depolanmasının kabul edilemez olduğuydu.
Tezra

0

Onun yaklaşımını uygulamak istediğiniz zamanlar var, ama onları "normal" durum olarak görmezdim. Hangi davada olduğunuzu belirlemenin anahtarı:

Mantığı / mantığı, programımızın 1 şey yapması gerektiği, kullanıcıya verileri göstermesi gerektiğidir. Bunu yapmamıza engel olmayan herhangi bir istisna dikkate alınmamalıdır.

Gereksinimleri kontrol et. Gereksinimleriniz gerçekte, kullanıcıya verileri göstermek üzere bir işiniz olduğunu söylüyorsa, o zaman haklıdır. Ancak deneyimlerime göre, çoğu zaman kullanıcı aynı zamanda hangi verilerin gösterildiğini de önemser. Doğru verileri istiyorlar. Bazı sistemler sadece sessizce arıza yapmak ve kullanıcının bir şeylerin yanlış gittiğini anlamasına izin vermek istiyor, ancak onları kuralın istisnası olarak görüyorum.

Bir hatadan sonra soracağım anahtar soru "Sistem, kullanıcının beklentilerinin ve yazılım değişmezlerinin geçerli olduğu bir durumda mı?" Eğer öyleyse, o zaman elbette sadece geri dönün ve devam edin. Pratik olarak konuşmak, çoğu programda olan şey değildir.

Bayrağın kendisine gelince, istisnalar bayrağı genellikle kod kokusu olarak kabul edilir, çünkü bir kullanıcının işlevin nasıl çalıştığını anlamak için modülün hangi modda olduğunu bilmesi gerekir. İçinde ise !shouldThrowExceptionsmodunda kullanıcı bu bilmelidir onlar hataları algılayarak ve bunlar oluştuğunda beklenti ve değişmezleri korumaktan sorumludur. Ayrıca, işlevin çağrıldığı satırda, oradan oraya da sorumludurlar. Bunun gibi bir bayrak genellikle oldukça kafa karıştırıcıdır.

Ancak, olur. Birçok işlemcinin programdaki kayan nokta davranışını değiştirmeye izin verdiğini düşünün. Daha rahat standartlara sahip olmak isteyen bir program bunu basitçe bir sicil değiştirerek yapabilir (ki bu bir bayraktır). İşin püf noktası, diğer ayak parmaklarına yanlışlıkla basmaktan kaçınmak için çok dikkatli olmanız gerektiğidir. Kod, geçerli bayrağı sık sık kontrol eder, istenen ayara getirir, işlemleri yapar ve ardından geri ayarlar. Bu şekilde kimse değişiklikten şaşırmaz.


0

Bu özel örnek, kuralları etkileyebilecek ilginç bir özelliğe sahiptir ...

CalculateArea(int x, int y)
{
    if(x < 0 || y < 0)
    {
        if(shouldThrowExceptions) 
            throwException;
        else
            return 0;
    }
}

Burada gördüğüm bir önkoşul kontrolü. Başarısız bir önkoşul kontrolü, arama yığında daha yüksek bir hatayı gösterir. Dolayısıyla, soru şu hale geliyor: bu kod başka bir yerde bulunan hataları bildirmekten sorumlu mudur?

Burada gerginlik bazıları bu arayüz sergiler gerçeğine bağlanabilir ilkel saplantı - xve ymuhtemelen uzunluğunun gerçek ölçümlerini temsil etmek gerekiyor. Etki alanlarının belirli tiplerinin makul bir seçim olduğu bir programlama bağlamında, önkoşul kontrolünü verinin kaynağına yaklaştırırız - başka bir deyişle, veri bütünlüğünün sorumluluğunu çağrı yığınının yukarısına taşıyoruz. bağlam için daha iyi anlam.

Bu, başarısız bir kontrolü yönetmek için iki farklı stratejiye sahip olmanın temelde yanlış bir şey görmediğini söyledi. Tercihim, hangi stratejinin kullanımda olduğunu belirlemek için kompozisyon kullanmak; özellik bayrağı, kütüphane yönteminin uygulanmasından ziyade, kompozisyon kökünde kullanılacaktır.

// Configurable dependencies
AreaCalculator(PreconditionFailureStrategy strategy)

CalculateArea(int x, int y)
{
    if (x < 0 || y < 0) {
        return this.strategy.fail(0);
    }
    // ...
}

Sistemin çökemediği havacılık ile ilgili kritik uygulamalar üzerinde çalıştılar.

Ulusal Trafik ve Güvenlik Kurulu gerçekten iyidir; Gri kafalara alternatif uygulama teknikleri önerebilirim, ancak hata raporlama alt sisteminde perdeleri tasarlama konusunda tartışmaya meyilli değilim.

Daha geniş anlamda: İşletmenin maliyeti nedir? Bir web sitesini çökertmek hayati öneme sahip bir sistemden çok daha ucuz.


Hala modernleşirken istenen esnekliği korumak için alternatif bir yol önerisini seviyorum.
drjpizzle

-1

Yöntemler istisnaları ele alır veya yapmazlar, C # gibi dillerde bayraklara gerek yoktur.

public int Method1()
{
  ...code

 return 0;
}

Bir şey kötü giderse ... kodda o istisnanın arayan tarafından ele alınması gerekir. Kimse hatayı çözmezse, program sonlandırılır.

public int Method1()
{
try {  
...code
}
catch {}
 ...Handle error 
}
return 0;
}

Bu durumda, ... kodunda kötü bir şey olursa, Method1 sorunu ele alıyor ve program devam etmeli.

İstisnaları ele aldığınız yer size kalmış. Kesinlikle onları yakalayıp hiçbir şey yapmadan görmezden gelebilirsiniz. Ancak, yalnızca gerçekleşmesini bekleyebileceğiniz belirli belirli istisna türlerini görmezden geldiğinizden emin olabilirim. Yoksaymak ( exception ex) tehlikelidir, çünkü bazı istisnalar, hafızamız ve benzeri durumlarla ilgili sistem istisnaları gibi göz ardı etmek istemez.


3
OP'nin gönderdiği mevcut kurulum, isteyerek bir istisna atıp atmamaya karar vermeyle ilgilidir. OP'nin kodu, hafıza dışı istisnalar gibi istenmeyen şeyler yutmasına yol açmaz. Herhangi bir şey varsa, istisnaların sistemi çökertdiği iddiası, kod tabanının istisnaları yakalamadığı ve bu nedenle istisnaları yutmayacağı anlamına gelir ; Her ikisi de kasıtlı olarak OP'nin iş mantığı tarafından atılmış ve atılmamış olanlar.
Flast

-1

Bu yaklaşım "hızlı başarısız, zor başarısız" felsefesini kırıyor.

Neden hızlıca başarısız olmak istiyorsun :

  • Başarısızlık ne kadar hızlı olursa, başarısızlığın görünür belirtisi o kadar yakınsa, hatanın gerçek nedenidir. Bu hata ayıklamayı çok daha kolaylaştırır - en iyi durumda, yığın izlemenizin ilk satırında hata satırına sahip olursunuz.
  • Ne kadar çabuk başarısız olursanız (ve hatayı uygun şekilde yakalarsanız), programınızın geri kalanını karıştırmanız o kadar az olasıdır.
  • Ne kadar çok başarısız olursanız (yani, yalnızca "-1" kodunu döndürmek yerine bir istisna atama), arayan kişinin hatayı gerçekten önemsemesi ve yanlış değerlerle çalışmaya devam etmemesi daha olasıdır.

Hızlı ve sert bir şekilde başarısız olmamanın sakıncaları :

  • Eğer gözle görülür hatalardan kaçınırsanız, yani her şeyin yolunda gittiğini iddia ediyorsanız, asıl hatayı bulmayı inanılmaz derecede zorlaştırırsınız. Örneğinizin döndürdüğü değerin, 100 alanın toplamını hesaplayan bazı yordamların bir parçası olduğunu hayal edin; yani, bu işlevi 100 kez çağırmak ve dönüş değerlerini toplamak. Hatayı sessiz bir şekilde bastırırsanız , gerçek hatanın nerede oluştuğunu bulmanın bir yolu yoktur ; ve aşağıdaki tüm hesaplamalar sessizce yanlış olacaktır.
  • Başarısızlığı geciktirirseniz (bir alan için "-1" gibi imkansız bir dönüş değeri döndürerek), işlevinizin arayan kişisinin sadece rahatsız etmediği ve hatayı işlemeyi unuttuğu olasılığını artırır; eldeki başarısızlık hakkında bilgi sahibi olsalar bile.

Son olarak, istisnaya dayalı gerçek hata işleme, "bant dışı" bir hata mesajı veya nesneyi verebilme avantajına sahiptir, etki alanı kodunuzda tek bir ekstra satır yazmadan kolayca hata günlüğü, uyarı vb. .

Bu yüzden, sadece basit teknik sebepler değil, aynı zamanda hızlı başarısızlığı son derece faydalı kılan “sistem” sebepleri de var.

Günün sonunda, istisnai yol tutuşun hafif ve istikrarlı olduğu suç sayısının sadece yarı olduğu suçlu günümüzde sert ve hızlı bir şekilde başarısız olmamak. İstisnaları bastırmanın iyi olduğu fikrinin nereden geldiğini mükemmel bir şekilde anlıyorum, ancak artık geçerli değil.

Özellikle bile istisnalar veya olmasın atmak konusunda bir seçenek vermek için özel durumda, içinde: Bu Arayan karar vermek zorunda olduğu anlamına gelir neyse . Dolayısıyla, arayan kişinin istisnayı yakalaması ve uygun şekilde ele alması için hiçbir sakınca yoktur.

Bir yorumda gelen bir nokta:

Diğer cevaplarda, üzerinde çalıştığınız donanım bir uçak olduğunda kritik bir uygulamada hızlı ve sert bir şekilde başarısız olmanın istenmediğine dikkat çekildi.

Hızlı ve zor başarısız olmak, tüm uygulamanızın çöktüğü anlamına gelmez. Bu, hatanın oluştuğu noktada yerel olarak başarısız olduğu anlamına gelir. OP'nin örneğinde, bir alanı hesaplayan düşük seviye yöntemi, bir hatayı yanlış bir değerle sessizce değiştirmemelidir. Açıkça başarısız olması gerekir.

Bazıları zincirleme çağıranlar belli ki bu hatayı / istisnayı yakalamak ve uygun şekilde ele almak zorunda. Eğer bu yöntem bir uçakta kullanılmışsa, bu muhtemelen bir miktar LED ışığının yanmasına veya en azından yanlış bir alan yerine "hata hesaplama alanının" gösterilmesine yol açmalıdır.


3
Diğer cevaplarda, üzerinde çalıştığınız donanım bir uçak olduğunda kritik bir uygulamada hızlı ve sert bir şekilde başarısız olmanın istenmediğine dikkat çekildi.
HAEM

1
@HAEM, o zaman bu başarısız ve hızlı ne anlama geldiğini bir yanlış anlama. Bu konuda cevaba bir paragraf ekledim.
AnoE

Niyeti 'bu kadar zor' başarısız olmasa bile, bu tür bir ateşle oynamak hala riskli olarak görülmektedir.
drjpizzle

Bu tür bir nokta, @ drjpizzle. Hızlı ve hızlı bir şekilde başarısızlığa alışkınsanız, benim tecrübeme göre "riskli" veya "bu tür ateşle oynamak" değildir. Au kontraire. Bu, "burada bir istisna varsa ne olacağını", "burada" her yerde olduğu anlamına gelmeye başladığınızı ve şu anda programladığınız noktanın büyük bir sorun yaşayıp yaşamayacağının farkında olma eğiliminde olduğunuz anlamına gelir ( uçak kazası, bu durumda ne olursa olsun). Ateşle oynamak, çoğunlukla her şeyin yolunda gitmesini beklemek, ve her bir bileşen, şüphesiz, her şeyin yolunda olduğunu
iddia etmek olacaktır
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.