Es scheint eine gewisse Übereinstimmung zu bestehen, dass Ausnahmemeldungen nützliche Details enthalten sollten .
Warum enthalten viele häufige Ausnahmen von Systemkomponenten keine nützlichen Details?
Einige Beispiele:
- Der .NET-
List
IndexzugriffArgumentOutOfRangeException
gibt weder den Indexwert an, der versucht wurde und ungültig war, noch den zulässigen Bereich. - Grundsätzlich sind alle Ausnahmenachrichten aus der MSVC C ++ - Standardbibliothek völlig unbrauchbar (in der gleichen Weise wie oben).
- Oracle-Ausnahmen in .NET, die Ihnen (umschrieben) mitteilen, dass "TABLE OR VIEW not found" (Tabelle oder Ansicht nicht gefunden), aber nicht welche .
Aus diesem Grund scheint es mir, dass Ausnahmemeldungen zum größten Teil nicht genügend Details enthalten, um nützlich zu sein. Entsprechen meine Erwartungen nicht den Erwartungen? Benutze ich Ausnahmen falsch, dass ich das überhaupt bemerke? Oder vielleicht mein Eindruck ist falsch: eine Mehrheit von Ausnahmen Sie bieten tatsächlich nützliche Details?
c#
c++
exceptions
Martin Ba
quelle
quelle
Antworten:
Ausnahmen enthalten keine nützlichen Details, da das Konzept der Ausnahmen in der Softwareentwicklungsdisziplin noch nicht ausreichend ausgereift ist, so dass viele Programmierer sie nicht vollständig verstehen und sie daher nicht richtig behandeln.
Ja,
IndexOutOfRangeException
sollte den genauen Index enthalten, der außerhalb des gültigen Bereichs lag, sowie den Bereich, der zum Zeitpunkt des Auslösens gültig war, und ist für die Ersteller der .NET-Laufzeit verächtlich, sofern dies nicht der Fall ist. Ja, dietable or view not found
Ausnahme von Oracle sollte den Namen der Tabelle oder Sicht enthalten, die nicht gefunden wurde, und auch die Tatsache, dass sie für den Verantwortlichen nicht verächtlich ist.Zu einem großen Teil rührt die Verwirrung von der fehlgeleiteten ursprünglichen Idee her, dass Ausnahmen von Menschen lesbare Botschaften enthalten sollten, was wiederum darauf zurückzuführen ist, dass man nicht weiß, worum es sich bei Ausnahmen handelt. Es handelt sich also um einen Teufelskreis.
Da die Menschen der Meinung sind, dass die Ausnahme eine für Menschen lesbare Nachricht enthalten sollte, sind sie der Ansicht, dass die von der Ausnahme übermittelten Informationen auch in der für Menschen lesbaren Nachricht formatiert werden sollten. Dann ist es ihnen entweder langweilig, alle für Menschen lesbaren Nachrichten zu schreiben. oder sie befürchten, dass dadurch eine nicht zu empfehlende Menge an Informationen an neugierige Augen weitergegeben wird, die die Nachricht möglicherweise sehen. (Die in anderen Antworten genannten Sicherheitsprobleme.)
Die Wahrheit ist jedoch, dass sie sich darüber keine Sorgen machen sollten, da die Ausnahme keine für Menschen lesbare Botschaft enthalten sollte. Ausnahmen sind Dinge, die nur Programmierer jemals sehen und / oder behandeln sollten. Wenn es jemals notwendig sein sollte, einem Benutzer Fehlerinformationen zu präsentieren, muss dies auf sehr hohem Niveau, auf raffinierte Weise und in der Sprache des Benutzers erfolgen, die statistisch gesehen wahrscheinlich nicht Englisch ist.
Für uns Programmierer ist die "Nachricht" der Ausnahme der Klassenname der Ausnahme , und alle anderen Informationen, die für die Ausnahme relevant sind, sollten in (endgültige / schreibgeschützte) Mitgliedsvariablen des Ausnahmeobjekts kopiert werden. Am liebsten ist jedes einzelne denkbare bisschen davon. Auf diese Weise muss (oder sollte) keine Nachricht generiert werden, und daher können keine neugierigen Augen sie sehen.
Um auf die Besorgnis einzugehen, die Thomas Owens in einem der folgenden Kommentare zum Ausdruck gebracht hat:
Ja, natürlich, auf einer bestimmten Ebene, Sie werden eine Log - Nachricht in Bezug auf die Ausnahme erstellen. Aber Sie sehen bereits das Problem mit dem, was Sie sagen: Einerseits ist eine Ausnahmeprotokollnachricht ohne Stapelablaufverfolgung nutzlos, andererseits möchten Sie dem Benutzer nicht die gesamte Ausnahme-Stapelablaufverfolgung anzeigen lassen. Auch hier besteht unser Problem darin, dass unsere Perspektive durch traditionelle Praktiken verzerrt wird. Protokolldateien wurden traditionell im Nur-Text-Format erstellt, was vielleicht in den Kinderschuhen unserer Disziplin in Ordnung war, aber vielleicht auch nicht mehr: Wenn Sicherheitsbedenken bestehen, muss die Protokolldatei binär und / oder verschlüsselt sein.
Unabhängig davon, ob es sich um Binär- oder Nur-Text-Dateien handelt, sollte die Protokolldatei als Stream betrachtet werden, in den die Anwendung die Debuginformationen serialisiert. Ein solcher Stream ist nur für die Augen des Programmierers bestimmt, und das Generieren von Debugging-Informationen für eine Ausnahme sollte so einfach wie das Serialisieren der Ausnahme in den Debug-Protokoll-Stream sein. Auf diese Weise sehen Sie im Protokoll den Namen der Ausnahmeklasse (der, wie ich bereits ausgeführt habe, für alle praktischen Zwecke "die Nachricht" ist). und praktisch, um in ein Protokoll aufzunehmen, und die gesamte Stapelverfolgung. Beachten Sie, dass die Formatierung einer für Menschen lesbaren Ausnahmemeldung in diesem Prozess auffällig fehlt .
PS
Ein paar meiner Gedanken zu diesem Thema finden Sie in dieser Antwort: Wie schreibe ich eine gute Ausnahmebedingungsnachricht?
PPS
Es scheint, dass viele Leute von meinem Vorschlag zu binären Protokolldateien abgehakt wurden, deshalb habe ich die Antwort noch einmal geändert, um noch klarer zu machen, dass ich hier nicht vorschlage, dass die Protokolldatei binär sein soll, sondern dass Die Protokolldatei kann bei Bedarf binär sein.
quelle
Nach meiner Erfahrung gibt es eine Reihe von Gründen, aus denen Ausnahmen keine nützlichen Informationen enthalten. Ich gehe davon aus, dass diese Gründe auch für Systemkomponenten gelten - aber ich weiß es nicht genau.
Irgendwie? Ich meine, Ausnahmen sollten nette Nachrichten haben, aber sie sind auch Ausnahmen . Sie sollten Ihre Zeit damit verbringen, Code zu entwerfen, um außergewöhnliche Bedingungen zu vermeiden, oder Code zu schreiben, um außergewöhnliche Bedingungen zu behandeln (die Nachricht zu ignorieren), und sie nicht als eine Art interaktiven Feedback-Mechanismus beim Codieren verwenden. Es ist unvermeidlich, sie für Debugging-Zwecke zu verwenden, aber in den meisten Situationen sollte dies auf ein Minimum beschränkt werden. Dass Sie dieses Problem bemerken, macht mir Sorgen, dass Sie nicht gut genug daran arbeiten, es zu verhindern.
quelle
Ich habe nicht viel Erfahrung mit C # oder C ++, aber ich kann Ihnen das sagen - von Entwicklern geschriebene Ausnahmen 9 von 10 sind nützlicher als jede generische Ausnahme, die Sie jemals finden werden.
Im Idealfall zeigt eine generische Ausnahme genau an, warum der Fehler aufgetreten ist, und Sie können ihn problemlos beheben - realistisch gesehen jedoch in großen Anwendungen mit mehreren Klassen, die eine Vielzahl verschiedener Arten von Ausnahmen auslösen können gleiche Art von Ausnahmen abgesehen, ist es immer wertvoller Ihren eigenen Ausgang für Fehler Rückkehr zu schreiben , als es auf der Standard - Nachricht verlassen ist.
Dies ist , wie es sein sollte, weil so viele Leute haben darauf hingewiesen, einige Anwendungen nicht wollen eine Fehlermeldung werfen , dass sie nicht sehen , der Benutzer möchte, aus Sicherheitsgründen oder zu vermeiden , dass sie verwirrend.
Stattdessen sollten Sie in Ihrem Entwurf vorhersehen, welche Arten von Fehlern in Ihrer Anwendung auftreten können (und es treten immer Fehler auf), und Fehlermeldungen verfassen, die Sie bei der Identifizierung des Problems unterstützen.
Dies wird Ihnen nicht immer weiterhelfen, da Sie nicht immer vorhersehen können, welche Fehlermeldung nützlich sein wird. Es ist jedoch der erste Schritt, um Ihre eigene Anwendung langfristig besser zu verstehen.
quelle
Die Frage ist insbesondere, warum so viele von "Systemkomponenten" (auch als Standardbibliotheksklassen bezeichnet) ausgelöste Ausnahmen keine nützlichen Details enthalten.
Leider schreiben die meisten Entwickler weder die Kernkomponenten in Standardbibliotheken, noch werden detaillierte Konstruktionsdokumente oder andere Konstruktionsgründe notwendigerweise veröffentlicht. Mit anderen Worten, wir werden es vielleicht nie genau wissen.
Es gibt jedoch zwei wichtige Punkte, die beachtet werden müssen, warum detaillierte Ausnahmeinformationen möglicherweise nicht wünschenswert oder wichtig sind:
Eine Ausnahme kann auf irgendeine Weise durch Aufrufen von Code verwendet werden: Eine Standardbibliothek kann die Verwendung der Ausnahme nicht einschränken. Insbesondere kann es dem Benutzer angezeigt werden. Betrachten Sie einen Array-Index außerhalb der Grenzen: Dies kann einem Angreifer nützliche Informationen liefern. Der Sprachdesigner hat keine Ahnung, wie eine Anwendung die ausgelöste Ausnahme verwendet oder welche Art von Anwendung sie ist (z. B. Web-App oder Desktop). Aus Sicherheitsgründen kann das Auslassen von Informationen daher sicherer sein.
Ausnahmen sollten dem Benutzer nicht angezeigt werden. Zeigen Sie stattdessen eine angezeigte Fehlermeldung an und protokollieren Sie die Ausnahme an einem Ort, auf den ein Angreifer keinen Zugriff hat (falls zutreffend). Sobald der Fehler erkannt wurde, sollte ein Entwickler den Code debuggen und Stack-Frames und logische Pfade untersuchen. Zu diesem Zeitpunkt verfügt der Entwickler über mehr Informationen, als eine Ausnahme jemals erhoffen könnte.
quelle
Lassen Sie mich zunächst eine Blase platzen, indem ich sage, auch wenn die diag-Nachricht mit Informationen geladen ist, die Sie in 4 Sekunden zur genauen Codezeile und zum Unterbefehl führen. Es besteht die Möglichkeit, dass die Benutzer sie niemals aufschreiben oder an den Support weiterleiten und dir wird gesagt "Nun, es hat etwas über einen Verstoß gesagt ... ich weiß nicht, dass es kompliziert aussah!"
Ich schreibe seit mehr als 30 Jahren Software und unterstütze die Ergebnisse anderer Software. Persönlich hat die aktuelle Qualität einer Ausnahmebedingungsnachricht praktisch nichts mit Sicherheit zu tun, unabhängig davon, wie die Endergebnisse ihrem Modell entsprachen Das Universum, viel mehr mit der Tatsache zu tun, dass so viele in unserer Branche ursprünglich Autodidakten waren und nie Unterricht in Kommunikation beinhalteten. Wenn wir alle neuen Programmierer für ein paar Jahre in eine Wartungsposition zwingen würden, in der sie herausfinden müssten, was schief gelaufen ist, würden sie vielleicht verstehen, wie wichtig zumindest eine Form von Präzision ist.
Kürzlich wurde in einer Anwendung, die neu erstellt wurde, entschieden, dass Rückkehrcodes in eine von drei Gruppen fallen:
(100 wurden aus irgendeinem Grund ausgelassen)
In einem bestimmten Workflow wurde unser Gedanke wiederverwendet, oder generischer Code würde generische Rückgaben (> 199) für schwerwiegende Fehler verwenden, sodass 100 schwerwiegende Fehler für einen Workflow möglich sind. Bei geringfügig differenzierenden Daten in der Nachricht können Fehler, z. B. nicht gefundene Dateien, denselben Code verwenden und sich von den Nachrichten unterscheiden.
Als der Code von den Vertragspartnern zurückkam, konnten Sie unsere Überraschung nicht glauben, als praktisch JEDER EINZELNE FATALE FEHLER der Rückkehrcode 101 war.
Alles, was ich in Betracht gezogen habe, ist, dass die Antwort auf Ihre Frage so bedeutungslos ist, weil sie bei der ursprünglichen Erstellung Platzhalter sein sollten, auf die niemand zurückkam. Irgendwann fanden die Leute heraus, wie man Probleme nicht aufgrund der Nachrichten behebt, sondern ABWEICHEN kann.
Seit dieser Zeit hatten die Autodidakten einfach nie ein gutes Beispiel dafür, was eine Ausnahme enthalten sollte. Hinzu kommt, dass mehr Benutzer die Nachrichten nicht lesen und erst recht nicht versuchen, sie an den Support weiterzuleiten (ich habe Fehlermeldungen gesehen, die von den Verwendeten ausgeschnitten und eingefügt wurden, die dann redigiert wurden, bevor sie mit dem späteren Kommentar an den Support weitergeleitet wurden schien eine Menge Informationen zu sein und ich konnte unmöglich alles wollen, also entfernten sie zufällig einen Haufen davon.
Und seien wir ehrlich, mit viel zu vielen (nicht allen, aber viel zu vielen) Codierern der nächsten Generation, wenn es mehr Arbeit ist und keinen Flash hinzufügt, es einfach nicht wert
Letzter Hinweis: Wenn eine Fehlermeldung einen Fehler- / Rückgabecode enthält, sollte sich in den ausgeführten Modulen meines Erachtens eine Zeile befinden, die so etwas wie "if condition return code-value" und "condition" enthält und Ihnen den Grund für den Rückgabecode angibt aufgetreten. Dies scheint eine einfache logische Herangehensweise zu sein, aber für mein ganzes Leben ist es nur VERSUCHEN, Microsoft zu veranlassen, Ihnen mitzuteilen, was passiert ist, als ein Windows-Upgrade auf CODE 80241013 oder einem anderen sehr eindeutigen Bezeichner fehlgeschlagen ist. Ein bisschen traurig, nicht wahr?
quelle
chances are the users will never write it down... and you will be told "Well it said something about a violation..."
Aus diesem Grund verwenden Sie ein Tool zur Protokollierung von Ausnahmen, um automatisch den Fehlerbericht mit dem Stack-Trace zu erstellen und möglicherweise sogar an Ihren Server zu senden. Ich hatte einmal einen Benutzer, der nicht sehr technisch war. Jedes Mal, wenn sie eine Nachricht vom Fehlerprotokollierer übermittelte, lautete die Meldung "Ich bin nicht sicher, was ich falsch gemacht habe, aber ...", egal wie oft ich erklärte, dass dieser Fehler bedeutete, dass der Fehler auf meiner Seite war . Aber ich habe immer die Fehlermeldungen von ihr bekommen!Ich stimme zwar zu, dass Ausnahmen so viele Informationen wie möglich enthalten oder zumindest weniger allgemein sein sollten. In dem Fall, dass die Tabelle nicht gefunden wird, wäre der Tabellenname nett.
Sie wissen jedoch mehr darüber, was Sie an der Stelle im Code versucht haben, an der Sie die Ausnahme erhalten haben. Während Sie häufig nicht viel tun können, um die Situation zu korrigieren, wenn in einer Bibliothek außerhalb Ihrer Kontrolle etwas schief geht, können Sie viel nützlichere Informationen hinzufügen, in welcher Situation etwas schief gegangen ist.
Im Fall einer nicht gefundenen Tabelle hilft es Ihnen nicht viel, wenn Sie erfahren, dass die nicht gefundene Tabelle STUDENTS heißt, weil Sie keine solche Tabelle haben und diese Zeichenfolge nicht in Ihrem Code enthalten ist.
Aber wenn Sie die Ausnahme abfangen und sie mit der SQL-Anweisung erneut auslösen, die Sie ausführen wollten, ist es besser, wenn Sie versuchen, einen Datensatz einzufügen, dessen Namensfeld Robert ist '); TROPFENTISCHSTUDENTEN; (Es gibt immer eine xkcd!)
Um den weniger informativen Ausnahmen entgegenzuwirken: Try-Catch-Rethrow mit mehr Informationen, die spezifisch für das sind, was Sie versucht haben.
Ich sollte wahrscheinlich hinzufügen, dass dies eher eine Antwort auf das Warum in der Frage ist, dass ein wahrscheinlicher Grund, warum der Fokus der Hersteller der Bibliotheken nicht darauf lag, die Ausnahmebotschaften zu verbessern, darin besteht, dass sie es nicht wissen warum etwas versucht wurde, das fehlgeschlagen ist, ist diese Logik im aufrufenden Code.
quelle
throw_with_nested
viel verwenden.Um eine etwas andere Antwort zu geben: Der fehlerhafte Code wurde wahrscheinlich nach folgenden Kriterien erstellt:
Fügen Sie den Druck hinzu, in kürzester Zeit und mit minimalem Aufwand exakt die Spezifikationen zu liefern (aus Angst, bei Überprüfungen / Tests abgelehnt zu werden). Dann haben Sie Ihr Rezept für eine vollständig konforme und nicht hilfreiche Bibliotheksausnahme.
quelle
Ausnahmen verursachen sprach- und implementierungsspezifische Kosten.
Zum Beispiel sind C ++ - Ausnahmen erforderlich, um alle lebenden Daten zwischen dem Auslösen eines Anrufrahmens und dem Abfangen eines Anrufrahmens zu zerstören, und das ist teuer. Daher möchten Programmierer Ausnahmen nicht häufig verwenden.
In Ocaml ist das Auslösen von Ausnahmen fast so schnell wie ein C
setjmp
(seine Kosten hängen nicht von der Anzahl der durchquerten Anrufrahmen ab), sodass Entwickler viel davon verwenden können (selbst in nicht außergewöhnlichen, sehr häufigen Fällen). Im Gegensatz dazu sind C ++ - Ausnahmen stark genug, sodass Sie sie wahrscheinlich nicht so häufig verwenden wie in Ocaml.Ein typisches Beispiel ist eine rekursive Suche oder Erforschung, die in einer ziemlich tiefen Rekursion "gestoppt" werden kann (z. B. ein Blatt in einem Baum finden oder eine Vereinigungsfunktion). In einigen Sprachen ist es schneller (also idiomatischer), diese Bedingung an jeden Anrufer weiterzugeben. In anderen Sprachen ist das Auslösen einer Ausnahme schneller.
In Abhängigkeit von der Sprache (und den Gewohnheiten der Entwickler, die sie verwenden) kann eine Ausnahme viele nützliche Details enthalten oder im Gegenteil als schneller nicht-lokaler Sprung verwendet werden und nur die sehr nützlichen Daten enthalten.
quelle
Aus welchem Grund halten Sie den Indexwert oder den erforderlichen Bereich oder den Namen der Tabelle für ein nützliches Detail, abgesehen von einer Ausnahme?
Ausnahmen sind keine Fehlerbehandlungsmechanismen. Sie sind ein Wiederherstellungsmechanismus .
Der Punkt der Ausnahmen besteht darin, die Codeebene zu erreichen, die die Ausnahme behandeln kann. Überall dort, wo sich diese Ebene befindet, verfügen Sie entweder über die erforderlichen Informationen oder sie sind nicht relevant. Wenn Sie Informationen benötigen, aber keinen unmittelbaren Zugriff darauf haben, behandeln Sie die Ausnahme nicht auf der entsprechenden Ebene.
Ich kann mir nur einmal überlegen, wo zusätzliche Informationen hilfreich sein könnten , und zwar auf der absoluten obersten Ebene Ihrer Anwendung, in der Sie abstürzen und einen Fehlerbericht ausgeben. Es ist jedoch nicht die Aufgabe der Ausnahme, auf diese Informationen zuzugreifen, sie zu kompilieren und zu speichern.
Ich sage nicht, dass Sie einfach überall "werfen neue Ausnahme" und nennen es gut, es ist möglich, schlechte Ausnahmen zu schreiben. Das Einfügen irrelevanter Informationen ist jedoch nicht erforderlich, um sie ordnungsgemäß zu verwenden.
quelle