Hata değişkenleri bir model mi yoksa iyi bir tasarım mı?


44

Yürütmeyi durdurmaması gereken olası birkaç hatayla başa çıkmak için error, istemcilerin istisnalar atmak için denetleyebileceği ve kullanabileceği bir değişkenim var. Bu bir Anti-Pattern mi? Bununla baş etmenin daha iyi bir yolu var mı? Bunun bir örneği olarak PHP'nin mysqli API'sini görebilirsiniz. Görünürlük sorunlarının (erişimciler, genel ve özel kapsam, bir sınıftaki veya global değişkenin ne olduğunu?) Doğru ele alındığını varsayalım.


6
Bunun için var try/ catchvar. Ek olarak, yığınınızı ele almak için daha uygun bir yere koyabilirsiniz try/ catchendişelerin daha fazla ayrılmasını sağlar).
jpmc26

Akılda tutulması gereken bir şey: istisna tabanlı işleme kullanacaksanız ve bir istisna alırsanız, kullanıcıya çok fazla bilgi göstermek istemezsiniz. Kesişmek ve kullanıcıya genel bir hata mesajı göstermek için Elmah veya Raygun.io gibi bir hata eylemcisi kullanın. Kullanıcıya ASLA bir yığın izlemesi veya belirli bir hata mesajı göstermeyin, çünkü kötüye kullanılabilecek uygulamanın iç işleri hakkında bilgi ifşa ederler.
Nzall

4
@Nate Öneriniz, yalnızca kullanıcının tamamen güvenilmeyen olduğu kritik güvenlik uygulamaları için geçerlidir. Belirsiz hata mesajları kendileri bir anti-paterndir. Yani kullanıcının açık rızası olmadan ağ üzerinden hata raporları gönderiyor.
turta

3
@piedar Bunun daha özgürce tartışılabileceği ayrı bir soru oluşturdum: programmers.stackexchange.com/questions/245255/…
Nzall

26
API tasarımında sizi oldukça uzağa götüren genel bir prensip, PHP'nin her zaman ne yaptığını görmek ve ardından tam tersini yapmaktır.
Philipp

Yanıtlar:


65

Bir dil istisnaları doğal olarak destekliyorsa, istisnalar atılması tercih edilir ve istemciler bir başarısızlıkla sonuçlanmasını istemiyorlarsa istisnayı yakalayabilirler. Aslında, kodunuzun müşterileri istisnalar bekler ve dönüş değerlerini kontrol etmeyeceklerinden birçok hatayla karşılaşırlar.

Bir seçeneğiniz varsa, istisnaları kullanmanın bir kaç avantajı vardır.

Mesajlar

İstisnalar, geliştiricilerin hata ayıklama amacıyla kullanabileceği veya istenirse kullanıcılara bile gösterebileceği, kullanıcı tarafından okunabilen hata mesajları içerir. Tüketici kod istisnayı idare edemiyorsa, bunu her zaman kaydedebilir, böylece geliştiriciler, geri dönüş değerinin ne olduğunu bulmak için diğer izlerde durmak zorunda kalmadan günlükleri gözden geçirebilir ve geri dönüşün ne olduğunu bulmak için bir tabloda eşleyebilirler. gerçek istisna.

Dönüş değerleri ile kolayca sağlanabilecek ek bilgi yoktur. Bazı diller son hata mesajını almak için yöntem çağrısı yapmayı destekleyecektir, bu nedenle bu endişe biraz ortadan kalkar, ancak arayan kişi fazladan arama yapmayı gerektirir ve bazen bu bilgiyi taşıyan 'özel bir nesneye' erişim gerektirir.

İstisna mesajları durumunda, mümkün olduğunca fazla içerik sağlıyorum:

Kullanıcı profilinde referans verilen "bar" adlı kullanıcı için "foo" adında bir politika alınamadı.

Bunu bir dönüş kodu -85 ile karşılaştırın. Hangisini tercih edersiniz?

Çağrı yığınları

İstisnalar genellikle ayrıca, hata ayıklama kodunun daha hızlı ve daha hızlı hata ayıklamasına yardımcı olan ayrıntılı arama yığınlarına sahiptir ve istenirse arama kodu tarafından da kaydedilebilir. Bu, geliştiricilerin sorunu genellikle tam çizgiye göre belirlemelerini sağlar ve bu nedenle çok güçlüdür. Bir kez daha, bunu geri dönüş değerleri olan bir günlük dosyasıyla (-85, 101, 0 vb. Gibi) karşılaştırın, hangisini tercih edersiniz?

Hızlı önyargılı yaklaşım başarısız

Bir yöntem başarısız olan bir yere çağrılırsa, bir istisna atar. Çağıran kodun istisnayı açıkça bastırması gerekir, aksi halde başarısız olur. Bunu gerçekten şaşırtıcı buldum çünkü geliştirme ve test sırasında (ve hatta üretim sırasında) kod hızlı bir şekilde başarısız oluyor ve geliştiricilerin bunu düzeltmesi için zorluyor. Dönüş değerleri söz konusu olduğunda, bir dönüş değeri kontrolü kontrolünün kaçırılması durumunda, hata sessizce göz ardı edilir ve hata beklenmeyen bir yere çıkar ve genellikle hata ayıklama ve düzeltme maliyeti çok daha yüksek olur.

Sarma ve Açma İstisnaları

İstisnalar diğer istisnaların içine sarılabilir ve ardından gerekirse açılabilir. Örneğin, kodunuz ArgumentNullException, arama kodunda hangi UnableToRetrievePolicyExceptionişlemin başarısız olacağını , çünkü arama kodunda başarısız olan kodu atabilir . Kullanıcıya yukarıda verdiğim örneğe benzer bir mesaj gösterilse de, bazı tanı kodları istisnayı çözebilir ve bir ArgumentNullExceptionsoruna neden olduğunu bulabilir; bu, tüketicinin kodunda kodlama hatası olduğu anlamına gelir. Bu, geliştiricinin kodu düzeltebilmesi için bir uyarı verebilir. Bu gibi gelişmiş senaryoların geri dönüş değerleri ile uygulanması kolay değildir.

Kodun basitliği

Bunu açıklamak biraz zor, ama bu kodlama yoluyla hem istisnalar hem de dönüş değerleri ile birlikte öğrendim. Dönüş değerleri kullanılarak yazılan kod genellikle bir çağrı yapar ve ardından dönüş değerinin ne olduğu konusunda bir dizi kontrol yapar. Bazı durumlarda, başka bir metoda çağrı yapar ve şimdi bu metodun geri dönüş değerleri için başka bir dizi kontrol yapar. İstisnalarda, istisnasızlık çoğu durumda olmasa da çoğu zaman daha kolaydır. Bir try / catch / finally bloklarına sahipsiniz, çalışma zamanı, nihayet temizlik için kodu engellemek için elinden gelenin en iyisini yapmaya çalışıyor. İç içe geçmiş try / catch / nihayet blokları takip etmek ve sürdürmek, iç içe geçmiş if / else ve ilişkili dönüş değerlerini çoklu yöntemlerden nispeten kolaydır.

Sonuç

Kullandığınız platform istisnaları destekliyorsa (özellikle Java veya .NET gibi), o zaman kesinlikle istisnalar atmanın dışında başka bir yol olmadığını varsaymalısınız, çünkü bu platformlarda istisnalar atmak için kurallar vardır ve müşterileriniz bekleyecektir. yani. Kütüphanenizi kullanıyor olsaydım, geri dönüş değerlerini kontrol etmeye zahmet etmeyeceğim çünkü istisnaların atılmasını bekliyorum, bu platformlardaki dünya böyle.

Bununla birlikte, eğer C ++ ise, dönüş kodlarıyla zaten büyük bir kod temeli bulunduğundan ve çok sayıda geliştiricinin istisnaların aksine değerleri döndürmek için ayarlandığı için (örneğin, Windows HRESULT'larla doludur) belirlenmesi daha zor olacaktır. . Ayrıca, birçok uygulamada, bu da bir performans sorunu olabilir (veya en azından öyle algılanan).


5
Windows, genel API'lerinde C uyumluluğunu korumak için C ++ işlevlerinden HRESULT değerleri döndürür (ve sınırlar ötesinde istisnalar dışında olmaya çalışan bir incinme dünyasına girmeye başlarsınız). Bir uygulama yazıyorsanız, işletim sisteminin modelini kesinlikle uygulamayın.
Cody Gray,

2
Buna ekleyeceğim tek şey daha gevşek kuplajdan bahsediyor. İstisnalar, en uygun yerde pek çok beklenmedik durumla başa çıkmanıza izin verir. Örneğin, bir web uygulamasında, web uygulamasını çökertmek yerine, kodunuzun hazırlanmadığı herhangi bir istisna dışında bir 500 döndürmek istiyorsunuz . Bu yüzden, kodunuzun en üstünde (veya çerçevenizde) bir çeşit yakalamaya ihtiyacınız var. Masaüstü GUI'lerinde de benzer bir durum söz konusudur. Ancak aynı zamanda, çeşitli başarısızlık durumlarını denenen geçerli işlem için uygun bir şekilde ele almak üzere, koddaki çeşitli yerlere daha az genel işleyici koyabilirsiniz.
jpmc26

2
@TrentonMaki Eğer C ++ yapıcılarının hatalarından bahsediyorsanız, en iyi cevap burada: parashift.com/c++-faq-lite/ctors-can-throw.html . Kısacası, bir istisna atın, ancak önce potansiyel sızıntıları temizlemeyi unutmayın. Sadece bir kurucudan fırlatmanın kötü bir şey olduğu başka dillerin farkında değilim. Bir API kullanıcısının çoğu kullanıcısı hata kodlarını kontrol etmek yerine istisnaları yakalamayı tercih eder.
Ogre Psalm33

3
"Bu gibi gelişmiş senaryoların geri dönüş değerleri ile uygulanması kolay değildir." Tabi ki yapabilirsin! Tek yapmanız gereken bir ErrorStateReturnVariablesüper sınıf oluşturmak ve özelliklerinden biri de InnerErrorState(ki bunun bir örneğidir ErrorStateReturnVariable), alt sınıfları uygulayan bir hatalar zinciri göstermek için ayarlayabilecekleri ... ah, bekle. : p
Brian S

5
Sadece bir dilin istisnaları desteklemesi, onları her derde deva yapmaz. İstisnalar, gizli yürütme yollarını ortaya çıkarır ve bu nedenle etkilerinin uygun şekilde kontrol edilmesi gerekir; denemek / yakalamak eklemek kolaydır, ancak kurtarmayı doğru yapmak zordur , ...
Matthieu M.

21

Hata değişkenleri, istisnalar bulunmayan C gibi dillerden gelen bir kalıntıdır. Bugün, potansiyel olarak bir C programından (veya istisna işlemesi olmayan benzer bir dilden) kullanılan bir kütüphane yazmanız dışında, bunlardan kaçınmalısınız.

Elbette, daha iyi "uyarı" olarak sınıflandırılabilecek bir hata türünüz varsa (= kitaplığınız geçerli bir sonuç verebilir ve eğer önemli olmadığını düşünürse arayan, uyarıyı görmezden gelebilir) Bir değişkenin istisnaları olan dillerde bile mantıklı gelebilir. Ama dikkat et. Kütüphanenin arayanları, olmasalar bile bu tür uyarıları görmezden gelme eğilimindedir. Öyleyse, bu tür bir kurumu kütüphanenize eklemeden önce iki kez düşünün.


1
Açıklama için teşekkürler! Cevabınız + Ömer İkbal sorumu yanıtladı.
Mikayla Maki

"Uyarıları" ele almanın bir başka yolu, varsayılan olarak bir istisna atmak ve istisnanın atılmasını engellemek için bir tür isteğe bağlı bayrağa sahip olmaktır.
Cyanfish

1
@Cyanfish: evet, ama özellikle de kütüphaneler yaparken, bu tür şeylerin fazla tasarlanmamasına dikkat edilmelidir. 2, 3 veya daha fazla bir basit ve çalışan uyarı mekanizması sağlamak daha iyi.
Doktor Brown,

Bir istisna, yalnızca bir başarısızlık, bilinmeyen veya onarılamayacak bir senaryo yaşandığında ortaya çıkarılmalıdır - istisnai durumlar . İstisnalar oluşturulurken performansın etkisini beklemelisiniz
Gusdor

@Gusdor: kesinlikle, bu yüzden tipik bir "uyarı" IMHO varsayılan olarak bir istisna atmamalıdır. Ancak bu aynı zamanda soyutlama seviyesine de biraz bağlı. Bazen bir hizmet veya kütüphane, olağandışı bir etkinliğin arayanlar açısından bir istisna olarak ele alınıp alınmayacağına karar veremez. Şahsen, böyle durumlarda lib'i sadece bir uyarı göstergesi (istisna hariç) ayarlamak için tercih ederim, arayan kişinin uygun olduğunu düşünmesi durumunda bu bayrağı işaretlemesine ve bir istisna atmasına izin verin. Yukarıda " bir kütüphanede bir uyarı mekanizması sağlamak daha iyi" yazarken aklımda olan buydu .
Doktor Brown,

20

Bir hatayı işaret etmenin birden fazla yolu vardır:

  • kontrol etmek için bir hata değişkeni: C , Go , ...
  • bir istisna: Java , C # , ...
  • "durum" işleyicisi: Lisp (yalnızca?), ...
  • polimorfik bir dönüş: Haskell , ML , Rust , ...

Hata değişkeninin sorunu, kontrol etmeyi unutmanın kolay olmasıdır.

İstisnaların sorunu, gizli yürütme yolları yaratmasıdır ve deneme / yakalamanın yazılması kolay olmasına rağmen, yakalama maddesinde uygun bir kurtarmanın sağlanması gerçekten zor olmaktadır (tip sistemlerinden / derleyicilerden destek alınmaz).

Koşul işleyicileri sorunu, iyi oluşturulmadıklarıdır: dinamik kod yürütme işleminiz (sanal işlevler) varsa, hangi koşulların ele alınması gerektiğini tahmin etmek imkansızdır. Ayrıca, aynı koşul birkaç noktada ortaya çıkarsa, her seferinde tek tip bir çözelti uygulanabileceği söylenemez ve hızlı bir şekilde dağınık hale gelir.

Polimorfik dönüşler ( Either a bHaskell'de) şu ana kadar en sevdiğim çözüm:

  • açık: gizli yürütme yolu yok
  • açık: tamamen işlev türü imzasında belgelenmiştir (sürpriz yoktur)
  • ihmal edilmesi zor: İstenen sonucu elde etmek için kalıp eşleşmesi gerekir ve hata durumuyla başa çıkmanız gerekir.

Tek sorun, potansiyel olarak aşırı denetime yol açabilecekleri; Onları kullanan diller, onları kullanan fonksiyonların çağrılarını zincirlemek için deyimlere sahiptir, ancak yine de biraz daha fazla yazma / karışıklık gerektirebilir. Haskell'de bu monadlar olurdu ; Ancak, bu göründüğünden çok daha korkunç, bkz. Demiryolu Yönelimli Programlama .


1
İyi cevap! Hataları işlemenin bir listesini alabileceğimi umuyordum.
Mikayla Maki

Arrghhhh! Kaç kez bunu gördüm "Hata değişkeninin sorunu, kontrol etmeyi unutmanın kolay olmasıdır". İstisnalarla ilgili sorun, onu yakalamayı unutmanın kolay olmasıdır. Sonra uygulamanız çöküyor. Patronunuz bunu düzeltmek için ödeme yapmak istemiyor, ancak müşterileriniz uygulamanızı kullanmayı bıraktılar, çünkü çarpışmalardan korkuyorlar. Hepsi, hata kodları iade edilir ve yoksayılırsa programın yürütülmesini etkilemeyecek bir şey yüzünden. İnsanları gördüğüm tek zaman hata kodlarını görmezden gelmek, o kadar da önemli değildi. Kod yükseldikçe, bir şeyin yanlış gittiğini biliyor.
Dunk,

1
@Dunk: Cevabımın da istisnaların özünü yaptığını sanmıyorum; Yine de yazdığınız kodun türüne bağlı olabilir. Kişisel iş tecrübem , hataların varlığında başarısız olan sistemleri tercih etme eğilimindedir, çünkü sessiz veri bozulması daha kötüdür (ve tespit edilmez) ve üzerinde çalıştığım veriler müşteriye göre değerlidir (tabii ki bu aynı zamanda acil düzeltmeler anlamına da gelir).
Matthieu M.,

Bu sessiz veri bozulması meselesi değil. Uygulamanızı anlama ve bir işlemin başarılı olup olmadığını ne zaman ve nerede doğrulamanız gerektiğini bilme meselesidir. Çoğu durumda, bu belirleme ve işleme yapılması gecikebilir. Bir istisnanın gerektirdiği başarısız bir operasyonla ne zaman başa çıkmam gerektiğinin bana söylemesi başka birine kalmamalı. Uygulamam, ilgili sorunları ne zaman ve nerede ele almak istediğimi biliyorum. İnsanlar verileri bozabilecek uygulamalar yazarsa, bu gerçekten kötü bir iş yapıyor. Çöken uygulamalar yazmak (ki çok görüyorum) da kötü bir iş yapıyor.
Dunk

12

Bence korkunç. Şu anda istisnalar yerine return değerleri kullanan bir Java uygulamasını yeniden gözden geçiriyorum. Java ile hiç çalışmıyor olsanız da, bunun yine de geçerli olduğunu düşünüyorum.

Bunun gibi bir kodla bitirdiniz:

String result = x.doActionA();
if (result != null) {
  throw new Exception(result);
}
result = x.doActionB();
if (result != null) {
  throw new Exception(result);
}

Veya bu:

if (!x.doActionA()) {
  throw new Exception(x.getError());
}
if (!x.doActionB()) {
  throw new Exception(x.getError());
}

Eylemlerin kendilerine istisnalar atmasını tercih ederim, sen de böyle bir şeyle bitirdin:

x.doActionA();
x.doActionB();

Bunu bir denemeye alabilirsiniz ve istisnadan mesaj alabilirsiniz veya istisnayı yok saymayı seçebilirsiniz, örneğin daha önceden gitmiş olabilecek bir şeyi silerken. Ayrıca, varsa, yığın izinizi korur. Yöntemlerin kendileri de kolaylaşıyor. İstisnaları kendileri halletmek yerine, sadece yanlış olanı atıyorlar.

Geçerli (korkunç) kod:

private String doActionA() {
  try {
    someOperationThatCanGoWrong1();
    someOperationThatCanGoWrong2();
    someOperationThatCanGoWrong3();
    return null;
  } catch(Exception e) {
    return "Something went wrong!";
  }
}

Yeni ve geliştirilmiş:

private void doActionA() throws Exception {
  someOperationThatCanGoWrong1();
  someOperationThatCanGoWrong2();
  someOperationThatCanGoWrong3();
}

Çatlak izi korunur ve yararsız "Bir şeyler ters gitti!" Yerine mesaj istisna dışında bulunur.

Elbette daha iyi hata mesajları sağlayabiliyorsunuz ve almalısınız. Ancak bu yazı burada üzerinde çalışıyorum çünkü şu an üzerinde çalıştığım kod bir acı ve aynısını yapmamalısınız.


1
Yine de bir sorun, 'yeni ve gelişmiş'inizin, istisnanın başlangıçta gerçekleştiği bağlamı kaybedeceği durumlar vardır. Örneğin doActionA () 'nın "akım (korkunç) versiyonunda", catch cümlesi, daha kullanışlı bir mesaj vermek için ek değişkenindeki örnek değişkenlere ve diğer bilgilere erişebilir.
Bilgilendirilmiş

1
Bu doğru, ancak şu anda gerçekleşmiyor. Ve doActionA'daki istisnayı her zaman yakalayabilir ve bir durum mesajıyla başka bir istisnada sarabilirsiniz. Sonra yığın izine ve faydalı mesaja sahip olacaksınız . throw new Exception("Something went wrong with " + instanceVar, ex);
mrjink

Kabul ediyorum, sizin durumunuzda olmayabilir. Ancak bilgileri doActionA () işlevine "her zaman" koyamazsınız. Neden? DoActionA () 'nın arayanı, eklemeniz gereken bilgileri içeren tek kişi olabilir.
Bilgilendirilmiş

2
Öyleyse, arayan kişi istisnayı ele aldığında onu da dahil etsin. Aynısı, asıl soru için de geçerlidir. Artık istisnalar ile yapamayacağınız hiçbir şey yok ve bu da daha temiz kodlara yol açıyor. Döndürülen boolean'ler veya hata mesajları dışındaki istisnaları tercih ederim.
mrjink

Genellikle "bazı Operasyonlar" ın herhangi birinde meydana gelen bir istisnanın aynı şekilde ele alınabileceği ve temizlenebileceği varsayımını yanlış yaptınız. Gerçek hayatta olan şey, her operasyon için istisnaları yakalamanız ve ele almanız gerektiğidir. Böylece, sadece örneğinizde olduğu gibi bir istisna atmazsınız. Ayrıca, istisnalar kullanmak, daha sonra bir demet yuvalanmış try-catch bloğu veya bir dizi try-catch bloğu oluşturarak sona erer. Sıklıkla kodu daha az okunabilir yapar. İstisnalara karşı hazırlıklı değilim, ancak belirli durum için uygun aracı kullanıyorum. İstisnalar sadece 1 araçtır.
Dunk,

5

"Birkaç olası hatayla başa çıkmak için, bu yürütmeyi durdurmamalıdır"

Hataların mevcut işlevin yürütülmesini durdurmaması gerektiğini, ancak arayana bir şekilde bildirilmesi gerektiğini kastediyorsanız - o zaman gerçekten bahsedilmeyen birkaç seçeneğiniz vardır. Bu dava gerçekten bir hatadan çok bir uyarıdır. Atma / Geri Dönme, mevcut işlevi sona erdiren bir seçenek değildir. Tek bir hata mesajı parametresi veya dönüşü, bu hatalardan yalnızca birinin gerçekleşmesine izin verir.

Kullandığım iki kalıp:

  • Bir hata / uyarı koleksiyonu ya geçti ya da üye değişkeni olarak tutuldu. Hangi şeyleri eklersiniz ve işlemeye devam edersiniz. Ben şahsen bu yaklaşımı pek sevmiyorum çünkü arayanı rahatsız ediyor.

  • Bir hata / uyarı işleyici nesnesini iletin (veya onu bir üye değişkeni olarak ayarlayın). Ve her hata işleyicinin bir üye işlevini çağırır. Bu şekilde arayan kişi, bu gibi sonlandırmayan hatalarla ne yapılacağına karar verebilir.

Bu koleksiyonlara / işleyicilere aktardıklarınız, "doğru" bir şekilde işlenecek hatanın yeterince bağlamı içermelidir - Bir dize genellikle çok azdır, bir istisna örneğini iletmek çoğu zaman mantıklıdır - ancak bazen kaşlarını çatmıştır (İstisnalar kötüye kullanımı olarak) .

Bir hata eylemcisi kullanan tipik kod şöyle görünebilir

class MyFunClass {
  public interface ErrorHandler {
     void onError(Exception e);
     void onWarning(Exception e);
  }

  ErrorHandler eh;

  public void canFail(int i) {
     if(i==0) {
        if(eh!=null) eh.onWarning(new Exception("canFail shouldn't be called with i=0"));
     }
     if(i==1) {
        if(eh!=null) eh.onError(new Exception("canFail called with i=1 is fatal");
        throw new RuntimeException("canFail called with i=2");
     }
     if(i==2) {
        if(eh!=null) eh.onError(new Exception("canFail called with i=2 is an error, but not fatal"));
     }
  }
}

3
Kullanıcının bir hata yerine bir uyarı istediğini fark etmesi için +1. Python'un warnings, bu problem için başka bir kalıp veren paketinden bahsetmeye değer olabilir .
James_pic

Harika cevap için teşekkürler! Bu, görmek istediğim şeylerden daha fazlası, geleneksel denemenin / yakalamanın yeterli olmayabileceği hataları ele almak için ek modeller.
Mikayla Maki

Bir iletilen hata geri çağırma nesnesinin, belirli hatalar veya uyarılar meydana geldiğinde bir istisna atabileceğini belirtmek faydalı olabilir - bu, aslında, varsayılan davranış olabilir - ancak, ayrıca, sorabileceği anlamına gelmesi de yararlı olabilir. Bir şey yapmak için çağıran işlevi. Örneğin, bir "işleme ayrıştırma hatası" yöntemi, arayan kişiye ayrıştırmanın döndürdüğü kabul edilmesi gereken bir değer verebilir.
Süperkat

5

Herkesin kullandığı deseni kullandığınız sürece, bu deseni veya bu deseni kullanmakta genellikle yanlış bir şey yoktur. Gelen Amaç-Cı geliştirme, çok tercih edilen bir model olarak adlandırılan metot, NSError nesne yatırmak bir işaretçi geçmektir. İstisnalar programlama hataları için ayrılmıştır ve bir çökmeye yol açar (Java veya .NET programcılarını ilk iPhone uygulamalarını yazmadığınız sürece ). Ve bu oldukça iyi çalışıyor.


4

Soru çoktan cevaplandı ama kendime yardımcı olamıyorum.

İstisna'nın tüm kullanım durumları için bir çözüm sunmasını gerçekten bekleyemezsiniz. Kimseyi çekiçle?

İstisnaların her şeyin sonu olmadığı ve hepsinin olabileceği durumlar vardır, örneğin, bir yöntem bir istek alırsa ve geçen tüm alanları doğrulamaktan sorumluysa ve yalnızca birincisini değil, bunun mümkün olacağını düşünmeniz gerekir. Birden fazla alan için hatanın nedenini belirtin. Doğrulamanın niteliğinin kullanıcının daha ileri gitmesini engelleyip engellemediğini de belirtmek mümkün olmalıdır. Buna bir örnek, güçlü olmayan bir şifre olabilir. Kullanıcıya girilen parolanın çok güçlü olmadığını, ancak yeterince güçlü olduğunu belirten bir mesaj gösterebilirsiniz.

Bütün bu validasyonların validasyon modülünün sonunda bir istisna olarak atılabileceğini, ancak adından başka bir şeyde hata kodları olacağını iddia edebilirsiniz.

Yani buradaki ders: İstisnalar, hata kodları gibi kendi yerlerine sahiptir. Akıllıca seçti.


Bunun oldukça kötü bir tasarım olduğunu düşünüyorum. Argümanları alan bir yöntemin bunlarla başa çıkabilmesi veya başaramaması gerekir - arada bir şey yok. Örnekte, söz Validatorkonusu yönteme (veya arkasındaki nesne) enjekte edilmiş bir (arabirim) olmalıdır . Enjekte Validatoredilen yönteme bağlı olarak, yöntem hatalı şifrelerle ilerler - değil. Çevreleyen kod daha sonra bir WeakValidatorkullanıcı, örneğin WeakPasswordExceptionbaşlangıçta denenen tarafından atılmasından sonra isterse deneyebilir StrongValidator.
jhr

Ah, ama bunun bir arayüz veya onaylayıcı olamayacağını söylemedim. JSR303'ten bile bahsetmedim. Ve dikkatlice okursanız, zayıf parola söylememeyi, çok güçlü olmadığını söylemeyi başardım. Zayıf bir parola, akışı durdurmak ve kullanıcıdan daha güçlü bir parola istemek için bir neden olabilir.
Alexandre Santos

Ve orta derecede güçlü ama çok zayıf bir şifre ile ne yaparsınız? Akışı keser ve kullanıcıya, girilen parolanın çok güçlü olmadığını belirten bir mesaj gösterirsiniz. Yani bir MiddlyStrongValidatorşey ya da bir şey var. Ve bu, akışınızı gerçekten Validatorkesmediyse, önceden aranmış olması gerekir; bu, kullanıcı hala şifresini (veya benzerini) girerken akışa devam etmeden önce yapılmalıdır. Ancak doğrulama, ilk başta söz konusu yöntemin bir parçası değildi. :) Muhtemelen sonuçta bir tat meselesi ...
jhr

@jhr Yazdığım doğrulayıcılarda, tipik olarak AggregateException(veya benzerini ValidationException) oluşturacağım ve InnerExceptions'ta her doğrulama sorunu için özel istisnalar koyacağım. Örneğin, şu olabilir BadPasswordException: "Kullanıcının şifresi minimum 6 uzunluğundan az" veya MandatoryFieldMissingException: "Kullanıcı için ilk ad girilmelidir" vb. Bu hata kodlarına eşdeğer değildir. Bu mesajların tümü kullanıcıya anlayacakları şekilde görüntülenebilir ve eğer NullReferenceExceptionbunun yerine atılırsa bir hatamız olur.
Ömer İkbal

4

İstisnalara göre hata kodlarının tercih edilebileceği durumlar vardır.

Hataya rağmen kodunuz devam ederse, ancak bildirilmesi gerekiyorsa, istisnalar akışı sonlandırdığı için istisnalar kötü bir seçimdir. Örneğin, bir veri dosyasında okuyorsanız ve terminalde olmayan bazı kötü veriler bulunduğunu keşfederseniz, dosyanın geri kalanında okumak ve hatayı düpedüz yerine rapor etmek daha iyi olabilir.

Diğer cevaplar, istisnaların neden genel olarak hata kodları olarak tercih edilmesi gerektiğini ele almıştır.


Bir uyarının kaydedilmesi gerekiyorsa veya bir şey olursa, öyle olsun. Ancak, kullanıcıya bildirmeyi kastettiğinizi düşündüğüm bir "raporlama ihtiyacı" hatası varsa, çevreleyen kodun dönüş kodunuzu okuyup gerçekten rapor edeceğini garanti etmenin bir yolu yoktur.
jhr

Hayır, onu arayana bildirmek istiyorum. Bir istisna dışında, kullanıcının hatayı bilmesi gerekip gerekmediğine karar vermek arayanın sorumluluğundadır.
Jack Aidley

1
@jhr: Ne zaman bir şeyin garantisi var? Bir sınıf için sözleşme, müşterilerin belirli sorumluluklara sahip olduğunu belirtebilir; Müşteriler sözleşmeye uyuyorsa, sözleşmenin gerektirdiği şeyleri yapacaklardır. Olmazlarsa, sonuçlardan herhangi biri müşteri kodunun hatası olacaktır. Eğer müşteri yanlışlıkla yapılan hatalara karşı korunmak isterse ve seri hale getirme yönteminin döndürdüğü tip üzerinde kontrole sahipse, bir "kabul edilmemiş olası yolsuzluk" bayrağı içerebilir ve müşterilerin bir AcknowledgePossibleCorruptionyöntem çağırmadan bu bilgiyi okumalarına izin verilmez . .
supercat

1
... ancak problemler hakkında bilgi sahibi olacak bir nesne sınıfına sahip olmak, istisnalar atmaktan veya başarılı bir hata kodu döndürmekten daha yararlı olabilir. Bu bilginin uygun şekilde kullanılması (örneğin "Foo" dosyası yüklenirken, kullanıcıya verilerin güvenilir olamayacağı konusunda bilgi verilmesi ve kullanıcıdan kaydederken yeni bir ad seçmesi istenmesi) uygulamanın görevi olacaktır.
supercat

1
İstisnalar kullanılırsa tek bir garanti vardır: Onları yakalayamazsanız, daha yukarı fırlatırlar - kullanıcı arayüzüne kadar en kötü durum. Kimsenin okumadığı dönüş kodları kullanırsanız böyle bir garanti yoktur. Tabii, kullanmak istersen API'yi takip et. Katılıyorum! Ama hata için yer var, ne yazık ki ...
jhr

2

İstisnalar uygun olmadığında istisnalar kullanmamakta kesinlikle yanlış bir şey yoktur.

Kod yürütme kesintiye olmamalı zaman (örneğin derlemeye bir program veya sürecine formu gibi, birden fazla hatalar içerebilir kullanıcı girişi üzerinde hareket eden), ben gibi hata değişkenleri hataları toplama bulmak has_errorsve error_messagesgerçekten atma çok daha zarif bir tasarım ilk hatada bir istisna. Kullanıcının gereksiz yere yeniden göndermeye zorlamadan kullanıcı girişindeki tüm hataları bulmasını sağlar.


Soru ilginç. Benim sorum ve anlayışımla ilgili sorunun belirsiz bir terminoloji olduğunu düşünüyorum. Tarif ettiğin istisnai değil, ama bir hatadır. Buna ne demeliyiz?
Mikayla Maki

1

Bazı dinamik programlama dillerinde her iki kullanabilirsiniz hata değerlerini ve durum işleme . Bu, bir hata değeri gibi kontrol edilebilecek normal geri dönüş değerinin yerine çıkarılmamış istisna nesnesi döndürülerek yapılır , ancak kontrol edilmezse istisna atar.

Gelen Perl 6 ile yapılıyor failWithing halinde, bu no fatal;kapsamı özel unthrown durum döner Failurenesne.

In Perl 5 kullanabileceğiniz İçeriğe :: İade sen ile yapabilirsiniz return FAIL.


-1

Çok özel bir şey olmadığı sürece, doğrulama için bir hata değişkenine sahip olmanın kötü bir fikir olduğunu düşünüyorum. Amaç doğrulama için harcanan zamanı kaydetmemek gibi görünüyor (sadece değişken değerini geri döndürebilirsiniz)

Fakat bir şeyi değiştirirseniz, yine de bu değeri yeniden hesaplamanız gerekir. Durma ve İstisna atma hakkında daha fazla şey söyleyemem.

EDIT: Bunun belirli bir durum yerine yazılım paradigması meselesi olduğunun farkında değildim.

Cevabımın mantıklı olacağı belirli bir madende durumumu daha da açıklığa kavuşturayım

  1. Bir varlık nesneleri koleksiyonum var
  2. Bu varlık nesnelerle çalışan ussal stil web hizmetlerine sahibim

İki tür hata vardır:

  1. İşlemin servis katmanında meydana geldiği hatalar
  2. Varlık nesnelerinde tutarsızlıklar olduğu için hatalar

Servis katmanında, Result nesnesini, hata değişkeninin eşdeğeri olan sarıcı olarak kullanmaktan başka bir seçenek yoktur. Bir istisnayı http gibi protokol üzerinden servis çağrısı yoluyla simüle etmek mümkündür, ancak kesinlikle yapılması gereken iyi bir şey değildir. Bu tür bir hatadan bahsetmiyorum ve bunun bu soruda sorulmakta olan bir hata olduğunu düşünmedim.

İkinci tür hatayı düşünüyordum. Ve cevabım bu ikinci tür hatalarla ilgili. Varlık nesnelerinde, bizim için seçenekler var, bazıları

  • doğrulama değişkeni kullanma
  • bir alan ayarlayıcıdan yanlış ayarlandığında hemen bir istisna atmak

Doğrulama değişkenini kullanmak, her varlık nesnesi için tek bir doğrulama yöntemine sahip olmakla aynıdır. Özellikle, kullanıcı, ayarlayıcıyı tamamen ayarlayıcı olarak tutacak şekilde ayarlayabilir, hiçbir yan etkisi olmaz (bu genellikle iyi bir uygulamadır) veya biri onaylayıcıyı her ayarlayıcıya dahil edebilir ve ardından sonucu bir doğrulama değişkenine kaydedebilir. Bunun avantajı zamandan tasarruf sağlamaktır, doğrulama sonucu doğrulama değişkenine önbelleğe alınır, böylece kullanıcı validation () birden fazla kez aradığında, çoklu doğrulama yapmaya gerek kalmaz.

Bu durumda yapılacak en iyi şey, doğrulama hatasını önbelleğe almak için herhangi bir doğrulama kullanmadan tek bir doğrulama yöntemi kullanmaktır. Bu, ayarlayıcıyı yalnızca ayarlayıcı olarak tutmanıza yardımcı olur.


Ne hakkında konuştuğunu anlıyorum. İlginç yaklaşım Cevap setinin bir parçası olduğuna sevindim.
Mikayla Maki
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.