Kütüphanem için uygulanacak 'iyi sayıda' istisna nedir?


20

Her zaman yazılımımın çeşitli parçaları için kaç farklı istisna sınıfı uygulamam ve atmam gerektiğini merak ettim. Benim özel geliştirme genellikle C ++ / C # / Java ile ilgili, ama bu tüm diller için bir soru olduğuna inanıyorum.

Atmak için çok sayıda farklı istisna ve geliştirici topluluğunun iyi bir kütüphaneden ne beklediğini anlamak istiyorum.

Gördüğüm ödünleşmeler şunları içerir:

  • Daha fazla istisna sınıfı, API kullanıcıları için (kullanıcı yapılandırmasına veya veri hatalarına eğilimli veya bulunmayan dosyalar) çok ince hata düzeylerine izin verebilir
  • Daha fazla istisna sınıfı hataya özel bilgilerin bir dize mesajı veya hata kodu yerine istisna içine gömülmesine izin verir
  • Daha fazla istisna sınıfı, daha fazla kod bakımı anlamına gelebilir
  • Daha fazla istisna sınıfı, API'nın kullanıcılar için daha az ulaşılabilir olduğu anlamına gelebilir

İstisna kullanımını anlamak istediğim senaryolar şunları içerir:

  • 'Yapılandırma' aşamasında, dosya yüklemeyi veya parametre ayarlamayı içerebilir
  • Kütüphanenin görevleri çalıştırdığı ve belki de başka bir iş parçacığında çalıştığı bir 'işlem' türü aşamasında

İstisnalar kullanılmadan veya daha az istisna (karşılaştırma olarak) kullanılmadan diğer hata raporlama kalıpları şunları içerebilir:

  • Daha az istisna, ancak arama olarak kullanılabilecek bir hata kodu gömme
  • Hata kodlarını ve bayrakları doğrudan işlevlerden döndürme (bazen iş parçacıklarından mümkün olmayabilir)
  • Hata durumunda bir olay veya geri çağrı sistemi uygulandı (yığın çözülmesini önler)

Geliştiriciler olarak ne görmeyi tercih ediyorsunuz?

BİRÇOK istisna varsa, bunları ayrı ayrı ele almakta güçlük çekiyor musunuz?

İşlem aşamasına bağlı olarak hata işleme türleri tercihiniz var mı?



5
"API, kullanıcılara daha az ulaşılabilir" - tümü, API için ortak bir temel sınıftan miras alınan birkaç istisna sınıfına sahip olarak ele alınabilir. Ardından, tıpkı başlarken, tüm ayrıntılar için endişelenmenize gerek kalmadan istisnanın hangi API'dan geldiğini görebilirsiniz. API kullanarak ilk programınızı tamamladığınız zaman, hata hakkında daha fazla bilgiye ihtiyacınız varsa, farklı istisnaların gerçekte ne anlama geldiğine bakmaya başlarsınız. Elbette kullandığınız dilin standart istisna hiyerarşisiyle eşzamanlı olarak oynamak zorundasınız.
Steve Jessop

ilgili nokta Steve
Fuzz

Yanıtlar:


18

Basit tutuyorum.

Bir kütüphanenin temel istisna türü std ::: runtime_error (C ++ 'dan diğer dillere uygun olarak uygulanır) ile genişletilir. Bu istisna bir mesaj dizesi alır, böylece giriş yapabiliriz; her atış noktasının benzersiz bir mesajı vardır (genellikle benzersiz bir ID ile).

Bu kadar.

Not 1 : İstisnayı yakalayan birinin istisnaları düzeltebileceği ve eylemi yeniden başlatabileceği durumlarda. Uzak bir konumda potansiyel olarak düzeltilebilecek şeyler için türetilmiş istisnalar ekleyeceğim. Ancak bu çok nadirdir (Yakalayıcının atış noktasına yakın olması muhtemel değildir, bu nedenle problemi düzeltmek zor olacaktır (ancak her şey duruma bağlıdır)).

Not 2 : Bazen kütüphane o kadar basittir ki kendi istisnasını vermeye değmez ve std :: runtime_error yapar. Bir istisnaya sahip olmak, onu std :: runtime_error'dan ayırt etme yeteneği kullanıcıya onunla bir şeyler yapmak için yeterli bilgi verebilirse önemlidir.

Not 3 : Bir sınıfta genellikle hata kodlarını tercih ederim (ancak bunlar asla sınıfımın genel API'sından kaçmayacaktır).

Ticari işlemlerinize bakarken:

Gördüğüm ödünleşmeler şunları içerir:

Daha fazla istisna sınıfı, API kullanıcıları için (kullanıcı yapılandırmasına veya veri hatalarına eğilimli veya bulunmayan dosyalar) çok ince hata düzeylerine izin verebilir

Daha fazla istisna gerçekten daha iyi tahıl kontrolü sağlıyor mu? Soru, alıcı kodun istisnayı temel alarak hatayı gerçekten düzeltebileceği hale gelir. Eminim böyle durumlar vardır ve bu durumlarda başka bir istisnanız olmalıdır. Ancak, yukarıda listelenen tüm istisnalar, tek yararlı düzeltmeyi büyük bir uyarı oluşturmak ve uygulamayı durdurmaktır.

Daha fazla istisna sınıfı hataya özel bilgilerin bir dize mesajı veya hata kodu yerine istisna içine gömülmesine izin verir

Bu, istisnaları kullanmak için harika bir nedendir. Ancak bilgi önbelleğe alan kişi için yararlı olmalıdır. Bilgileri bazı düzeltici eylemleri gerçekleştirmek için kullanabilirler mi? Nesne kitaplığınızın içindeyse ve herhangi bir API'yi etkilemek için kullanılamıyorsa, bilgiler işe yaramaz. Atılan bilgilerin, onu yakalayabilen kişiye faydalı bir değere sahip olması konusunda çok spesifik olmanız gerekir. Onu yakalayan kişi genellikle herkese açık API'nızın dışındadır, bu nedenle herkese açık API'nızdaki şeylerle kullanılabilmesi için bilgilerinizi özelleştirin.

Tek yapabilecekleri istisnayı günlüğe kaydetmekse, çok fazla veri yerine bir hata mesajı atmak en iyisidir. Yakalayıcı genellikle verilerle bir hata mesajı oluşturacaktır. Hata mesajını oluşturursanız, tüm alıcılarda tutarlı olacaktır, eğer yakalayıcının hata mesajını oluşturmasına izin verirseniz, aynı hatayı kimin aradığını ve yakaladığına bağlı olarak farklı şekilde bildirebilirsiniz.

Daha az istisna, ancak arama olarak kullanılabilecek bir hata kodu gömme

Hata kodunun anlamlı bir şekilde kullanılabileceği hava durumunu belirlemelisiniz. Eğer yapabilirse, kendi istisnasına sahip olmalısınız. Aksi takdirde, kullanıcılarınızın artık bu catch içinde anahtar deyimleri uygulaması gerekir (bu, catchin otomatik olarak işlenmesinin tüm noktasını yener).

O zaman neden istisnada bir hata mesajı kullanmıyorsanız (kodu ve mesajı bölmeye gerek yoktur, bu onu aramak için acı verir).

Hata kodlarını ve bayrakları doğrudan işlevlerden döndürme (bazen iş parçacıklarından mümkün olmayabilir)

Hata kodlarını döndürmek dahili olarak harika. Buradaki hataları düzeltmenize izin verir ve tüm hata kodlarını düzelttiğinizden ve bunları hesaba kattığınızdan emin olmanız gerekir. Ancak herkese açık API'nızda sızdırmak kötü bir fikirdir. Sorun, programcıların genellikle hata durumlarını kontrol etmeyi unutmalarıdır (en azından bir istisna dışında, kontrol edilmemiş bir hata, uygulamayı işlenmeyen bir hatadan çıkmaya zorlar) genellikle tüm verilerinizi bozar).

Hata durumunda bir olay veya geri çağrı sistemi uygulandı (yığın çözülmesini önler)

Bu yöntem genellikle diğer hata işleme mekanizmalarıyla birlikte kullanılır (alternatif olarak değil). Windows programınızı düşünün. Kullanıcı bir menü öğesi seçerek bir eylem başlatır. Bu, olay kuyruğunda bir eylem oluşturur. Olay kuyruğu sonunda eylemi işlemek için bir iş parçacığı atar. İş parçacığının eylemi gerçekleştirmesi ve sonunda iş parçacığı havuzuna dönmesi ve başka bir görev beklemesi gerekir. Burada işle görevlendirilmiş iş parçacığı tarafından tabana bir istisna yakalanmalıdır. Kural dışı durumun yakalanması sonucu genellikle ana döngü için oluşturulan ve sonuçta kullanıcıya bir hata mesajının görüntülenmesine neden olan bir olayla sonuçlanır.

Ancak istisna karşısında devam edemezseniz, yığın gevşeyecektir (en azından iş parçacığı için).


+ 1; Tho "Aksi takdirde, kullanıcılarınızın artık buradaki catch deyimlerini uygulaması gerekir (bu, catch'in otomatik olarak işlenmesinin tüm noktasını yener)." - Çağrı yığını çözme (hala kullanabiliyorsanız) ve zorla hata işleme hala büyük fayda sağlar. Ancak, ortada yakalamanız ve tekrar dinlemeniz gerektiğinde, çağrı yığını gevşetme yeteneğinden uzaklaşacaktır.
Merlyn Morgan-Graham

9

Genellikle ile başlarım:

  1. Bağımsız değişken hataları için bir istisna sınıfı . Örneğin, "argümanın boş olmasına izin verilmez", "argüman pozitif olmalı" vb. Java ve C # bunlar için önceden tanımlanmış sınıflara sahiptir; C ++ genellikle std :: exception türetilmiş, sadece bir sınıf oluşturmak.
  2. Önkoşul hataları için bir istisna sınıfı . Bunlar "dizin boyuttan daha küçük olmalıdır" gibi daha karmaşık testler içindir.
  3. Onaylama hataları için bir istisna sınıfı . Bunlar, devletin yarı-istikrarlı yöntemlerde olup olmadığını kontrol etmek içindir. Örneğin, negatif, sıfır veya pozitif öğeleri saymak için bir listeyi yinelediğinde, sonunda bu üç boyutun boyutuna eklenmesi gerekir.
  4. Kütüphanenin kendisi için bir temel istisna sınıfı . İlk başta, sadece bu sınıfı atın. Yalnızca ihtiyaç duyulduğunda alt sınıflar eklemeye başlayın.
  5. İstisnaları sarmamayı tercih ederim, ancak görüşlerin bu noktada farklı olduğunu biliyorum (ve kullanılan dil ile çok ilişkili). Kaydırırsanız, ek sarma istisna sınıflarına ihtiyacınız olacaktır .

İlk 3 vaka için sınıflar hata ayıklama yardımcıları olduğundan, kod tarafından ele alınmaları amaçlanmamıştır. Bunun yerine, yalnızca kullanıcının geliştiriciye kopyalayıp yapıştırabileceği (veya daha da iyisi: "rapor gönder" düğmesine basın) bilgileri görüntüleyen bir üst düzey işleyici tarafından yakalanmalıdır. Bu nedenle geliştirici için yararlı bilgiler ekleyin: dosya, işlev, satır numarası ve hangi denetimin başarısız olduğunu açıkça belirten bazı mesajlar.

İlk 3 vaka her proje için aynı olduğundan, C ++ 'da genellikle bunları önceki projeden kopyalarım. Birçoğu aynı şeyi yaptığından, C # ve Java tasarımcıları bu durumlar için standart sınıfları standart kütüphaneye ekledi. [GÜNCELLEME:] Tembel programcılar için: bir sınıf yeterli olabilir ve bazı şanslarla standart kütüphaneniz zaten uygun bir istisna sınıfına sahiptir. Dosya adı ve linenumber, C ++ varsayılan sınıfları sağlamayan bilgi eklemeyi tercih ederim. [Güncellemeyi sonlandır]

Kütüphaneye bağlı olarak, dördüncü durum sadece bir sınıfa sahip olabilir ya da bir sınıf ders olabilir. İhtiyaç olduğunda alt sınıflar ekleyerek çevik yaklaşımın basit başlamasını tercih ederim.

Dördüncü vakam hakkında ayrıntılı bir tartışma için Loki Astari'nin cevabına bakınız . Ayrıntılı cevabına tamamen katılıyorum.


+ 1; Bir çerçevede yazma istisnalarını nasıl yazmanız gerektiği ile bir uygulamada istisnaları nasıl yazmanız gerektiği arasında kesin bir fark vardır. Ayrım biraz bulanık, ama bundan bahsediyorsunuz (kütüphane davası için Loki'ye erteleniyor).
Merlyn Morgan-Graham
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.