it-swarm.com.de

Warum enthalten viele Ausnahmemeldungen keine nützlichen Details?

Es scheint eine gewisse Übereinstimmung zu bestehen, dass Ausnahmemeldungen sollten nützliche Details enthalten .

Warum enthalten viele häufige Ausnahmen von Systemkomponenten keine nützlichen Details?

Einige Beispiele:

  • .NET List Indexzugriff ArgumentOutOfRangeException sagt mir nicht den Indexwert, der versucht wurde und ungültig war, und tut es auch nicht es sagt mir die erlaubte Reichweite.
  • Grundsätzlich sind alle Ausnahmemeldungen aus der MSVC C++ - Standardbibliothek völlig nutzlos (in der gleichen Weise wie oben).
  • Oracle-Ausnahmen in .NET, die Ihnen (umschrieben) "TABLE OR VIEW not found" mitteilen, aber nicht welche .

Daher scheint es mir, dass Ausnahmemeldungen zum größten Teil nicht genügend Details enthalten, um nützlich zu sein. Sind meine Erwartungen nicht im Einklang? Benutze ich falsche Ausnahmen, dass ich das überhaupt bemerke? Oder vielleicht ist mein Eindruck falsch: Die meisten Ausnahmen liefern tatsächlich nützliche Details?

224
Martin Ba

Ausnahmen enthalten keine nützlichen Details, da das Konzept der Ausnahmen innerhalb der Softwareentwicklungsdisziplin noch nicht ausreichend ausgereift ist, sodass viele Programmierer sie nicht vollständig verstehen und sie daher nicht richtig behandeln.

Ja, IndexOutOfRangeException sollte den genauen Index enthalten, der außerhalb des Bereichs lag, sowie den Bereich, der zum Zeitpunkt des Auslösens gültig war, und er ist im Namen der Ersteller der .NET-Laufzeit verächtlich es tut nicht. Ja, Oracle table or view not found Ausnahme sollte den Namen der Tabelle oder Ansicht enthalten, die nicht gefunden wurde, und auch die Tatsache, dass dies nicht der Fall ist, ist im Namen des Verantwortlichen verächtlich.

Die Verwirrung rührt zu einem großen Teil von der fehlgeleiteten ursprünglichen Idee her, dass Ausnahmen von Menschen lesbare Nachrichten enthalten sollten, was wiederum auf ein Unverständnis darüber zurückzuführen ist, worum es bei Ausnahmen geht. Es handelt sich also um einen Teufelskreis.

Da die Leute der Meinung sind, dass die Ausnahme eine für Menschen lesbare Nachricht enthalten sollte, glauben sie, dass alle Informationen, die von der Ausnahme getragen werden, auch in die für Menschen lesbare Nachricht formatiert werden sollten, und dann ist es ihnen entweder langweilig, alle von Menschen lesbaren Nachrichten zu schreiben. Bauvorschriften, oder sie befürchten, dass dies eine nicht zu empfehlende Menge an Informationen an die neugierigen Blicke weitergibt, die die Nachricht sehen könnten. (Die Sicherheitsprobleme, die in anderen Antworten erwähnt werden.)

Aber die Wahrheit ist, dass sie sich darüber keine Sorgen machen sollten, weil die Ausnahme nicht eine von Menschen lesbare Nachricht 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 kopiert werden (final/readonly) Mitgliedsvariablen des Ausnahmeobjekts. Vorzugsweise jedes denkbare kleine Stück davon. Auf diese Weise muss (oder sollte) keine Nachricht generiert werden, und daher können keine neugierigen Augen sie sehen.

Um die von Thomas Owens in einem Kommentar unten geäußerte Besorgnis anzusprechen:

Ja, natürlich erstellen Sie auf einer bestimmten Ebene wird eine Protokollnachricht bezüglich der Ausnahme. Sie sehen jedoch bereits das Problem mit dem, was Sie sagen: Einerseits ist eine Ausnahmeprotokollnachricht ohne Stack-Trace nutzlos, andererseits möchten Sie nicht, dass der Benutzer den gesamten Exception-Stack-Trace sieht. Auch hier besteht unser Problem darin, dass unsere Perspektive durch traditionelle Praktiken verzerrt wird. Protokolldateien sind traditionell im Klartext, was in unserer Kindheit vielleicht in Ordnung war, aber vielleicht nicht mehr: Wenn Sicherheitsbedenken bestehen, muss die Protokolldatei binär und/oder verschlüsselt sein.

Ob binärer oder einfacher Text, die Protokolldatei sollte als Stream betrachtet werden, in den die Anwendung Debug-Informationen serialisiert. Ein solcher Stream ist nur für die Augen der Programmierer bestimmt, und die Aufgabe, Debugging-Informationen für eine Ausnahme zu generieren, sollte so einfach sein wie das Serialisieren der Ausnahme in den Debug-Protokoll-Stream. Auf diese Weise erhalten Sie durch Betrachten des Protokolls den Namen der Ausnahmeklasse (der, wie ich bereits ausgeführt habe, für alle praktischen Zwecke "die Nachricht" ist) jede der Ausnahmemitgliedvariablen, die alles beschreibt, was relevant ist. und-praktisch-in-ein-Protokoll aufzunehmen, und die gesamte Stapelverfolgung. Beachten Sie, dass die Formatierung einer für Menschen lesbaren Ausnahmemeldung bei diesem Vorgang auffällig fehlt ist.

P.S.

Einige meiner Gedanken zu diesem Thema finden Sie in dieser Antwort: Wie schreibe ich eine gute Ausnahmemeldung

P.P.S.

Es scheint, dass viele Leute von meinem Vorschlag zu binären Protokolldateien abgehakt wurden, daher habe ich die Antwort noch einmal geändert, um noch deutlicher zu machen, dass das, was ich hier vorschlage, nicht ​​das Protokoll ist file sollte binär sein, aber dass die Protokolldatei darf binär sein, wenn nötig.

206
Mike Nakis

Warum enthalten viele häufige Ausnahmen von Systemkomponenten keine nützlichen Details?

Nach meiner Erfahrung gibt es eine Reihe von Gründen, warum Ausnahmen keine nützlichen Informationen enthalten. Ich gehe davon aus, dass diese Art von Gründen auch für Systemkomponenten gelten würde - aber ich weiß es nicht genau.

  • Sicherheitsorientierte Personen sehen Ausnahmen als Quelle für Informationslecks (für Beispiel ). Da das Standardverhalten von Ausnahmen darin besteht, diese Informationen dem Benutzer anzuzeigen, sind Programmierer manchmal vorsichtig.
  • In C++ habe ich Argumente gegen die Zuweisung von Speicher in Catch-Blöcken gehört (in denen zumindest ein Teil des Kontexts für gute Nachrichten liegt). Diese Zuordnung ist schwer zu verwalten und kann schlimmer noch zu einer Speicherausnahme führen - häufig zum Absturz Ihrer App oder zum Verlust von Speicher. Es ist schwierig, Ausnahmen gut zu formatieren, ohne Speicher zuzuweisen, und diese Praxis ist möglicherweise wie Programmierer zwischen Sprachen gewandert.
  • Sie wissen es nicht. Ich meine, es gibt sind Szenarien, in denen der Code keine Ahnung hat, was schief gelaufen ist. Wenn der Code es nicht weiß, kann er es Ihnen nicht sagen.
  • Ich habe an Orten gearbeitet, an denen Lokalisierungsprobleme verhindert haben, dass nur englischsprachige Zeichenfolgen in das System eingefügt werden - selbst bei Ausnahmen, die nur von englischsprachigen Support-Mitarbeitern gelesen werden.
  • An einigen Stellen habe ich Ausnahmen gesehen, die eher wie Behauptungen verwendet wurden. Sie sind da, um während der Entwicklung eine klare, laute Botschaft zu vermitteln, dass etwas nicht getan wurde oder an einem Ort eine Änderung vorgenommen wurde, an einem anderen jedoch nicht. Diese sind oft so einzigartig, dass eine gute Nachricht doppelt oder einfach verwirrend ist.
  • Die Leute sind faul, Programmierer mehr als die meisten anderen. Wir verbringen viel weniger Zeit auf dem außergewöhnlichen Weg als auf dem glücklichen Weg, und dies ist ein Nebeneffekt.

Sind meine Erwartungen nicht im Einklang? Benutze ich Ausnahmen falsch, dass ich das überhaupt bemerke?

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 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 darin sind, sie zu verhindern.

46
Telastyn

Ich habe keinen Überschuss an C # -Erfahrung oder speziell an C++, aber ich kann Ihnen dies sagen - von Entwicklern geschriebene Ausnahmen sind 9 von 10 Mal 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 - aber realistisch gesehen in großen Anwendungen mit mehreren Klassen, die eine Vielzahl verschiedener Arten von Ausnahmen auslösen können, oder die gleiche Art von Ausnahmen, es ist immer wertvoller, eine eigene Ausgabe für die Fehlerrückgabe zu schreiben, als sich auf die Standardnachricht zu verlassen.

So sollte es sein, denn wie viele Leute darauf hingewiesen haben, geben einige Anwendungen nicht wollen eine Fehlermeldung aus, die der Benutzer aus Sicherheitsgründen nicht sehen oder vermeiden soll verwirrt sie.

Stattdessen sollten Sie in Ihrem Entwurf vorhersehen, welche Arten von Fehlern in Ihrer Anwendung auftreten können (und es werden immer Fehler auftreten), und Fehlermeldungen verfassen, mit denen Sie das Problem identifizieren können.

Dies wird Ihnen nicht immer helfen - da Sie nicht immer vorhersehen können, welche Fehlermeldung nützlich sein wird -, aber es ist der erste Schritt, um Ihre eigene Anwendung langfristig besser zu verstehen.

12
Zibbobz

Die Frage ist speziell, warum so viele Ausnahmen, die von "Systemkomponenten" (auch als Standardbibliotheksklassen bezeichnet) ausgelöst werden, keine nützlichen Details enthalten.

Leider schreiben die meisten Entwickler weder die Kernkomponenten in Standardbibliotheken, noch werden detaillierte Entwurfsdokumente oder andere Entwurfsgründe notwendigerweise veröffentlicht. Mit anderen Worten, wir werden es vielleicht nie genau wissen.

Es sind jedoch zwei wichtige Punkte zu beachten, warum detaillierte Ausnahmeinformationen möglicherweise nicht wünschenswert oder wichtig sind:

  1. Eine Ausnahme kann durch Aufrufen von Code auf folgende Weise verwendet werden: Eine Standardbibliothek kann die Verwendung der Ausnahme nicht einschränken. Insbesondere kann es dem Benutzer angezeigt werden. Stellen Sie sich einen Array-Index außerhalb der Grenzen vor: Dies kann einem Angreifer nützliche Informationen geben. Der Sprachdesigner hat keine Ahnung, wie eine Anwendung die ausgelöste Ausnahme verwendet oder welche Art von Anwendung es ist (z. B. Webanwendung oder Desktop), sodass das Auslassen von Informationen aus Sicherheitsgründen sicherer sein kann.

  2. Ausnahmen sollte nicht werden dem Benutzer angezeigt. Zeigen Sie stattdessen eine freundliche 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 Stapelrahmen und Logikpfade überprüfen. Zu diesem Zeitpunkt verfügt der Entwickler über mehr Informationen, als eine Ausnahme jemals erhoffen könnte.

7
user22815

Lassen Sie mich zunächst eine Blase platzen lassen, indem Sie sagen, selbst wenn die diag-Nachricht mit Informationen geladen ist, die Sie in 4 Sekunden zur genauen Codezeile und zum Unterbefehl führen, besteht die Möglichkeit, dass die Benutzer sie niemals aufschreiben oder an die Support-Mitarbeiter weiterleiten und dir wird gesagt "Nun, es hat etwas über eine Verletzung 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 Ausnahmemeldung praktisch nichts mit Sicherheit zu tun, unabhängig davon, wie die Endergebnisse zu ihrem Modell passen das Universum, viel mehr mit der Tatsache zu tun, dass so viele in unserer Branche ursprünglich Autodidakten waren und einfach nie Unterricht in Kommunikation beinhalteten. Wenn wir alle neuen Codierer 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 gewisse Präzision ist.

Kürzlich wurde in einer neu erstellten Anwendung die Entscheidung getroffen, dass Rückkehrcodes in eine von drei Gruppen fallen:

  • 0 bis 9 wäre Erfolg durch Erfolg mit zusätzlichen Informationen.
  • 10 bis 99 wären nicht schwerwiegende (behebbare) Fehler, und
  • 101 bis 255 wären schwerwiegende Fehler.

(100 wurde aus irgendeinem Grund weggelassen)

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 leicht differenzierenden Daten in der Nachricht können Fehler wie nicht gefundene Dateien denselben Code verwenden und mit den Nachrichten differenzieren.

Als der Code von den Auftragnehmern zurückkam, würden Sie unsere Überraschung nicht glauben, wenn praktisch JEDER EINZELNE FATALE FEHLER der Rückkehrcode 101 war.

Ich denke, die Antwort auf Ihre Frage ist, dass die Nachrichten so bedeutungslos sind, weil sie bei ihrer ursprünglichen Erstellung Platzhalter sein sollten, auf die niemand zurückkam. Schließlich fanden die Leute heraus, wie man Probleme nicht aufgrund der Nachrichten behebt, sondern trotz der Nachrichten.

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, geschweige denn versuchen, sie an den Support weiterzuleiten (ich habe Fehlermeldungen gesehen, die von den Verwendeten ausgeschnitten und eingefügt wurden und die dann redigiert wurden, bevor sie mit dem späteren Kommentar weitergeleitet wurden schien eine Menge Informationen zu sein und ich konnte unmöglich alles wollen, also haben sie zufällig ein paar davon entfernt.

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 Blitz hinzufügt, lohnt es sich einfach nicht ...

Letzte Anmerkung: Wenn eine Fehlermeldung einen Fehler-/Rückkehrcode enthält, scheint es mir, dass irgendwo in den ausgeführten Modulen eine Zeile mit der Aufschrift "if condition return code-value" stehen sollte und die Bedingung Ihnen mitteilen sollte, warum der Rückkehrcode aufgetreten. Dies scheint ein einfacher logischer Ansatz zu sein, aber für mein ganzes Leben versuchen Sie einfach, Microsoft zu veranlassen, Ihnen mitzuteilen, was passiert ist, als ein Windows-Upgrade auf CODE 80241013 oder einer anderen sehr eindeutigen Kennung fehlgeschlagen ist. Ein bisschen traurig, nicht wahr?

4
Randy

Um eine etwas andere Antwort zu geben: Der fehlerhafte Code wurde wahrscheinlich gemäß Spezifikation erstellt:

  • Die Funktion empfängt X und gibt Y zurück
  • Wenn X ungültig ist, lösen Sie die Ausnahme Z aus

Fügen Sie den Druck hinzu, in kürzester Zeit und mit minimalem Aufwand genau nach Spezifikation 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.

3
Stu Pegg

Ausnahmen haben 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 keine Ausnahmen 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 es häufig verwenden können (auch für nicht außergewöhnliche, sehr häufige) , Fälle). Im Gegensatz dazu sind C++ - Ausnahmen schwer genug, sodass Sie sie wahrscheinlich nicht so häufig verwenden wie in Ocaml.

Ein typisches Beispiel ist eine rekursive Suche oder Erkundung, die innerhalb einer ziemlich tiefen Rekursion "gestoppt" werden kann (z. B. Finden eines Blattes in einem Baum oder einer 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.

Abhängig 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.

Ich stimme zwar zu, dass Ausnahmen so viele Informationen wie möglich enthalten oder zumindest weniger allgemein sein sollten. In dem Fall "Tabelle nicht gefunden" wäre der Tabellenname "Nizza".

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 oft 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 gelaufen ist.

Wenn die Tabelle nicht gefunden wird, hilft es Ihnen nicht viel, wenn Sie erfahren, dass die nicht gefundene Tabelle STUDENTS heißt, da Sie keine solche Tabelle haben und diese Zeichenfolge nirgends in Ihrem Code enthalten ist.

Wenn Sie jedoch die Ausnahme abfangen und sie mit der SQL-Anweisung, die Sie ausführen wollten, erneut auslösen, sind Sie besser dran, da sich herausstellt, dass Sie versucht haben, einen Datensatz mit dem Namensfeld Robert ') einzufügen. DROP TABLE STUDENTS; (Es gibt immer eine xkcd!)

Um die weniger informativen Ausnahmen zu bekämpfen: Versuchen Sie es erneut mit mehr Informationen, die spezifisch für das sind, was Sie versucht haben.

Ich sollte wahrscheinlich hinzufügen, damit 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 Ausnahmemeldungen besser zu machen, darin besteht, dass sie es nicht wissen Warum etwas versucht wurde, das fehlgeschlagen ist, befindet sich diese Logik im aufrufenden Code.

3
Bent