Biri boş beklemiyorsa null kontrolü yapmalı mı?


113

Geçen hafta, uygulamamızın hizmet katmanındaki boş değerleri ele alma konusunda hararetli bir tartışma yaptık. Soru .NET bağlamında, ancak Java ve diğer birçok teknolojide aynı olacak.

Soru şuydu: boştakileri her zaman kontrol etmeli ve ne olursa olsun kodunuzun çalışmasını sağlamalı mı ya da boş bir beklenmedik şekilde alındığında bir istisna oluşsun mu?

Bir tarafta, beklemeyeceğiniz null (yani onu işlemek için kullanıcı arayüzü yok) kontrol, bence, boş yakalamak bir deneme bloğu yazmak gibi. Sadece bir hata gizliyorsun. Hata, kodda bir şeylerin değişmiş olması olabilir ve null şimdi beklenen bir değerdir veya başka bir hata vardır ve yanlış kimlik yönteme iletilir.

Öte yandan, boş değerlerin kontrolü genel olarak iyi bir alışkanlık olabilir. Dahası, eğer bir kontrol varsa uygulama çalışmaya devam edebilir, fonksiyonelliğin sadece küçük bir kısmı etkilenmez. Ardından müşteri "X sayfasını açamaz" gibi çok daha ciddi bir hata yerine "yorumu silemez" gibi küçük bir hatayı bildirebilir.

Hangi uygulamaları takip ediyorsun ve bu yaklaşımlardan herhangi birine karşı ya da karşı olan argümanların neler?

Güncelleme:

Özel durumumuz hakkında biraz ayrıntı eklemek istiyorum. Veritabanından bazı nesneler alıyorduk ve üzerlerinde bazı işlemler yaptık (diyelim ki, bir koleksiyon oluşturalım). Kodu yazan geliştirici, nesnenin boş olacağını tahmin etmiyordu, bu nedenle herhangi bir kontrol içermiyordu ve sayfa yüklendiğinde bir hata oluştu ve tüm sayfa yüklenmedi.

Açıkçası, bu durumda bir çek olmalıydı. Sonra, işlenen her nesnenin, eksik olması beklenmese bile kontrol edilmesinin gerekip gerekmediği ve nihai işlemenin sessizce iptal edilip edilmemesi gerektiği üzerine bir tartışma yaptık.

Varsayımsal yarar, sayfanın çalışmaya devam edeceği olacaktır. Stack Exchange'de farklı gruplar halinde (kullanıcılar, yorumlar, sorular) bir arama sonucu düşünün. Bu yöntem null değerini kontrol edebilir ve (bir hata nedeniyle null olan) kullanıcıların işlemlerini iptal edebilir, ancak "yorumlar" ve "sorular" bölümlerini döndürür. Sayfa, "kullanıcılar" bölümünün (bir hata) eksik olması dışında çalışmaya devam eder. Erken başarısız olup tüm sayfayı kırmalı mıyız veya çalışmaya devam edip birisinin "kullanıcılar" bölümünün eksik olduğunu fark etmesini beklemeli miyiz?


62
Fox Mulder prensibi: Kimseye güvenme.
yannis

14
@YannisRizos: bu ilke iyi bir şey - o kadar iyidir ki, Java ve C # yaratıcıları dilin çalışma zaman ortamının bunu otomatik olarak yapmasına izin verir. Bu nedenle normal olarak, kodunuzun her yerinde bu dillerde boş aramalar yapmanız gerekmez .
Doktor Brown,


Tdammers'ın cevabına katılıyorum. Boş denetlemenin yanlış olduğuna inanıyorum, çünkü bununla başa çıkmak için makul bir yolunuz yok. Ancak senaryonuzda, bir kullanıcıyı onaylamak (veya yorum almak veya her ne olursa olsun) ve "oh hiçbir hata oluşmamış" kutusunun olması gibi bir bölümü kaldırabilirsiniz. Uygulamamdaki tüm istisnaları kişisel olarak kaydettim ve

2
assert(foo != null, "foo is web control within the repeater, there's no reason to expect it to be null, etc, etc...");
zzzzBov

Yanıtlar:


105

Asıl soru, nullçalışma zamanının bir istisna atmasına izin verip vermemeniz gerektiği değil ; Beklenmedik bir duruma nasıl cevap vermelisin.

Seçenekleriniz, o zaman:

  • Genel bir istisna ( NullReferenceException) atın ve kabarmasına izin verin; Eğer nullkontrolü kendiniz yapmazsanız, otomatik olarak olan budur.
  • Sorunu daha yüksek düzeyde tanımlayan özel bir istisna atın; Bu, nullçeke NullReferenceExceptionatılarak veya daha belirgin bir istisna yakalayarak ve atarak gerçekleştirilebilir.
  • Uygun bir varsayılan değerin yerini alarak kurtarın.

Hangisinin en iyi çözüm olduğuna dair genel bir kural yoktur. Şahsen şöyle derdim:

  • Genel istisna, hata koşulu kodunuzdaki ciddi bir hatanın belirtisi olduğunda, en iyisidir, yani boş olan değerin ilk sırada oraya asla girmesine izin verilmemelidir. Böyle bir istisna, kurduğunuz hata günlüğüne kadar tümüyle kabarcıklı olabilir, böylece birisi bilgilendirilir ve hatayı düzeltir.
  • Yarı yararlı çıktı sağlamak, teknik olarak hatalı HTML'yi kabul eden ve mantıklı hale getirmek için en iyi çabayı gösteren web tarayıcısı gibi doğruluktan daha önemliyse, varsayılan değer çözümü iyidir.
  • Aksi takdirde, özel istisna ile gider ve uygun bir yerde tutardım.

1
@ Son kullanıcı için Stilgar fark yoktur. gibi belirli bir istisna "veritabanı sunucusunda erişilemiyor" developper için "boş işaretçi excepteion" olduğunu daha sezgisel
k3b

32
Sıkı ve erken başarısız olmak, çizginin aşağısında daha ustaca yanlış gitme, yanlış kimlik doğrulama, saklı kalmaya devam eden bozuk veri, bilgi sızması ve diğer eğlenceli şeyler gibi risklerin daha az olduğu anlamına gelir.
Lars Viklund

1
@ Stilgar: Burada iki kaygı var: katılımsız davranış ve sürdürülebilirlik. Katılımsız davranış için belirli bir istisna ve genel bir davranış arasında çok az fark varken, sürdürebilirlik açısından "oh, bu yüzden işler patlar" ve çok saatlik bir debugatlon arasındaki farkı yaratabilir.
tdammers

3
Tdammers tam olarak doğru. "Nesne başvurusu bir nesnenin örneğine ayarlanmadı", en sık görülen en sinir bozucu istisnalardan biridir. Bunun parametre adıyla bir ArgumentNullException veya "TK421 kullanıcısı için hiçbir kayıt yok" şeklinde bir özel istisna olup olmadığını görmeyi tercih ederim.
Sean Chase,

1
@ k3b Son kullanıcı için de “veritabanı sunucusuna ulaşılamıyor” çok yardımcı oluyor. En azından, yaygın sorunlar hakkında biraz ipucu olan herhangi bir son kullanıcı için - kablonun gevşek olduğunu, buggy yazılımına kızmak yerine yönlendiricinin yeniden başlatılması gerektiğini vs. bulmasına yardımcı olabilir.
Julia Hayward

58

IMHO, beklemeyeceğiniz boş değerleri ele almaya çalışmak, aşırı karmaşık kodlara yol açar. Eğer boş beklemiyorsanız, fırlatarak netleştirin ArgumentNullException. İnsanlar değerin boş olup olmadığını kontrol ettiklerinde ve sonra herhangi bir anlam ifade etmeyen bir kod yazmaya çalıştıklarında gerçekten sinirleniyorum. Aynı şey SingleOrDefault, birisinin gerçekten beklediği Singledurumlarda ve hatta çoğu zaman ne olduğunu bilmiyorum) mantığını açık bir şekilde ifade etmekten korktuğunda (gerçekten ne olduğunu bilmiyorum) kullanmak (veya daha da kötüleşmek ) için de geçerlidir.


Bunun yerine, ArgumentNullExceptionkod sözleşmeleri kullanılmalıdır (kod sözleşmelerini desteklemeyen 2010 öncesi bir kaynak kod değilse).
Arseni Mourzenko

Size katılıyorum. Eğer boş beklenmiyorsa, garip şekillerde kullanılmamalıdır, sadece bildirilmelidir.
Giorgio,

9
Eğer doğru soruyu okursam, bir ArgumentNullExceptionboş değeri "işleme" olarak sayarsak , daha sonra boş bir referans istisnasını önler .
KutuluMike

@MichaelEdenfield: Verilen soruya göre bunun gerçek bir işlem sayıldığını sanmıyorum (amacımız ne olursa olsun kodunuzun çalışmasını sağlamak değildir ). Dürüst olmak gerekirse, boş geçilirse fırlatacak uygun bir blok yazmayı unutuyorum. Ancak, NullArgumentException'ı en iyi uygulama olarak atmayı düşünüyorum ve bence en kötü uygulama null'ı işleyemeyen ancak istisna geri dönüşleri atmak yerine, örneğin bir yöntem sonucu olarak başka bir boş (veya boş dize veya boş toplama veya -1) , veya dönüş türü geçersizse yöntem yürütmeyi atlar, vb.).
empi

2
@Giorgio, ArgumentNullExceptionsorunun ne olduğunu ve nasıl düzeltileceğini çok net bir şekilde ortaya koyuyor. C # "tanımsız" kullanma eğiliminde değildir. Eğer bir şeyi tanımsız bir şekilde ararsanız, aradığınız şey mantıklı olmaz. Bir istisna, bunu belirtmek için uygun yoldur. Şimdi, bazen int(örneğin) ayrıştırılamadığında null döndüren ayrıştırma yöntemlerini yapacağım . Ancak bu, kabul edilemez bir sonucun kullanım hatası yerine meşru bir olasılık olduğu bir durumdur. Ayrıca bu makaleye bakınız .
Kyralessa

35

nullDeneyimlerime bakma alışkanlığı, eski C veya C ++ geliştiricilerinden geliyor; bu dillerde, kontrol etmediğiniz zamanlarda ciddi bir hatayı gizleme şansınız var NULL. Bildiğiniz gibi, Java veya C # 'da işler farklıdır, denetlemeden boş bir ref kullanmak null, bir istisnaya neden olur; bu nedenle, arayan tarafta görmezden gelmediğiniz sürece hata gizlice gizlenmez. Bu yüzden çoğu durumda, açıkça kontrol etmek nullpek bir anlam ifade etmiyor ve kodu gereğinden fazla zorlaştırıyor. Ben bu yüzden yok (en azından, değil genel olarak) o dillerde iyi alışkanlık olmaya boş denetimi düşünün.

Tabii ki, bu kuralın istisnaları var, işte aklıma gelenler:

  • Kullanıcıya programın hangi bölümünde yanlış null başvurusunun gerçekleştiğini söyleyen daha iyi, insan tarafından okunabilen bir hata mesajı vermek istiyorsanız. Yani null için yaptığınız test farklı bir hata metniyle birlikte sadece farklı bir istisna atar. Açıkçası, hiçbir hata bu şekilde maskelenmeyecek.

  • Programınızı "daha erken başarısız" yapmak istiyorsunuz. Örneğin, nesne başvurusunun aksi takdirde yalnızca bir üye değişkeninde saklanıp daha sonra kullanılacağı bir constructor parametresinin boş değerini kontrol etmek istiyorsunuz.

  • Boş bir ref durumu, sonraki arıza riski olmadan ve ciddi bir hatayı maskeleme olmadan güvenle çözebilirsiniz.

  • Geçerli bağlamınızda tamamen farklı bir tür hata sinyali (örneğin, bir hata kodu döndürme) istiyorsanız


3
"daha iyi, okunabilir bir hata mesajı istiyorsun" - bence bunu yapmanın en iyi nedeni bu. "Nesne başvurusu bir nesnenin örneğine ayarlanmadı" veya "Boş başvuru istisnası" hiçbir zaman "Ürün somutlaştırılmadı" kadar yararlı değildir.
pdr,

pdr: Kontrol etmenin bir diğer nedeni de her zaman algılandığından emin olmak.
Giorgio,

13
Belki de "Eski C geliştiricileri". "Eski C ++ geliştiricileri" yalnızca kendileri C geliştiricilerini kurtarıyorsa. Modern bir C ++ geliştiricisi olarak çıplak işaretçiler veya dikkatsiz dinamik tahsisat kullanan kod hakkında çok şüpheliydim. Aslında, argümanı tersine çevirmeye ve C ++ ' nın OP'nin tanımladığı sorunla karşı karşıya olmadığını söylemeye cazip olacağım çünkü değişkenleri Java ve C #' nın sahip olduğu özel boş özelliklere sahip değil.
Kerrek SB,

7
İlk paragrafınız hikayenin sadece yarısıdır: evet, C # ile boş bir başvuru kullanırsanız, bir istisna elde edersiniz, oysa C ++ 'da tanımsız davranış alırsınız. Ancak, iyi yazılmış C # 'da, iyi yazılmış C ++' dan çok daha fazla null olabilecek referansla sıkışmışsınızdır .
James McNell,

Kapsülleme ne kadar iyi olursa, bu cevap o kadar iyi uygulanır.
radarbob

15

Kullanım iddia test edip kodu için ön / Hedefşartlar ve değişmezler gösterir.

Kodun neyi beklediğini ve neyin ele alınması beklenebileceğini anlamayı çok daha kolaylaştırır.

Bir iddia, IMO, uygun bir kontrol çünkü:

  • verimli (genellikle sürümde kullanılmaz),
  • kısa (genellikle tek satır) ve
  • temizle (ön koşul ihlal edildi, bu bir programlama hatasıdır).

Kendini belgeleyen kodun önemli olduğunu düşünüyorum, bu nedenle bir onay almak iyi. Defansif, hatasız programlama, çoğu zaman harcanan yerde bakımı kolaylaştırır.

Güncelleme

Çalışmanızı tamamlayın. Son kullanıcıya, hataların altında çalışan, yani mümkün olduğu kadar iyi görünen bir uygulama vermek genellikle iyidir. Sağlamlık iyidir, çünkü cennet yalnızca kritik bir anda ne kıracağını bilir.

Bununla birlikte, geliştiricilerin ve test yapanların ASAP hatalarının farkında olmaları gerekir, bu nedenle muhtemelen bir sorun olduğu konusunda kullanıcıyı uyaran bir kancaya sahip bir kayıt çerçevesi istiyorsunuz. Uyarı muhtemelen tüm kullanıcılara gösterilmelidir, ancak çalışma zamanına bağlı olarak muhtemelen farklı şekillerde uyarlanabilir.


sürümde bulunmadığını iddia etmek benim için büyük bir olumsuz, sürüm eklemek istediğiniz bilginin tam zamanı
jk.

1
Peki, ihtiyacınız varsa, sürümde etkin olan assert ^ h ^ h ^ hconditional throw işlevini kullanmaktan çekinmeyin. Kendimi sık sık yuvarladım.
Macke

7

Erken başarısız olun, sık sık başarısız olun. nullKullanabileceğiniz en iyi beklenmedik değerlerden biridir, çünkü kullanmaya başlar başlamaz çabucak başarısız olabilirsiniz. Diğer beklenmeyen değerleri tespit etmek o kadar kolay değildir. Beri nullbunu kullanmaya çalıştığınızda her sizin için otomatik olarak başarısız, ben açık bir çek gerektirmez söyleyebilirim.


28
Umarım demek istediniz: Erken başarısız, hızlı başarısız, sık sık değil ...
empi

12
Sorun, açık kontroller olmadan, bir boş değerin bazen bir istisnaya neden olmadan önce oldukça uzağa yayılması ve daha sonra nereden geldiğini bulmak çok zor olabilir.
Michael Borgwardt

@ MichaelBorgwardt Yığın izleri bunun için değil mi?
R0MANARMY

6
@ R0MANARMY: yığın izleri boş bir değer bir alana kaydedildiğinde ve NullPointerException çok daha sonra atıldığında yardımcı olmaz.
Michael Borgwardt

@ R0MANARMY yığın izlemesindeki satır numarasına güvenebilseniz bile (çoğu durumda yapamazsınız) bazı satırlar null olabilecek birden fazla değişken içerir.
Ohad Schneider

6
  • Bir boşluğu kontrol etmek sizin ikinci doğanız olmalıdır

  • API'niz diğer insanlar tarafından kullanılacak ve beklentileri sizinkinden farklı olabilir

  • Kapsamlı ünite testleri normalde boş referans kontrolü ihtiyacını vurgulamaktadır

  • Boşlukları kontrol etmek şartlı ifadeler anlamına gelmez. Boş denetlemenin kodunuzu daha az okunabilir kılmasından endişe ediyorsanız, .NET kod sözleşmelerini göz önünde bulundurmak isteyebilirsiniz.

  • Eksik boş referans kontrolleri için kodunuzu aramak üzere ReSharper'ı (veya benzerini) yüklemeyi düşünün


Önkoşullar için kod sözleşmelerini kullanmak, yalnızca koşullu ifadeleri yüceltir.
12'de CVn

Evet, katılıyorum, ancak kod sözleşmelerini kullanırken kodun daha temiz olduğunu düşünüyorum, yani okunabilirliği artırıldı.
CodeART

4

Soruyu anlamsal bakış açısından ele alırdım, yani kendime NULL işaretçi veya null referans argümanının neyi temsil ettiğini sorun.

Bir işlev veya yöntem foo (), T türünde x argümanına sahipse, x zorunlu veya isteğe bağlı olabilir .

C ++ 'da zorunlu bir argüman olarak

  • Bir değer, örneğin geçersiz foo (T x)
  • Bir referans, örneğin geçersiz foo (T & x).

Her iki durumda da bir NULL işaretçi kontrol etme probleminiz yoktur. Yani, birçok durumda, bir boş gösterici çek gerekmez hiç zorunlu argümanlar için.

Bir geçiyoruz isteğe bağlı argüman, bir işaretçi kullanabilir ve hiçbir değer verildiğini göstermek için NULL değerini kullanabilirsiniz:

void foo(T* x)

Bir alternatif gibi bir akıllı işaretçi kullanmaktır

void foo(shared_ptr<T> x)

Bu durumda, muhtemelen koddaki işaretçiyi kontrol etmek istersiniz, çünkü x'in bir değer içerip içermediğine veya hiç değer içermemesine bağlı olarak foo () yönteminde bir fark yaratır.

Üçüncü ve son durum, zorunlu bir argüman için bir işaretçi kullanmanızdır . Bu durumda, x == NULL ile foo (x) çağrısı bir hatadır ve bunun nasıl ele alınacağına karar vermelisiniz (sınırların dışında bir endekse veya geçersiz herhangi bir girişle aynı şekilde):

  1. Kontrol yok: bir hata varsa çökmesine izin verin ve bu hatanın yeterince erken görünmesini umun (test sırasında). Olmazsa (yeterince erken başarısızlığa uğramazsanız), bir üretim sisteminde görünmeyeceğini umarsınız, çünkü kullanıcı deneyimi uygulama çöküşünü göreceklerdir.
  2. Yöntemin başındaki tüm argümanları kontrol edin ve geçersiz NULL argümanlarını bildirin; örneğin, foo () komutundan bir istisna atayın ve başka bir yöntemin bunu yapmasına izin verin. Muhtemelen yapılacak en iyi şey, kullanıcıya uygulamanın dahili bir hatayla karşılaştığını ve kapanacağını söyleyen bir iletişim penceresi göstermektir.

Daha iyi bir başarısızlık yolunun dışında (kullanıcıya daha fazla bilgi vermek), ikinci yaklaşımın bir avantajı, hatanın bulunmasının daha muhtemel olmasıdır: Program, yöntemin yanlış argümanlarla çağrıldığı her seferinde başarısız olur. Yaklaşım 1'de hata sadece işaretçiyi yönlendiren bir ifadenin çalıştırılması durumunda ortaya çıkar (örn. bir if ifadesinin sağ dalı girilmişse). Dolayısıyla yaklaşım 2 daha güçlü bir "erken başarısız" şekli sunar.

Java'da daha az seçeneğiniz vardır, çünkü tüm nesneler her zaman boş olabilen referanslar kullanılarak iletilir. Yine, null isteğe bağlı bir argümanın NONE değerini temsil ediyorsa, null değerinin kontrol edilmesi (muhtemelen) uygulama mantığının bir parçası olacaktır.

Boş değer geçersiz bir girdiyse, o zaman bir hata yaparsınız ve ben C ++ işaretçilerinde olduğu gibi benzer düşünceler uygulardım. Java'da boş gösterici istisnaları yakalayabildiğiniz için, yukarıdaki yaklaşım 1, yöntem foo () tüm yürütme yollarındaki (muhtemelen küçük yöntemler için çok sık meydana gelen) tüm giriş bağımsız değişkenlerini kaldırırsa, yaklaşım 2'ye eşdeğerdir.

Özetleme

  • Hem C ++ hem de Java'da isteğe bağlı değişkenlerin boş olup olmadığını kontrol etmek programın mantığının bir parçasıdır.
  • C ++ 'da, programın sağlam bir şekilde idare edebilmesi için uygun bir istisna oluşturulduğundan emin olmak için zorunlu argümanları her zaman kontrol ederim .
  • Java'da (veya C #), daha güçlü bir "erken başarısız" biçimine sahip olmak için fırlatmayan yürütme yolları varsa zorunlu argümanları kontrol ederdim .

DÜZENLE

Daha fazla bilgi için Stilgar'a teşekkürler.

Senin durumunda bir yöntemin sonucu olarak boş var gibi görünüyor. Yine, bir karar vermeden önce yöntemlerin anlamını önce netleştirmeniz ve düzeltmeniz gerektiğini düşünüyorum.

Bu nedenle, m1 () yöntemini çağırıyorsanız, m2 () yöntemini çağırıyorsunuz ve m2 () bir nesneye bir referans (Java'da) ya da bir işaretçi (C ++ içinde) döndürüyor.

M2 () 'nin anlamı nedir? M2 () her zaman boş olmayan bir sonuç verir mi? Bu durumda boş bir sonuç dahili bir hatadır (m2 () cinsinden ). Dönüş değerini m1 () cinsinden kontrol ederseniz, daha sağlam bir hata işleme hakkınız olabilir. Aksi takdirde, er ya da geç, muhtemelen bir istisna olacaktır. Belki de değil. İstisnaların dağıtım sırasında değil test sırasında atıldığını umuyoruz. Soru : eğer m2 () hiç boş bırakmazsa, neden boş dönüyor? Belki de bunun yerine bir istisna atmalı? m2 () muhtemelen buggy.

Alternatif, boş değerin geri döndürülmesi, m2 () yönteminin anlambiliminin bir parçasıdır, yani yöntemin Javadoc belgelerinde belgelenmesi gereken isteğe bağlı bir sonuç vardır. Bu durumda boş değere sahip olmak tamamdır. M1 () yöntemi başka bir değer olarak kontrol etmelidir: burada hata yoktur, ancak sonucun null olup olmadığını kontrol etmek program mantığının sadece bir kısmıdır.


Dışarıda, boş olan argüman değildi. Mevcut olması beklenen bir şey için veritabanı çağrısı yaptık, ancak pratikte yoktu. Soru, her nesnenin var olup olmadığını kontrol etmemiz veya sadece eksik olmasını beklememiz durumunda kontrol etmemiz gerektiğidir.
Stilgar

Bu nedenle, bir yöntem tarafından döndürülen sonuç, bir nesneye referanstı ve null, sonucu temsil etmek için kullanılan değerdi: NOT FOUND. Doğru anlıyor muyum
Giorgio

Soruyu ek detaylarla güncelledim.
Stilgar

3

Genel yaklaşımım, nasıl idare edeceğinizi bilmediğiniz bir hata durumunu asla test etmemektir . Daha sonra her bir özel durumda cevaplanması gereken soru şu olur: Beklenmeyen değerin varlığında makul bir şey yapabilir misiniznull ?

Başka bir değerle (boş bir koleksiyon, örneğin veya varsayılan bir değer veya örnek) değiştirerek güvenle devam ederseniz, elbette bunu yapın. @ Shahbaz'ın World of Warcraft'tan bir görüntüyü başka biriyle ikame etmek bu kategoriye giriyor; görüntünün kendisi sadece dekorasyondur ve işlevsel bir etkisi yoktur . (Bir hata ayıklama yapısında, sübstitüsyonun gerçekleştiğine dikkat çekmek için çığlık atan bir renk kullanırdım, ancak bu uygulamanın doğasına bağlı olarak değişir.) Hata ile ilgili ayrıntıları günlüğe kaydedin; Aksi takdirde, muhtemelen bilmek istediğiniz bir hatayı gizliyor olacaksınız. Kullanıcıdan gizlemek bir şeydir (işlemin güvenli bir şekilde devam edebileceğini varsayalım); geliştiriciden gizlemek başka bir şeydir.

Boş bir değer varlığında güvenli bir şekilde devam edemezseniz, makul bir hatayla başarısız olun; Genel olarak, operasyonun başarılı olamayacağı belli olduğunda en kısa sürede başarısız olmayı tercih ediyorum, bu da önkoşulları kontrol etmek anlamına geliyor. Derhal başarısız olmak istemediğiniz, ancak mümkün olduğunca uzun süre ertelemeyi istemediğiniz zamanlar vardır; bu değerlendirme, örneğin, yan kanal saldırılarının bilmediğiniz bilgileri açığa çıkarabileceği kriptografi ile ilgili uygulamalarda ortaya çıkar. Sonunda, hatanın bir genel hata işleyicisine kadar kabarmasına izin verin; bu da ilgili ayrıntıları kaydeder ve kullanıcıya güzel (ancak güzel olabilir) hata mesajı görüntüler.

Ayrıca, doğru yanıtın test / QA / hata ayıklama yapıları ve üretim / bırakma yapıları arasında çok iyi farklılıklar gösterebileceğine dikkat etmek önemlidir. Hata ayıklama yapılarında, bir sorunun olduğu açıkça anlaşılır hale getirmek ve post-mortem'in bunu düzeltmek için ne yapılması gerektiğine karar vermesine izin vermek için çok ayrıntılı hata mesajlarıyla erken ve zor başarısızlığa uğrayacağım. Üretim, güvenli bir şekilde kurtarılabilir hatalarla karşılaştığında, muhtemelen kurtarmayı desteklemelidir.


Tabii ki zinciri işleyen genel bir hata var. Günlüklerle ilgili sorun, uzun zamandır onları kontrol edecek kimsenin bulunmaması olabilir.
Stilgar

@Stilgar, günlükleri kontrol edecek kimse yoksa, o zaman bu boş kontrollerin varlığı veya yokluğu ile ilgili bir sorun değildir.
12'de bir CVn

2
Bir problem var. Son kullanıcılar, hatayı gizleyen ve günlüklere yazan boş denetimler varsa sistemin uzun süre doğru çalışmadığını farketmeyebilirler.
Stilgar

@Stilgar, bu tamamen hatanın niteliğine bağlıdır. Dediğim gibi, yalnızca güvenli bir şekilde devam edebiliyorsanız , beklenmeyen boş değerin değiştirilmesi / göz ardı edilmesi gerekir. Bir sürüm derlemesinde bir başkasının yerine bir görüntü kullanmak (hata ayıklama yapılarında, sorun olabildiğince erken ve mümkün olmadığı kadar başarısız), örneğin bir hesaplama için geçersiz sonuçlar döndürmekten çok farklı bir canavardır. (Bunu dahil etmek için düzenlenmiş cevap.)
08:12

1
Bir şekilde günlüğe kaydetme ve hatayı bildirmediğiniz sürece (bilgili kullanıcılara çok fazla güvenmeden), hızlı ve erken üretimde başarısızlıkla giderim. Konuşlandırılmış böceklerinizi kullanıcılardan gizlemek bir şeydir - onları kendinizden gizlemek tehlikelidir. Ayrıca, kullanıcının ince böceklerle yaşamasına izin vermek, uygulamanıza olan güvenini aşındırabilir. Bazen mermiyi ısırmak ve bir böcek olduğunu ve onu hızlı bir şekilde düzelttiğinizi bildirmek daha iyidir .
Merlyn Morgan-Graham

2

Tabii NULLdeğildir beklendiği , ancak hatalar her zaman vardır!

Beklemiyor olup olmadığını kontrol etmen gerektiğine inanıyorum NULL. Size örnekler vereyim (Java'da olmasalar da).

  • World of Warcraft'ta, bir hata nedeniyle geliştiricilerin birinin görüntüsü birçok nesne için bir küpün üzerinde belirdi. Grafik motorunun işaretçiler beklememesi durumunda NULL, kullanıcı için çok ölümcül (hatta komik) bir deneyime dönüştürülürken bir çarpışma olacağını düşünün . En önemlisi, beklenmedik bir şekilde bağlantınızı veya kaydettiğiniz herhangi bir puanınızı kaybetmemiş olmanızdır.

    Bu, NULL denetlemesinin bir çökmeyi önlediği ve davanın sessizce kullanıldığı bir örnektir.

  • Bir banka vezne programı düşünün. Arayüz bazı kontrolleri yapar ve para transferlerini gerçekleştirmek için girdi verilerini temel bir kısma gönderir. Temel bir parçası değilse beklediğini almamayı NULL, daha sonra arayüzde bir hata (çoğaltılamaz, ya da kötü) kaybolmadan ortada, işlemde muhtemelen biraz para bir soruna neden olabilir.

    "Bir sorun" derken, bir çarpışma demek istiyorum ( çarpışma kazasında olduğu gibi (programın C ++ ile yazıldığını söyleyin), bir boş gösterici istisnası değil). Bu durumda, NULL ile karşılaşıldığında işlemin geri alınması gerekir (değişkenleri NULL'a karşı kontrol etmeseydiniz elbette bu mümkün olmazdı!)

Eminim fikri anlarsın.

İşlevlerin argümanlarının geçerliliğini kontrol etmek kodunuzu bozmaz, çünkü işlevinizin üstündeki bir çift kontrol (ortada yayılmaz) ve sağlamlığı büyük ölçüde artırır.

"Program kullanıcıya başarısız olduğunu ve incelikle kapandığını ya da muhtemelen bir hata günlüğü oluşturan tutarlı bir duruma geri döndüğünü bildirir" ve "Erişim İhlali" arasında bir seçim yapmanız gerekiyorsa, ilkini seçmez misiniz? Bu, her işlevin, her zaman doğru olmasını beklemek yerine , bir hata kodu tarafından çağrılmaya hazır olması gerektiği anlamına gelir .


İkinci örneğiniz bu noktayı onaylamıyor. Bir banka işleminde herhangi bir sorun çıkarsa işlem iptal edilir. Bu, tam olarak, paranın kaybedilmesi veya kopyalanmasıyla ilgili hatayı kapattığınızda gerçekleşir. Null değerinin kontrol edilmesi "Müşteri null para gönderir ... peki ben sadece 10 $ (geliştiricinin görüntüsünün eşdeğeri) gönderirim"
Stilgar

@Stilgar, Aksine! NULL'u kontrol etmek mesajla iptal olur. NULL için kontrol etmemek çarpışmaya neden olur . Şimdi işlemin başındaki çarpışma fena olmayabilir, ama ortada felaket olabilir. (Banka havalesinin oyun gibi bir hatayı idare etmesi gerektiğini söylemedim! Sadece bunun üstesinden gelmesi gerektiği gerçeğini )
Shahbaz

2
Bir "işlemin" amacı, yarı yarıya tamamlanamayacak olmasıdır :) Bir hata varsa o zaman geri alınır.
Stilgar

İşlemsel anlambilimin gerçekte gerekli olduğu her şey için bu korkunç bir tavsiyedir. Tüm işlemlerinizi atomik ve iddiasız hale getirmelisiniz, aksi halde yaptığınız herhangi bir hata kaybolan veya kopyalanan kaynaklar (para) garantisi verir. Atomik olmayan veya iddiasız olmayan işlemlerle uğraşmak zorunda kalırsanız, atomik ve idrarsız davranışı garanti eden katmanlara çok dikkatli sarmalısınız (bu katmanları kendiniz yazmanız gerekse bile). Daima düşün: bu işlem devam ederken bir meteor web sunucusuna isabet ederse ne olur?
Merlyn Morgan-Graham

1
@ MerlynMorgan-Graham, ben yaptım. Umarım karmaşayı temizler.
Shahbaz

2

Diğer cevapların işaret ettiği gibi Eğer beklemiyorsanız NULL, fırlatarak netleştirin ArgumentNullException. Benim düşünceme göre, projeyi debug ederken , program mantığındaki hataları daha erken keşfetmenize yardımcı olur.

Böylece, yazılımınızı yayınlayacaksınız, eğer bu NullRefrenceskontrolleri geri yüklerseniz, yazılımınızın mantığı üzerinde hiçbir şeyi kaçırmazsınız, ciddi bir hatanın ortaya çıkmayacağından emin olmak iki katına çıkar.

Başka bir nokta, eğer NULLkontrol bir fonksiyonun parametreleri üzerinde ise, fonksiyonun bunu yapmak için doğru yer olup olmadığına karar verebilirsiniz; değilse, işleve olan tüm referansları bulun ve sonra bir parametreyi işleve iletmeden önce boş bir referansa yol açabilecek olası senaryoları gözden geçirin.


1

nullSisteminizde her biri keşfedilmeyi bekleyen bir saatli bombadır. Kontrol edin nullsizin kod kontrol etmiyoruz kodu ile etkileşime sınırlarında ve korusun nullkendi kodu içinde. Bu, yabancı kodlara saf bir şekilde güvenmeden sizi rahatsız eder. Bunun yerine istisnalar veya bir çeşit Maybe/ Nothingtürü kullanın.


0

Bir boş gösterici istisnası sonunda atılacak olsa da, genellikle boş göstericiyi aldığınız noktadan uzağa atılır. Kendinize bir iyilik yapın ve en azından bir boş göstericiye gittiğiniz gerçeğini kaydederek hatayı düzeltmek için geçen süreyi kısaltın.

Şimdi ne yapacağınızı bilemeseniz bile, etkinliği kaydetmek size zaman kazandırır. Ve belki de bileti alan adam, uygun cevabı bulmak için harcanan zamanı kullanabilir.


-1

Yana Fail early, fail fastweb uygulaması kural uygulamak gerekir böcek altında iyi çalışması gerekir çünkü olarak @DeadMG (@empi) belirttiği pssible değil

günlüğe kaydetmeden yakalama istisnası yok

bu yüzden geliştiriciler olarak günlükleri inceleyerek olası sorunların farkındasınız.

log4net veya log4j gibi bir günlük kaydı kullanıyorsanız, size hataları ve fataler'leri postalayan ek bir özel günlük çıkışı (aka appender) ayarlayabilirsiniz . bu yüzden bilgili kal .

[Güncelleme]

Sayfanın son kullanıcısı hatanın farkında olmamalıysa, sizi bilgilendiren ve hatalarınızı bildiren bir apender ayarlayabilir.

Sayfanın son kullanıcı şifreli hata mesajları görüyorsa, sayfanın sonuna sayfa işleme için hata günlüğü koyan bir appender ayarlayabilirsiniz.

İstisnayı yutarsanız günlüğü nasıl kullanırsanız kullanın, programm mantıklı olan verilerle devam eder ve yutma artık sessiz değildir.


1
Soru sayfaya ne olur?
Stilgar

Verilerin anlamlı olduğunu ve sistemin tutarlı bir durumda olduğunu nasıl biliyoruz. Tüm hata beklenmedik oldu, bu yüzden etkisinin ne olduğunu bilmiyoruz.
Stilgar

"Erken başarısız olunca, @DeadMG (@empi) 'de belirtildiği gibi hızlı bir şekilde başarısız olunması mümkün değildir, çünkü web uygulaması kuralı uygulamanız gereken hatalar altında iyi çalışmalıdır": Biri tüm istisnaları her zaman yakalayabilir (catch (Throwable t)) ve bazı hata sayfalarına yönlendir. Bu mümkün olmaz mı?
Giorgio

-1

Zaten bu sorunun iyi cevapları var, bunlara bir ek olabilir: Kodumdaki iddiaları tercih ederim. Kodunuz yalnızca geçerli nesnelerle çalışabiliyorsa, ancak boş olan somunlarla çalışıyorsa, boş değeri belirtmeniz gerekir.

Bu tür bir durumla ilgili iddialar, herhangi bir ünitenin ve / veya entegrasyon testinin tam mesajla başarısız olmasına izin verir, böylece üretimden önce sorunu hızla çözebilirsiniz. Eğer böyle bir hata testlerden geçerse ve üretime giderse (iddiaların devre dışı bırakılması gerektiği durumlarda) NpEx ve ciddi bir hata alırsınız, ancak bu daha kötüdür, ancak daha bulanık ve başka bir yerde ortaya çıkan küçük hatalardan daha iyidir. kod ve düzeltmek daha pahalı olurdu.

Dahası, birisi kod iddialarınızla çalışmak zorundaysa, ona kodunuzu tasarlarken / yazarken yaptığınız varsayımlarınız hakkında bilgi verirse (bu durumda: Hey dostum, bu nesnenin sunulması gerekir!), Bu da bakımını kolaylaştırır.


Aşağı oy kullanmak için bir şeyler yazabilir misiniz? Bir tartışma için minnettar olurum. Thanx
GeT

Oy kullanmam, genel fikrine katılıyorum. Dil olsa biraz çalışma gerektiriyor. İddialarınız API'nizin sözleşmesini tanımlar ve bu sözleşmeler ihlal edilirse erken / başarısız olarak başarısız olursunuz. Bunu uygulamanızın derinliklerinde yapmanız, kodunuzun kullanıcılarının kodlarında yanlış bir şey yaptıklarını bilmelerini sağlar. Kodunuzun girintilerinde bir yığın izlerlerse, muhtemelen kodunuzun hatalı olduğunu düşüneceklerdir - ve siz katı bir repro alıp hata ayıklayana kadar siz de düşünebilirsiniz.
Merlyn Morgan-Graham

-1

Normalde null değerlerini kontrol ederim, ancak null değerinin tam olarak nerede gerçekleştiği hakkında biraz daha fazla ayrıntı veren bir istisna atarak beklenmedik null'ları "ele alırım".

Düzenleme: Bir şeyin yanlış olduğunu düşünmüyorsanız boş alırsanız, program ölmeli.


-1

İstisnaların dil uygulamasına bağlıdır. İstisnalar, verilerinizin zarar görmesini önlemek veya sisteminizin beklenmedik bir duruma veya duruma girmesi durumunda kaynakları temiz bir şekilde serbest bırakmak için bazı adımlar atmanıza izin verir. Bu, önceden tahmin edebileceğiniz koşul olan hata işlemeden farklıdır. Benim felsefem, mümkün olduğu kadar az istisna kullanmanız gerektiğidir. Gürültü. Yöntemin istisnayı ele alarak makul bir şey yapabilir mi? Kurtarılabilir mi? Tamir edebilir veya daha fazla hasarı önleyebilir mi? Sadece istisnayı yakalayacak ve sonra yöntemden geri dönecek veya zararsız bir şekilde başarısız olacaksanız, istisnayı yakalamanın hiçbir anlamı yoktu. Yönteminize yalnızca gürültü ve karmaşıklık eklerdiniz ve tasarımınızdaki bir hatanın kaynağını gizliyor olabilirsiniz. Bu durumda, hatanın kabarmasına ve bir dış döngü tarafından yakalanmasına izin verirdim. Bir nesneyi tamir etmek veya bozuk olarak işaretlemek veya kilit dosyası gibi bazı kritik kaynakları serbest bırakmak veya bir soketi temiz bir şekilde kapatmak gibi bir şey yapabilirseniz, bu istisnaların iyi bir şekilde kullanılmasıdır. NULL'ın gerçekten geçerli bir uç durum olarak görünmesini beklerseniz, bunu normal mantık akışında if-else ya da switch-case ifadeleriyle ya da herhangi bir istisna işlemesiyle yapmamalısınız. Örneğin, bir formda devre dışı bırakılmış bir alan boş bırakılmış bir alanı temsil eden boş bir dizgeden farklı olan NULL olarak ayarlanabilir. Bu, iyi yargı ve sağduyu kullanmanız gereken bir alandır. Her durumda bu problemle nasıl başa çıkılacağına dair sağlam kurallar duymadım. Bir nesneyi tamir etmek veya bozuk olarak işaretlemek veya kilit dosyası gibi bazı kritik kaynakları serbest bırakmak veya bir soketi temiz bir şekilde kapatmak gibi bir şey yapabilirseniz, bu istisnaların iyi bir şekilde kullanılmasıdır. NULL'ın gerçekten geçerli bir uç durum olarak görünmesini beklerseniz, bunu normal mantık akışında if-else ya da switch-case ifadeleriyle ya da herhangi bir istisna işlemesiyle yapmamalısınız. Örneğin, bir formda devre dışı bırakılmış bir alan boş bırakılmış bir alanı temsil eden boş bir dizgeden farklı olan NULL olarak ayarlanabilir. Bu, iyi yargı ve sağduyu kullanmanız gereken bir alandır. Her durumda bu problemle nasıl başa çıkılacağına dair sağlam kurallar duymadım. Bir nesneyi tamir etmek veya bozuk olarak işaretlemek veya kilit dosyası gibi bazı kritik kaynakları serbest bırakmak veya bir soketi temiz bir şekilde kapatmak gibi bir şey yapabilirseniz, bu istisnaların iyi bir şekilde kullanılmasıdır. NULL'ın gerçekten geçerli bir uç durum olarak görünmesini beklerseniz, bunu normal mantık akışında if-else ya da switch-case ifadeleriyle ya da herhangi bir istisna işlemesiyle yapmamalısınız. Örneğin, bir formda devre dışı bırakılmış bir alan boş bırakılmış bir alanı temsil eden boş bir dizgeden farklı olan NULL olarak ayarlanabilir. Bu, iyi yargı ve sağduyu kullanmanız gereken bir alandır. Her durumda bu problemle nasıl başa çıkılacağına dair sağlam kurallar duymadım.

Java, bir yöntemde kullanılan nesneler tarafından ortaya çıkabilecek olası istisnaların, yöntemin "atma" maddesinde yakalanması veya bildirilmesi gereken "kontrol edilen istisnalar" ile istisna işleme uygulamasında başarısız olur. C ++ ve Python'un tam tersi, istisnaları uygun gördüğünüz şekilde kullanmayı seçebilirsiniz. Java’da, bir istisna oluşturabilecek bir çağrı içerecek şekilde bir yöntemin gövdesini değiştirirseniz, kodunuza gürültü ve karmaşıklık eklemeyi umursamayacağınız bir istisna için açıkça işleme ekleme seçeneğiyle karşı karşıya kalırsınız veya Bu istisnayı, değiştirdiğiniz yöntemin "fırlatma" yan tümcesine ekleyerek, yalnızca gürültü ve karışıklık eklemekle kalmaz, yönteminizin imzasını da değiştirir. Daha sonra, yönteminizin şimdi kullanabileceği yeni istisnayı ele almak için yönteminizin kullanıldığı yerlerde bir değiştirme koduna gitmelisiniz veya bu yöntemlerin "atma" yan tümcesine istisna ekleyerek kod değişikliklerinin domino etkisini tetiklemelisiniz. "Gereksinimi Yakala veya Belirt", Java'nın en can sıkıcı yönlerinden biri olmalıdır. RuntimeExceptions ve bu tasarım hatası için resmi Java rasyonalizasyonu için istisna istisnası topal değildir.

Bu son paragrafın sorunuzu yanıtlamakla ilgisi yoktu. Sadece Java'dan nefret ediyorum.

- Nuh


Bu yazı okumak oldukça zordur (metin duvarı). Sakıncası var düzenleyebilir daha iyi bir şekle ing?
tatarcık
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.