İyi bir istisna mesajı nasıl yazılır


101

Şu anda bir kod incelemesi yapıyorum ve dikkatimi çektiğim şeylerden biri, istisna mesajının sadece istisnanın gerçekleştiği yeri tekrar ettiği görünen istisnaların sayısı. Örneğin

throw new Exception("BulletListControl: CreateChildControls failed.");

Bu mesajdaki her üç madde de istisna dışında çalışabiliyor. Sınıfı ve yöntemi yığın izlemeden biliyorum ve başarısız olduğunu biliyorum (çünkü bir istisna buldum).

İstisna mesajlarına hangi mesajı koyduğumu düşündürdü. Öncelikle, eğer zaten mevcut değilse, genel bir nedenden dolayı (örneğin PropertyNotFoundException- neden ) bir istisna sınıfı yaratıyorum ve sonra onu attığımda mesaj neyin yanlış gittiğini gösteriyor (örn., "Düğüm 1234'te" "IDontExist" özelliği bulunamıyor " "- ne ). Nerede olduğunu StackTrace. Ne zaman kütükte bitebilir (eğer varsa). Nasıl olduğunu geliştirici egzersiz (ve düzeltmek) için

İstisnaları atmak için başka ipucunuz var mı? Özellikle yeni tipler oluşturma ve istisna mesajı ile ilgili olarak.


4
Bunlar günlük dosyaları için mi yoksa kullanıcıya sunulması mı?
Jon Hopkins,

5
Sadece hata ayıklama için. Bir kütüğe girebilirler. Kullanıcıya sunulmayacaklardı. İstisna mesajlarını kullanıcıya sunma hayranı değilim.
Colin Mackay

Yanıtlar:


70

Cevabımı bir istisnadan sonra ne olacağına daha fazla yönlendireceğim: bu ne işe yarar ve yazılım nasıl davranmalı, kullanıcılarınız istisna ile ne yapmalı? Kariyerimde erken karşılaştığım harika bir teknik, her zaman sorunları ve hataları 3 kısımda bildirmekti: bağlam, problem ve çözüm. Bu disiplini kullanmak hata işlemesini büyük ölçüde değiştirir ve yazılımı operatörlerin kullanması için çok daha iyi hale getirir.

İşte birkaç örnek.

Context: Saving connection pooling configuration changes to disk.
Problem: Write permission denied on file '/xxx/yyy'.
Solution: Grant write permission to the file.

Bu durumda, operatör tam olarak ne yapacağını ve hangi dosyanın etkilenmesi gerektiğini bilir. Ayrıca, bağlantı havuzu değişikliklerinin değişmediğini ve tekrarlanması gerektiğini de biliyorlar.

Context: Sending email to 'abc@xyz.com' regarding 'Blah'.
Problem: SMTP connection refused by server 'mail.xyz.com'.
Solution: Contact the mail server administrator to report a service problem.  The email will be sent later. You may want to tell 'abc@xyz.com' about this problem.

Sunucu tarafı sistemleri yazıyorum ve operatörlerim genellikle teknoloji meraklısı ilk hat desteği. Farklı kitlelere sahip olan ancak aynı bilgileri içeren masaüstü yazılımı için mesajları farklı yazardım.

Biri bu tekniği kullanırsa birkaç harika şey olur. Yazılım geliştirici genellikle problemleri kendi kodlarında nasıl çözeceklerini bilmek için yerleştirilir, bu yüzden kodları yazarken kodlama çözümleri bu şekilde dezavantajlı bir şekilde çözüm bulma konusunda sıkıntı çeken son kullanıcılar için büyük yarar sağlar. Yazılımın tam olarak ne yaptığını. Oracle hata mesajını daha önce okuyan herkes ne demek istediğimi anlayacaktır.

Akla gelen ikinci harika şey, kendinize bir istisnada bir çözüm tanımlamaya çalışırken kendinizi bulduğunuzda ve "X'i kontrol et ve A sonra B başkası C" yazıyor olmanızdır. Bu, istisnanızın yanlış yerde kontrol edildiğinin açık ve açık bir işaretidir. Siz programcının koddaki şeyleri karşılaştırma kapasitesine sahip olduğunuzdan dolayı “eğer” ifadeleri kodda çalıştırılmalı, neden kullanıcıyı otomatik hale getirilebilecek bir şeye dahil etmelisiniz? Şansı o kodda derin geliyor ve birisi yeterince neyin yanlış gittiğini tarif edemez kodu çağıran bir blok içinde hepsi potansiyel hataları tembel şey yapmış ve yöntemlerin herhangi sayıda IOException atılmış ve yakalamış nelerdir özgübağlam ve nasıl düzeltilir. Bu, daha ince tanecik hataları yazmanızı, kodunuzda doğru yerde yakalamanızı ve ele almanızı sağlar; böylece operatörün atması gereken adımları doğru şekilde anlayabilirsiniz.

Bir şirkette, yazılımı gerçekten iyi tanıyan ve hata raporlamamızı güçlendiren ve çözümler öneren kendi “çalışma kitaplarını” tutan birinci sınıf operatörler vardı. Bunu tanımak için yazılım istisnalar dışında çalışma kitabına wiki bağlantıları dahil etmeye başladı, böylece temel bir açıklama mevcuttu ve zaman içinde operatörler tarafından daha ileri görüşmelere ve gözlemlere bağlantılar yapıldı.

Bu tekniği denemek için bir disipline sahipseniz, kendinize ait bir kod oluştururken istisnalarınızı kodlamanız gerekenler çok daha belirgin hale gelir. NonRecoverableConfigurationReadFailedException , operatöre tam olarak tanımlayacağınız şey için biraz kısa yol açar. Ayrıntılı olmayı seviyorum ve kodumu yorumlayacak bir sonraki geliştiricinin daha kolay olacağını düşünüyorum.


1
+1 Bu iyi bir sistem. Hangisi daha önemlidir: Bilginin geçtiğinden emin olmak mı yoksa kısa kelimeler kullanmak mı?
Michael K,

3
+1 için bağlam, sorun, çözümü de içeren çözümü
severim

1
Bu teknik çok faydalıdır. Kesinlikle onu kullanacağım.
Çocuk Pırlanta

Bağlam gereksiz veridir. Yığın izinde zaten mevcut. Çözeltiye sahip olmak tercih edilir ancak her zaman mümkün / faydalı değildir. Çoğu sorunları tür incelikle uygulamayı durdurmak veya bekleyen işlemler göz ardı edip geri uygulama ana yürütme döngüye dahaki sefere bu durum sınıfın ismi böyle olmalı ... başarılı umuyor çözüm için bariz hale gelecektir FileNotFoundya ConnectException)) ne yapacağını bilmek
gavenkoa

2
@ThomasFlinkow Örneğinizde izleri yığın izlemede init (), execute () ve cleanup () olacaktır. Kitaplıktaki iyi adlandırma şeması ve temiz / anlaşılır API ile dize açıklamalarına ihtiyacınız yoktur. Ve hızlı bir şekilde başarısız olun, sistemin her tarafına bozuk devlet taşımayın. Benzersiz tanıtıcılı kayıtların izlenmesi ve günlüğe kaydedilmesi uygulama akışını / durumunu açıklayabilir.
gavenkoa

23

Gelen bu daha yeni soruya ben istisnalar hiç bir ileti içermemeli noktası yaptı. Kanımca, yaptıkları gerçeği çok büyük bir yanılgıdır. Teklif ettiğim şey bu

İstisnanın "mesajı", istisnanın (tam nitelikli) sınıf adıdır .

Bir istisna, tam olarak ne olduğu hakkında kendi üye değişkenlerinde mümkün olduğunca fazla ayrıntı içermelidir; örneğin, IndexOutOfRangeExceptiongeçersiz olduğu tespit edilen endeks değerini ve istisnanın atıldığı anda geçerli olan üst ve alt değerleri içermesi gerekir. Bu şekilde, yansıma kullanarak otomatik olarak şöyle bir mesaj yazabilirsiniz: IndexOutOfRangeException: index = -1; min=0; max=5ve bu, yığın izi ile birlikte, sorunu gidermek için ihtiyaç duyduğunuz tüm objektif bilgiler olmalıdır. "İndex -1, 0 ile 5 arasında değildi" gibi güzel bir mesaja biçimlendirmek, herhangi bir değer katmaz.

Özel örneğinizde, NodePropertyNotFoundExceptionsınıf bulunamayan özelliğin adını ve özelliği içermeyen düğüme bir başvuru içerir. Bu önemlidir: bu olmalı değil düğümün adını içermelidir; gerçek düğüme bir referans içermelidir. Özel durumunuzda bu gerekli olmayabilir, ancak bu bir prensip meselesi ve tercih edilen bir düşünce şeklidir: Bir istisna oluştururken öncelikli endişe, onu yakalayabilecek kodla kullanılabilir olması gerektiğidir. İnsanlar tarafından kullanılabilirlik önemli, ancak yalnızca ikincil bir sorundur.

Bu, kariyerinizde belirli bir noktada tanık olabileceğiniz çok sinir bozucu durumla ilgilenir, burada mesaj metninde neler olduğu hakkında hayati bilgiler içeren bir istisna yakalamış olabilirsiniz, ancak üye değişkenlerinde değil mesaj metninin altta yatan katmanın gelecekteki sürümlerinde aynı kalacağını ümit ederek, metnin dizgeyi ayrıştırması ve programın, diğer ülkelerde koşmak.

Tabii ki, istisnanın sınıf adı istisnanın mesajı olduğundan, (ve istisnanın üye değişkenleri de özel detaylardır), bu, tüm farklı mesajları iletmek için çok sayıda ve çok sayıda istisnaya ihtiyacınız olduğu anlamına gelir ve bu iyi.

Şimdi, bazen kod throwyazarken, bir ifadeyi hızlı bir şekilde kodlamak ve yeni bir istisna sınıfı oluşturmak için yaptığımız işi kesmek yerine kodumuzu yazmaya devam etmek istediğimiz hatalı bir durumla karşı karşıya kalıyoruz. oraya at. Bu gibi durumlarda, GenericExceptionbir dize mesajını bir inşaat zamanı parametresi olarak kabul eden bir sınıfa sahibim , ancak bu istisna sınıfının kurucusu, bu sınıfın FIXME XXX TODOher bir örneğinin olması gerektiğini belirten büyük, büyük, parlak, parlak bir yorumla süslenmiştir . yazılım sistemi piyasaya sürülmeden önce, tercihen kodun işlenmesinden önce, bazı daha özel istisna sınıflarının bir örneği ile değiştirildi.


8
GC'si olmayan bir dilde, C ++ gibi bir dilde iseniz, rastgele verilere referansları yığını gönderdiğiniz istisnalar içine koymak konusunda çok dikkatli olmalısınız. Muhtemelen, neye atıfta bulunursanız olun, istisna yakalandığı zaman yok edildi.
Sebastian Redl,

4
@SebastianRedl Doğru. Aynı şey, nodenesne bir kullanılıp atılan (C # ile) veya kaynakları ile dene (Java'da) yan tümcesi tarafından korunuyorsa C # ve Java için de geçerli olabilir : istisna dışında saklanan nesne, yasadışı hale getirilerek imha edilir / kapatılır İstisnaların işlendiği yerde herhangi bir yararlı bilgi almak için erişmek. Bu durumlarda, nesnenin kendisinin yerine istisnanın içinde bir çeşit özetin saklanması gerektiğini düşünüyorum. Bunu tüm durumlar için genel olarak ele almanın aptal bir yolunu düşünemiyorum.
Mike Nakis

13

Genel bir kural olarak, bir istisna, geliştiricilerin yararlı bilgiler vererek (beklenen değerler, gerçek değerler, olası nedenler / çözümler vb.) Sebebi belirlemelerine yardımcı olmalıdır .

Yerleşik türlerden hiçbiri bir şey ifade etmediğinde yeni istisna türleri oluşturulmalıdır . Belirli bir tür, diğer geliştiricilerin belirli bir istisnayı yakalamasını ve ele almasını sağlar. Eğer geliştirici istisnanızla nasıl başa çıkacağınızı bilirse, ancak tip ise Exception, uygun şekilde kullanamayacaktır.


+1 - beklenen değerler - gerçek değerler son derece kullanışlıdır. Soruda verilen örnekte, basitçe bir yöntemin başarısız olduğunu söylememelisiniz, ama neden başarısız oldu (temelde, başarısız olan tam komut ve başarısızlığa neden olan koşullar.)
Felix Dombek

4

. NET'te hiç yapma throw new Exception("...")(sorunun yazarı gibi). İstisna, kök İstisna türüdür ve doğrudan atılmaması gereken bir durumdur. Bunun yerine, türetilmiş .NET istisna türlerinden birini atın veya İstisna'dan (veya başka bir istisna türünden) kaynaklanan özel bir istisna oluşturun.

Neden İstisna atmıyorsun? Çünkü İstisna atmak, istisnanızı tanımlamak için hiçbir şey yapmaz ve arama kodunuzu catch(Exception ex) { ... }, genellikle iyi bir şey olmayan bir kod yazmaya zorlar ! :-).


2

İstisnaya "eklemek" istediğiniz şeyler istisna ya da yığın izinde doğal olmayan veri unsurlarıdır. Bunların "mesajın" bir parçası olup olmadığı ya da giriş yapılırken eklenmeleri gerekip gerekmediği ilginç bir sorudur.

Daha önce not ettiğiniz gibi, istisna muhtemelen size ne olduğunu söyler, istifleme muhtemelen size nerede olduğunu ancak "neden" in bir veya iki satırda eşlik etmekten ve "söylemekten daha fazla dahil olabileceğini (olması gerektiği gibi)" olduğunu söyler Doh! Elbette ". Bu, üretim kodundaki hataları kaydederken daha da doğrudur - Sık sık test sistemlerimizde bulunmayan canlı bir sisteme giden kötü veriler yüzünden ısırıldım. Veritabanındaki kaydın kimliğinin ne olduğunu bilmek kadar basit olan, hataya neden olan (veya katkıda bulunan), önemli miktarda zaman kazandırabilir.

Yani ... Ya listelenen ya da .NET için kayıtlı istisnalar veri koleksiyonuna eklendi (cf @Plip!):

  • Parametreler (bu biraz ilginç olabilir - serileştirilmezse veri toplamaya ekleyemezsiniz ve bazen tek bir parametre şaşırtıcı şekilde karmaşık olabilir)
  • ADO.NET veya Linq tarafından SQL veya benzerlerine döndürülen ek veriler (bu biraz ilginç de olabilir!).
  • Başka hiçbir şey görünmeyebilir.

Elbette bazı şeyler, ilk hata raporunuzda / logunuzda bulunmadıkça ihtiyacınız olmadığını bilemezsiniz. Farkında olmadığınız bazı şeyler, ihtiyacınız olduğunu bulana kadar elde edebilirsiniz.


0

İstisnalar nelerdir için ?

(1) Kullanıcıya bir şeylerin yanlış gittiğini söylemek mi?

Bu, son çare olmalı, çünkü kodunuz birbiriyle çakışmalı ve bunlara bir İstisna'dan daha iyi bir şey göstermelidir.

"Hata" mesajı, neyin yanlış gittiğini ve bir şey olursa, kullanıcının hata durumundan kurtulmak için ne yapabileceğini açıkça ve kısaca belirtmelidir .

örneğin "Lütfen bu tuşa tekrar basmayın"

(2) Bir Geliştiriciye ne zaman yanlış gittiğini söylemek?

Bu, daha sonraki analizler için bir dosyaya girdiğiniz türden bir şeydir. Yığın İzleme Geliştirici söyleyecektir kodu kırdı; Mesaj yine neyin yanlış gittiğini göstermelidir .

(3) Bir İstisna işleyicisine (yani kod) bir şeyin ters gittiğini söylemek mi?

Tip İstisna bakmak alacak ve hangi istisna işleyicisi karar verecek özellikler İstisna nesne üzerinde tanımlı işleyicisi onunla başa sağlayacaktır.

İstisna'nın mesajı tamamen ilgisizdir .


-3

Yardım edebilirseniz yeni türler oluşturmayın. Ekstra karışıklığa, karmaşıklığa neden olabilir ve daha fazla kodun korunmasına yol açabilir. Kodunuzun uzatılması gerekebilir. Bir istisna hiyerarşisi tasarlamak çok fazla şey ve test gerektirir. Bu bir düşünce sonrası değil. Dahili dil istisna hiyerarşisini kullanmak genellikle en iyisidir.

İstisna mesajının içeriği mesajın alıcısına bağlıdır - bu yüzden kendinizi o kişinin ayakkabılarına koymak zorundasınız.

Bir destek mühendisinin hatanın kaynağını en kısa sürede tanımlayabilmesi gerekir. Kısa bir açıklayıcı dize artı sorunu gidermeye yardımcı olabilecek tüm verileri ekleyin. Her zaman yığın izini dahil et - eğer yapabilirsen - bu tek gerçek bilgi kaynağı olacak.

Hataları sisteminizin genel kullanıcılarına sunmak, hatanın türüne bağlıdır: kullanıcı sorunu çözebiliyorsa, örneğin farklı girdiler sağlayarak, kısa ve açıklayıcı bir mesaj gerekir. Kullanıcı sorunu çözemezse, bir hatanın meydana geldiğini belirtmek ve bunu desteklemek için bir hatayı günlüğe kaydetmek / göndermek (yukarıdaki yönergeleri kullanarak) en iyisidir.

Ayrıca - büyük bir "HALT ERROR!" simgesi. Bu bir hata - bu dünyanın sonu değil.

Özetle: aktörleri düşünün ve sisteminiz için durumları kullanın. Kendinizi bu kullanıcının ayakkabılarına yerleştirin. Yardımcı ol. Nazik ol. Sistem tasarımınızda bunu ön tarafa düşünün. Kullanıcılarınızın bakış açısına göre - bu istisna durumları ve sistemin onları nasıl ele aldığı, sisteminizdeki normal durumlar kadar önemlidir.


10
Katılmıyorum. Dil API'si ihtiyaçlarınızı tam olarak karşılamadığında kendi istisnalarınızı uygulamanın birçok iyi nedeni vardır. Bunun bir nedeni, birden fazla şeyin başarısız olabileceği bir yöntemde, farklı istisna türleri için farklı yakalama cümleleri yazabilmenizdir; Bir diğeri, farklı soyutlama katmanlarını temsil eden çok sayıda istisna katmanını ayırabileceğiniz, bir istisnanın ait olduğu tam katmanın türünde kodlanabileceği durumdur. Sadece "İstisna" veya "IllegalStateException" kullanarak bir mesaj dizesi orada pek yardımcı olmuyor.
Felix Dombek,

1
Ben de aynı fikirde değilim. İstisna türleri, onu tüketecek olan arama koduna mantıklı gelmelidir. Örneğin, bir çerçeveyi çağırıyorsam ve bu dahili olarak bir FileDoesNotExistException'a neden oluyorsa, bu benim için çerçevenin arayanı olarak bir anlam ifade etmeyebilir. Bunun yerine, bir özel istisna oluşturmak ve atılan istisnadan iç istisna olarak geçmek daha iyi olabilir.
bytedev
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.