Ich führe gerade eine Codeüberprüfung durch, und eines der Dinge, die ich bemerke, ist die Anzahl der Ausnahmen, bei denen die Ausnahmemeldung lediglich zu wiederholen scheint, wo die Ausnahme aufgetreten ist. z.B
throw new Exception("BulletListControl: CreateChildControls failed.");
Alle drei Punkte in dieser Nachricht kann ich aus dem Rest der Ausnahme herausarbeiten. Ich kenne die Klasse und Methode aus dem Stack-Trace und weiß, dass dies fehlgeschlagen ist (da ich eine Ausnahme habe).
Ich habe darüber nachgedacht, welche Meldung ich in Ausnahmemeldungen eingefügt habe. Zuerst erstelle ich eine Ausnahmeklasse, falls noch keine vorhanden ist, aus dem allgemeinen Grund (z. B. PropertyNotFoundException
dem Warum ) und dann, wenn ich sie ausspreche, zeigt die Nachricht an, was schief gelaufen ist (z. B. "Die Eigenschaft 'IDontExist' konnte auf Knoten 1234 nicht gefunden werden "- das was ). Das wo ist in der StackTrace
. Das Wann wird möglicherweise im Protokoll vermerkt (falls zutreffend). Das Wie soll der Entwickler herausfinden (und beheben)
Haben Sie weitere Tipps zum Auslösen von Ausnahmen? Speziell im Hinblick auf das Anlegen neuer Typen und die Ausnahmemeldung.
quelle
Antworten:
Ich werde meine Antwort mehr auf das richten, was nach einer Ausnahme kommt: Wofür ist es gut und wie sollte sich Software verhalten, was sollten Ihre Benutzer mit der Ausnahme tun? Eine großartige Technik, auf die ich zu Beginn meiner Karriere gestoßen bin, bestand darin, Probleme und Fehler immer in drei Teilen zu melden: Kontext, Problem und Lösung. Die Verwendung dieser Disziplin verändert die Fehlerbehandlung enorm und verbessert die Benutzerfreundlichkeit der Software erheblich.
Hier sind einige Beispiele.
In diesem Fall weiß der Bediener genau, was zu tun ist und welche Datei betroffen sein muss. Sie wissen auch, dass die Änderungen am Verbindungspool nicht übernommen wurden und wiederholt werden sollten.
Ich schreibe serverseitige Systeme und meine Bediener sind in der Regel technisch versierte First-Line-Support. Ich würde die Nachrichten für Desktop-Software, die eine andere Zielgruppe haben, aber die gleichen Informationen enthalten, anders schreiben.
Wenn man diese Technik anwendet, passieren mehrere wunderbare Dinge. Der Softwareentwickler ist oft am besten in der Lage, die Probleme in seinem eigenen Code zu lösen. Daher ist die Codierung von Lösungen auf diese Weise beim Schreiben des Codes für Endbenutzer von großem Vorteil, die nachteilig Lösungen finden, da ihnen häufig Informationen zu fehlen was genau die Software tat. Jeder, der jemals eine Oracle-Fehlermeldung gelesen hat, weiß, was ich meine.
Die zweite wunderbare Sache, die mir einfällt, ist, wenn Sie versuchen, eine Lösung in Ihrer Ausnahme zu beschreiben, und Sie schreiben "Check X und wenn A, dann B, dann C". Dies ist ein sehr klares und offensichtliches Zeichen dafür, dass Ihre Ausnahme an der falschen Stelle überprüft wird. Sie, der Programmierer, haben die Fähigkeit, Dinge im Code zu vergleichen. Wenn Anweisungen im Code ausgeführt werden sollen, warum sollte der Benutzer dann an etwas beteiligt sein, das automatisiert werden kann? Die Wahrscheinlichkeit ist groß, dass es sich um einen tieferen Code handelt, und jemand hat das Faule getan und IOException von einer beliebigen Anzahl von Methoden geworfen und potenzielle Fehler von allen in einem Block von aufrufendem Code aufgefangen, der nicht ausreichend beschreiben kann, was falsch gelaufen ist, was der spezifische Code istKontext ist und wie man es behebt. Dies ermutigt Sie, feinere Körnungsfehler zu schreiben, diese zu erfassen und an der richtigen Stelle in Ihrem Code zu behandeln, damit Sie die Schritte, die der Bediener ausführen sollte, richtig artikulieren können.
In einem Unternehmen hatten wir erstklassige Betreiber, die die Software sehr gut kennengelernt und ein eigenes "Run Book" geführt haben, das unsere Fehlerberichte und Lösungsvorschläge vervollständigte. Um dies zu erkennen, hat die Software in Ausnahmefällen Wiki-Links zum Runbook hinzugefügt, sodass eine grundlegende Erklärung zur Verfügung stand sowie Links zu weiterführenden Diskussionen und Beobachtungen der Bediener im Laufe der Zeit.
Wenn Sie die Disziplin hatten, diese Technik auszuprobieren, wird es viel offensichtlicher, wie Sie Ihre Ausnahmen im Code benennen sollten, wenn Sie Ihre eigenen erstellen. NonRecoverableConfigurationReadFailedException wird zu einer Abkürzung für das, was Sie dem Bediener genauer beschreiben werden. Ich mag es, wortreich zu sein, und ich denke, das wird dem nächsten Entwickler, der meinen Code berührt, leichter fallen, ihn zu interpretieren.
quelle
FileNotFound
oderConnectException
Sie wissen , was zu tun ) )In dieser neueren Frage habe ich darauf hingewiesen, dass Ausnahmen überhaupt keine Nachricht enthalten sollten. Meiner Meinung nach ist die Tatsache, dass sie dies tun, ein großes Missverständnis. Was ich vorschlage, ist das
Eine Ausnahme sollte innerhalb ihrer eigenen Mitgliedsvariablen so viele Details wie möglich darüber enthalten, was genau passiert ist. Ein
IndexOutOfRangeException
sollte beispielsweise den Indexwert enthalten, der als ungültig befunden wurde, sowie die oberen und unteren Werte, die zum Zeitpunkt des Auslösens der Ausnahme gültig waren. Auf diese Weise können Sie mithilfe von Reflection automatisch eine MeldungIndexOutOfRangeException: index = -1; min=0; max=5
erstellen lassen, die wie folgt lautet: Dies sollte zusammen mit dem Stack-Trace alle objektiven Informationen enthalten, die Sie zur Behebung des Problems benötigen. Das Formatieren in eine hübsche Nachricht wie "Index -1 war nicht zwischen 0 und 5" fügt keinen Wert hinzu.In Ihrem speziellen Beispiel
NodePropertyNotFoundException
würde die Klasse den Namen der Eigenschaft enthalten, die nicht gefunden wurde, und einen Verweis auf den Knoten, der die Eigenschaft nicht enthielt. Dies ist wichtig: Es sollte nicht den Namen des Knotens enthalten. es sollte einen Verweis auf den tatsächlichen Knoten enthalten. In Ihrem speziellen Fall ist dies möglicherweise nicht erforderlich, es handelt sich jedoch um ein Prinzip und eine bevorzugte Denkweise: Das Hauptanliegen beim Erstellen einer Ausnahme ist, dass sie von Code verwendet werden kann, der sie möglicherweise abfängt. Benutzerfreundlichkeit für den Menschen ist ein wichtiges, aber nur zweitrangiges Anliegen.Dies behebt die sehr frustrierende Situation, die Sie möglicherweise zu einem bestimmten Zeitpunkt in Ihrer Karriere erlebt haben, in der Sie möglicherweise eine Ausnahme mit wichtigen Informationen über das Geschehen im Nachrichtentext, aber nicht in den Mitgliedervariablen abgefangen haben Ich musste den Text in Strings analysieren, um herauszufinden, was passiert ist, in der Hoffnung, dass der Nachrichtentext in zukünftigen Versionen der darunter liegenden Ebene gleich bleibt, und beten, dass der Nachrichtentext nicht in einer Fremdsprache vorliegt, wenn Ihr Programm ist in anderen Ländern laufen.
Da der Klassenname der Ausnahme die Nachricht der Ausnahme ist (und die Mitgliedsvariablen der Ausnahme die spezifischen Details sind), bedeutet dies natürlich, dass Sie sehr viele verschiedene Ausnahmen benötigen, um alle verschiedenen Nachrichten zu übermitteln, und das ist gut.
Jetzt stoßen wir manchmal beim Schreiben von Code auf eine fehlerhafte Situation, für die wir nur schnell eine
throw
Anweisung codieren und den Code schreiben möchten, anstatt zu unterbrechen, was wir tun, um eine neue Ausnahmeklasse zu erstellen, damit wir dies tun können wirf es genau dort hin. Für diese Fälle habe ich eineGenericException
Klasse, die tatsächlich eine Zeichenfolgenmeldung als Konstruktionszeitparameter akzeptiert, aber der Konstruktor dieser Ausnahmeklasse ist mit einem großen, großen, leuchtend violettenFIXME XXX TODO
Kommentar geschmückt, der besagt, dass jede einzelne Instanz dieser Klasse sein muss wird durch eine Instanziierung einer spezielleren Ausnahmeklasse ersetzt, bevor das Softwaresystem freigegeben wird, vorzugsweise bevor der Code festgeschrieben wird.quelle
node
Objekt durch eine using-disposable-Klausel (in C #) oder eine try-with-resources-Klausel (in Java) geschützt wird: Das mit der Ausnahme gespeicherte Objekt wird freigegeben / geschlossen, wodurch es ungültig wird Zugriff darauf, um nützliche Informationen an der Stelle abzurufen, an der die Ausnahme behandelt wird. Ich nehme an, dass in diesen Fällen eine Art Zusammenfassung des Objekts in der Ausnahme statt des Objekts selbst gespeichert werden sollte. Ich kann mir keinen idiotensicheren Weg vorstellen, dies für alle Fälle generisch zu handhaben.In der Regel sollte eine Ausnahme den Entwicklern helfen, die Ursache zu lokalisieren, indem nützliche Informationen (erwartete Werte, tatsächlicher Wert, mögliche Ursachen / Lösung usw.) angegeben werden.
Neue Ausnahmetypen sollten erstellt werden, wenn keiner der integrierten Typen sinnvoll ist . Mit einem bestimmten Typ können andere Entwickler eine bestimmte Ausnahme abfangen und damit umgehen. Wenn der Entwickler weiß, wie er mit Ihrer Ausnahme umgehen soll, der Typ jedoch so ist
Exception
, kann er sie nicht richtig behandeln.quelle
In .NET nicht immer
throw new Exception("...")
(wie der Autor der Frage gezeigt hat). Die Ausnahme ist der Stamm-Ausnahmetyp und darf niemals direkt ausgelöst werden. Werfen Sie stattdessen einen der abgeleiteten .NET-Ausnahmetypen oder erstellen Sie eine eigene benutzerdefinierte Ausnahme, die von Exception (oder einem anderen Ausnahmetyp) abgeleitet ist.Warum nicht Exception werfen? Weil das Auslösen von Exception nichts zur Beschreibung Ihrer Exception beiträgt und Ihren aufrufenden Code dazu zwingt, Code zu schreiben, wie er
catch(Exception ex) { ... }
im Allgemeinen nicht gut ist! :-).quelle
Die Dinge, nach denen Sie suchen möchten, um der Ausnahme "hinzuzufügen", sind diejenigen Datenelemente, die der Ausnahme oder der Stapelablaufverfolgung nicht inhärent sind. Ob diese Teil der "Nachricht" sind oder bei der Anmeldung angehängt werden müssen, ist eine interessante Frage.
Wie Sie bereits bemerkt haben, sagt Ihnen die Ausnahme wahrscheinlich, was, die Stapelspur sagt Ihnen wahrscheinlich, wo, aber das "Warum" kann mehr involviert sein (sollte es sein, würde man hoffen), als nur ein oder zwei Zeilen zu betrachten und zu sagen: " doh! Natürlich ". Dies gilt umso mehr, wenn Fehler im Produktionscode protokolliert werden. Ich bin allzu oft von schlechten Daten gebissen worden, die in ein Live-System eingedrungen sind, das es in unseren Testsystemen nicht gibt. Etwas so Einfaches wie das Erkennen der ID des Datensatzes in der Datenbank, der den Fehler verursacht (oder dazu beiträgt), kann erhebliche Zeitersparnis bedeuten.
Also ... Entweder aufgelistet oder für .NET zur Datenerfassung für protokollierte Ausnahmen hinzugefügt (siehe @Plip!):
Einige Dinge werden Sie natürlich nicht wissen müssen, bis Sie sie nicht in Ihrem anfänglichen Fehlerbericht / -protokoll haben. Einige Dinge, von denen Sie nicht wissen, dass Sie sie bekommen können, bis Sie feststellen, dass Sie sie brauchen.
quelle
Was sind Ausnahmen für ?
(1) Dem Benutzer mitteilen, dass ein Fehler aufgetreten ist?
Dies sollte ein letzter Ausweg sein, da Ihr Code eingreifen und ihnen etwas "Schöneres" als eine Ausnahme zeigen sollte.
Die "Fehler" -Meldung sollte klar und prägnant angeben, was schief gelaufen ist und was der Benutzer gegebenenfalls tun kann, um den Fehlerzustand zu beheben.
zB "Bitte drücken Sie diese Taste nicht noch einmal"
(2) Einem Entwickler mitteilen, wann ein Fehler aufgetreten ist?
Dies ist die Art von Dingen, die Sie für die nachfolgende Analyse in eine Datei einloggen.
Der Stack-Trace teilt dem Entwickler mit, wo der Code fehlerhaft war. Die Nachricht sollte wieder anzeigen, was schief gelaufen ist.
(3) Einem Exception-Handler (dh Code) mitteilen, dass ein Fehler aufgetreten ist?
Der Typ der Ausnahme entscheidet, welche Ausnahmebehandlungsroutine darauf zugreift, und die für das Ausnahmeobjekt definierten Eigenschaften ermöglichen es der Behandlungsroutine, damit umzugehen.
Die Nachricht der Ausnahme ist völlig irrelevant .
quelle
Erstellen Sie keine neuen Typen, wenn Sie es verbessern können. Sie können zusätzliche Verwirrung und Komplexität verursachen und dazu führen, dass mehr Code gepflegt wird. Sie könnten dazu führen, dass Ihr Code erweitert werden musste. Das Entwerfen einer Ausnahmehierarchie erfordert jedoch eine Menge Tests. Es ist kein nachträglicher Gedanke. Es ist oft am besten, die eingebaute Sprachausnahmehierarchie zu verwenden.
Der Inhalt der Ausnahmemeldung hängt vom Empfänger der Meldung ab - Sie müssen sich also in die Lage dieser Person versetzen.
Ein Support-Techniker muss in der Lage sein, die Fehlerquelle so schnell wie möglich zu identifizieren. Fügen Sie eine kurze beschreibende Zeichenfolge sowie alle Daten hinzu, die zur Behebung des Problems beitragen können. Fügen Sie immer den Stack-Trace ein, wenn Sie können. Dies ist die einzig wahre Informationsquelle.
Die Darstellung von Fehlern für allgemeine Benutzer Ihres Systems hängt von der Art des Fehlers ab: Wenn der Benutzer das Problem beheben kann, indem er beispielsweise eine andere Eingabe vornimmt, ist eine kurze beschreibende Meldung erforderlich. Wenn der Benutzer das Problem nicht beheben kann, geben Sie am besten an, dass ein Fehler aufgetreten ist, und protokollieren / senden Sie einen Fehler an den Support (gemäß den obigen Richtlinien).
Auch - werfen Sie keinen großen "HALT ERROR!" Symbol. Es ist ein Fehler - es ist nicht das Ende der Welt.
Also zusammenfassend: Denken Sie über die Akteure und Anwendungsfälle für Ihr System nach. Versetzen Sie sich in die Lage dieses Benutzers. Sei hilfreich. Sei nett. Denken Sie in Ihrem Systemdesign darüber nach. Aus Sicht Ihrer Benutzer sind diese Ausnahmefälle und die Art und Weise, wie das System mit ihnen umgeht, genauso wichtig wie die normalen Fälle in Ihrem System.
quelle