
Ich hatte noch nie eine bestimmte Meinung zur Fehlerbehandlung. Wenn ich anfing, mit vorhandenem Code zu arbeiten, führte ich die Aufgabe weiter, an der der Autor der Quelle gearbeitet hatte. Wenn ich den Code von Grund auf neu geschrieben habe, habe ich das getan, was mir richtig erschien.
Aber kürzlich bin ich auf ein Problem gestoßen, einen Fehler, der sich aufgrund eines "stillen" Fehlers im Code manifestierte. Mir wurde klar, dass es etwas zu reflektieren gibt. Vielleicht kann ich den Umgang mit Fehlern in der gesamten Codebasis, an der ich arbeite, nicht ändern, aber etwas kann definitiv optimiert werden.
Wir erinnern Sie daran: Für alle Leser von „Habr“ - ein Rabatt von 10.000 Rubel bei der Anmeldung für einen Skillbox-Kurs mit dem Promo-Code „Habr“.
Skillbox empfiehlt: Der Online-Schulungskurs "Profession Java-Entwickler" .
Es lohnt sich nicht immer, die Schulter abzuhacken
Der erste Schritt bei der Fehlerbehandlung sollte das Verständnis sein, wenn "Fehler" nicht "Fehler" ist! Natürlich hängt dies alles von der Geschäftslogik Ihrer Anwendung ab, aber im Allgemeinen sind einige Fehler explizit und können problemlos behoben werden.
- Haben Sie einen Datumsbereich, in dem das "Vorher" vor dem "Von" steht? Nachbestellen.
- Haben Sie eine Telefonnummer, die mit + beginnt oder einen Bindestrich enthält, bei dem Sie keine Sonderzeichen erwarten? Entfernen Sie sie.
- Null-Sammelproblem? Stellen Sie sicher, dass Sie dies vor dem Zugriff initialisieren (mithilfe der verzögerten Initialisierung oder des Konstruktors).
Unterbrechen Sie die Codeausführung nicht aufgrund von Fehlern, die Sie beheben können, und beeinträchtigen Sie natürlich nicht Ihre Aktionen für Benutzer Ihres Dienstes oder Ihrer Anwendung. Wenn Sie das Problem verstehen und im Handumdrehen lösen können, tun Sie es einfach.

Geben Sie Null oder andere magische Zahlen zurück
Nullwerte, –1, wenn eine positive Zahl erwartet wird, und andere magische Rückgabewerte - all dies ist das Produkt des Teufels, der die Verantwortung für die Überprüfung von Fehlern auf die aufrufende Funktion überträgt.
Mit ihnen ist Ihr Code voll von solchen Blöcken, die die Anwendungslogik unklar machen:
return_value = possibly_return_a_magic_value() if return_value < 0: handle_error() else: do_something() other_return_value = possibly_nullable_value() if other_return_value is None: handle_null_value() else: do_some_other_thing()
Gut oder einfacher, aber auch schlecht:
var item = returnSomethingWhichCouldBeNull(); var result = item?.Property?.MaybeExists; if (result.HasValue) { DoSomething(); }
Die Übergabe von null an Methoden ist ebenfalls ein Problem, obwohl Sie im Code einiger Entwickler möglicherweise Stellen finden, an denen Methoden mit einigen Zeilen der Eingabevalidierung beginnen. Tatsächlich ist dies alles nicht notwendig. Die meisten modernen Sprachen bieten nicht nur ein, sondern mehrere Tools gleichzeitig, mit denen Sie klar angeben können, was Sie erwarten. Sie überspringen auch nutzlose Überprüfungen, indem sie beispielsweise Parameter als ungleich Null oder mit dem entsprechenden Dekorator definieren.
Fehlercodes
Dies ist das gleiche Problem wie bei null und anderen ähnlichen Werten, wenn unnötige Codekomplikationen hinzugefügt werden.
Mit dieser Konstruktion können Sie beispielsweise einen Fehlercode zurückgeben:
int errorCode; var result = getSomething(out errorCode); if (errorCode != 0) { doSomethingWithResult(result); }
Das Ergebnis kann wie folgt angezeigt werden:
public class Result<T> { public T Item { get; set; }
Dies ist wirklich nicht der beste Code. Es stellt sich heraus, dass Item noch leer sein kann. Tatsächlich gibt es keine Garantie (außer einer Vereinbarung), dass Sie sicher auf den Artikel zugreifen können, wenn das Ergebnis keinen Fehler enthält.
Nachdem Sie diese Verarbeitung abgeschlossen haben, müssen Sie den Fehlercode noch in eine Fehlermeldung konvertieren und etwas damit tun. Manchmal kommt es vor, dass diese Nachricht aufgrund der übermäßigen Komplexität des Codes nicht so angezeigt wird, wie sie sollte.
Es gibt ein noch schwerwiegenderes Problem: Wenn Sie oder eine andere Person die interne Implementierung ändern, um einen neuen ungültigen Status mit einem neuen Fehlercode zu behandeln, funktioniert die gesamte Struktur überhaupt nicht mehr.
Wenn es beim ersten Mal nicht funktioniert hat, versuchen Sie es erneut
Bevor Sie fortfahren, sollten Sie betonen, dass ein „stiller“ Programmfehler schlecht ist. Ein unerwartetes Problem kann im ungünstigsten Moment auftreten - zum Beispiel am Wochenende, wenn Sie nicht alles schnell beheben können.

Wenn Sie
Clean Code lesen, fragen Sie sich höchstwahrscheinlich, warum Sie nicht einfach eine Ausnahme auslösen. Wenn nicht, dann denken Sie höchstwahrscheinlich, dass Ausnahmen die Wurzel des Bösen sind. Früher habe ich das auch gedacht, jetzt denke ich etwas anders.
Zumindest für mich ist ein interessanter Punkt, dass die Standardimplementierung für die neue Methode in C # darin besteht, eine NotImplementedException auszulösen, während die Standardimplementierung für die neue Methode in Python "pass" ist.
Infolgedessen geben wir meistens die Einstellung "stiller Fehler" für Python ein. Ich frage mich, wie viele Entwickler viel Zeit aufgewendet haben, um zu verstehen, was passiert und warum das Programm nicht funktioniert. Aber am Ende, nach vielen Stunden, stellten sie fest, dass sie vergessen hatten, die Platzhaltermethode zu implementieren.
Aber schauen Sie sich das an:
public MyDataObject UpdateSomething(MyDataObject toUpdate) { if (_dbConnection == null) { throw new DbConnectionError(); } try { var newVersion = _dbConnection.Update(toUpdate); if (newVersion == null) { return null; } MyDataObject result = new MyDataObject(newVersion); return result; } catch (DbConnectionClosedException dbcc) { throw new DbConnectionError(); } catch (MyDataObjectUnhappyException dou) { throw new MalformedDataException(); } catch (Exception ex) { throw new UnknownErrorException(); } }
Ausnahmen allein schützen Sie natürlich nicht davor, unlesbaren und nicht verwalteten Code zu erstellen. Sie sollten Ausnahmen als gut durchdachte und ausgewogene Strategie anwenden. Andernfalls befindet sich Ihre Anwendung möglicherweise in einem inkonsistenten Zustand, wenn das Projekt zu groß ist. Umgekehrt, wenn das Projekt zu klein ist, werden Sie Chaos bekommen.
Um dies zu verhindern, rate ich Ihnen, Folgendes zu beachten:
Vor allem Konsistenz. Sie müssen immer sicherstellen, dass die Anwendung konsistent ist. Wenn dies bedeutet, dass Sie jedes Zeilenpaar mit einem Try / Catch-Block umschließen müssen, verstecken Sie einfach alles in einer anderen Funktion.
def my_function(): try: do_this() do_that() except: something_bad_happened() finally: cleanup_resource()
Die Konsolidierung von Fehlern ist erforderlich. Es ist gut, wenn Sie verschiedene Arten der Behandlung verschiedener Arten von Fehlern bereitstellen. Dies ist jedoch für Sie, nicht für Benutzer. Wirf für sie die einzige Ausnahme, damit Benutzer einfach wissen, dass etwas schief gelaufen ist. Details liegen in Ihrem Verantwortungsbereich.
public MyDataObject UpdateSomething(MyDataObject toUpdate) { try { var newVersion = _dbConnection.Update(toUpdate); MyDataObject result = new MyDataObject(newVersion); return result; } catch (DbConnectionClosedException dbcc) { HandleDbConnectionClosed(); throw new UpdateMyDataObjectException(); } catch (MyDataObjectUnhappyException dou) { RollbackVersion(); throw new UpdateMyDataObjectException(); } catch (Exception ex) { throw new UpdateMyDataObjectException(); } }
Es lohnt sich, sofort Ausnahmen zu machen. Sie werden am besten auf der niedrigsten Ebene abgefangen. Es lohnt sich, wie oben beschrieben konsistent zu bleiben und die Details zu verbergen. Die Fehlerbehandlung sollte der obersten Ebene der Anwendung überlassen bleiben. Wenn alles richtig gemacht wurde, können Sie den Logikfluss der Anwendung selbst vom Fehlerverarbeitungsfluss trennen. Auf diese Weise können Sie klaren, lesbaren Code schreiben.
def my_api(): try: item = get_something_from_the_db() new_version = do_something_to_item(item) return new_version except Exception as ex: handle_high_level_exception(ex)
Das ist alles für den Moment, und wenn Sie das Thema Fehler und deren Verarbeitung diskutieren möchten - Willkommen.
Skillbox empfiehlt: