Fatalismus in der Fehlerbehandlung

    Vorwort


    Dieser Artikel ist eine Antwort auf den Artikel: Was ist mit Fehlerbehandlung in C ++ 2a passieren wird . Nach jedem Absatz hatte ich einen Juckreiz, heilte Wunden und begann zu bluten. Vielleicht nehme ich mir zu viel, was geschrieben steht. Aber ich möchte nur über die Kurzsichtigkeit und das Analphabetentum der C ++ - Programmierer im 21. Jahrhundert heulen. Und auch nicht am Anfang.


    Lass uns anfangen


    Klassifizierung


    Üblicherweise können alle Fehlersituationen im Programm in zwei große Gruppen unterteilt werden:
    1. Schwerwiegende Fehler
    2. Nicht schwerwiegende oder erwartete Fehler.


    Ich werde jetzt Fehler finden. In gewissem Sinne werden jedoch auch fatale Fehler erwartet. Wir erwarten, dass eine Reise durch das Gedächtnis oft zu einem Sturz führt, aber möglicherweise nicht dazu führt. Und das wird erwartet, nicht wahr? Wenn eine Klassifizierung eingeführt wird, muss immer die Konsistenz überprüft werden.


    Dies ist jedoch oft ein subtiler Fehler.


    Betrachten wir schwerwiegende Fehler.


    Division durch 0 . Ich frage mich, warum dieser Fehler fatal ist. Ich würde in diesem Fall gerne eine Ausnahme auslösen und zur weiteren Bearbeitung fangen. Warum ist sie tödlich? Warum wird mir das spezifische Verhalten meines eigenen Programms auferlegt, und ich kann es in keiner Weise beeinflussen? Geht es in C ++ nicht um Flexibilität und um die Tatsache, dass die Sprache dem Programmierer zugewandt ist? Obwohl ...


    Nullzeiger-Dereferenzierung . Ruft sofort Java ab, das es gibt NullPointerException, das verarbeitet werden kann. Die Poco-Bibliothek ist auch da NullPointerException! Warum wiederholen die Entwickler des Standards mit der Sturheit der Gehörlosen und Stummen dasselbe Mantra?


    Warum habe ich dieses Thema überhaupt angefangen? Es ist sehr wichtig und zeigt nur das Verständnis des Entwicklers für die Fehlerbehandlung. Die Sprache geht hier nicht auf die Fehlerbehandlung als solche ein, sie ist der Auftakt zu einer wichtigen Aktion. Bei der Sprache geht es immer um Anwendungssicherheit, Fehlertoleranz und manchmal, in seltenen und gefährdeten, ich würde sagen, gefährdete Programmtypen, transaktionales und konsistentes Verhalten.


    In diesem Aspekt sehen alle Streitigkeiten über das Teilen durch Null- und Dereferenzierungszeiger wie Vogelkämpfe um Brotkrumen aus. Sicher ein wichtiger Prozess. Aber nur in Bezug auf Vögel.


    Kehren wir zur Trennung in Fatalismus und seine Abwesenheit zurück ... Ich werde mit einer einfachen Frage beginnen: Wenn ich falsche Daten über das Netzwerk erhalten habe, ist dies ein schwerwiegender Fehler?


    Die einfache und korrekte Antwort hängt von ab. Es ist klar, dass dies in den meisten Fällen kein schwerwiegender Fehler ist und alle über das Netzwerk empfangenen Daten überprüft werden müssen. Im Fall eines Datenfehlers sollte 4xx zurückgegeben werden. Gibt es Fälle, in denen Sie abstürzen müssen? Und mit einem wilden Heulen abstürzen, um zum Beispiel SMS zu senden. Ja und nicht eins.


    Es gibt Ich kann ein Beispiel aus meinem Fachgebiet geben: einen verteilten Konsensalgorithmus. Ein Knoten empfängt eine Antwort, die einen Hash von Änderungsketten eines anderen Knotens enthält. Und dieser Hash unterscheidet sich vom lokalen. Dies bedeutet, dass etwas schiefgelaufen ist und die weitere Ausführung ist gefährlich. Die Daten können abweichen, wenn dies nicht bereits der Fall ist. Dies geschieht, wenn die Verfügbarkeit eines Dienstes weniger wichtig ist als seine Konsistenz. In diesem Fall müssen wir fallen und mit einem Sturz, damit alle hören können. Ie Wir haben die Daten über das Netzwerk erhalten, eingecheckt und abgelegt. Für uns ist dieser Fehler nirgends tödlicher. Wird dieser Fehler erwartet? Ja, wir haben den Code mit Validierung geschrieben. Es ist töricht, das Gegenteil zu sagen. Nur wollen wir das Programm danach nicht fortsetzen. Manuelle Eingriffe sind erforderlich, die Automatisierung hat nicht funktioniert.


    Die Wahl des Fatalismus


    Die dunkelste Sache bei der Fehlerbehandlung ist die Entscheidung, was fatal ist und was nicht. Aber diese Frage stellt sich jeder Programmierer während der gesamten Entwicklung. Beantwortet sich also irgendwie auf diese Frage. Die richtige Antwort kommt aus irgendeinem Grund aus der Praxis.


    Dies ist jedoch nur der sichtbare Teil des Eisbergs. In der Tiefe gibt es eine viel monströsere Frage. Um die Tiefe der Tiefen zu verstehen, müssen Sie eine einfache Aufgabe festlegen und versuchen, diese zu beantworten.


    Aufgabe . Machen Sie einen Rahmen aus etwas.


    Es ist einfach Wir machen ein Framework, zum Beispiel Netzwerkinteraktion. Oder Json parsen. Oder im schlimmsten Fall XML. Es stellt sich sofort die Frage: Wenn ein Fehler von einem Socket auftritt, ist es ein schwerwiegender Fehler oder nicht? Ich umschreibe: Sollte ich eine Ausnahme auslösen oder einen Fehler zurückgeben? Ist das eine Ausnahmesituation oder nicht? Und kann wiederkommen std::optional? Oder Monadka? (^ 1)


    Die paradoxe Schlussfolgerung lautet, dass der Rahmen selbst diese Frage nicht beantworten kann. Nur der Code weiß es. Deshalb verwendet die boost.asio- Bibliothek meiner Meinung nach beide Möglichkeiten. Abhängig von den persönlichen Präferenzen des Autors des Codes und der Anwendungslogik können Sie die eine oder andere Methode zur Fehlerbehandlung wählen. Anfangs war mir dieser Ansatz etwas peinlich, aber im Laufe der Zeit wurde ich von der Flexibilität dieses Ansatzes durchdrungen.


    Dies ist jedoch nicht alles. Das Schlimmste, was kommen wird. Hier schreiben wir Anwendungscode, aber es scheint, dass er angewendet wird. Für anderen Code höherer Ebene wird unser Code Bibliothek sein. Ie Die Einteilung in Anwendungs- / Bibliothekscode (Framework usw.) ist eine reine Konvention, die von der Wiederverwendung der Komponenten abhängt. Sie können immer etwas vermasseln und der Anwendungscode wird nicht mehr so ​​sein. Und dies bedeutet sofort, dass die Wahl, was gültig ist und was nicht, bereits durch den Code bestimmt wird und nicht verwendet wird.


    Wenn wir zur Seite springen, stellt sich heraus, dass es manchmal sogar unmöglich ist zu verstehen, wer wen verwendet. Ie Komponente A kann die Komponente verwenden , B , und die Komponente B Komponente A (t2). Ie Wer bestimmt, was passieren wird, ist im Allgemeinen unverständlich.


    Aufwickeln der Spule


    Wenn Sie sich diese ganze Schande anschauen, stellt sich sofort die Frage: Wie leben Sie damit? Was zu tun ist? Welche Richtlinien sollten Sie wählen, um nicht in der Vielfalt zu ertrinken?


    Dazu ist es nützlich, sich umzusehen und zu verstehen, wie solche Probleme an anderen Orten gelöst werden. Wir müssen jedoch mit Bedacht vorgehen: Wir müssen zwischen "Sammeln von Briefmarken" und vollwertigen Lösungen unterscheiden.


    Was ist "Briefmarkensammlung"? Dies ist ein Sammelbegriff, was bedeutet, dass wir ein Ziel ausgetauscht haben, aber etwas anderes. Zum Beispiel: Wir hatten ein Ziel - mit Angehörigen anzurufen und mit ihnen zu kommunizieren. Und wir haben einmal ein teures Spielzeug gekauft, weil es "modisch" und "schön" ist (^ 3). Vertraut Denken Sie, dass das bei Programmierern nicht der Fall ist? Schmeichel dir nicht.


    Fehlerbehandlung ist kein Ziel. Wenn wir über Fehlerbehandlung sprechen, kommen wir sofort zum Stillstand. Denn es ist - ein Weg, um das Ziel zu erreichen. Das anfängliche Ziel ist es, unsere Software zuverlässig, einfach und verständlich zu machen. Solche Ziele sollten festgelegt werden und sich immer daran halten. Und Fehlerbehandlung ist Bullshit, über den es sich nicht zu diskutieren lohnt. Ich möchte eine Ausnahme machen - ja zur Gesundheit! Fehler zurückgegeben - gut gemacht! Willst du Monadka? Glückwunsch, Sie haben die Illusion des Fortschritts geschaffen, aber nur in Ihrem eigenen Kopf (^ 4).


    Hier wollte ich auch schreiben, wie es richtig geht, aber ich habe es schon geschrieben. Die Wunden heilten und hörten auf zu bluten. Kurz gesagt, die Tipps sind:


    1. Trennen Sie sich in Komponenten mit klaren Grenzen.
    2. Beschreibe an den Grenzen, was und wie fliegen kann. Es ist wünschenswert, einheitlich zu sein. Aber viel wichtiger war es.
    3. Machen Sie es einfach, Fehler in dem Code zu behandeln, den es verwenden soll.
    4. Wenn etwas im Inneren verarbeitet werden kann, ohne den Benutzercode zu laden, drücken Sie ihn nicht heraus. Je weniger Fehler ein Benutzer behandeln muss, desto besser.
    5. Respektieren Sie Ihren Benutzer, seien Sie keine Arschlöcher! Schreiben Sie verständliche Schnittstellen mit dem erwarteten Verhalten, sodass Sie keine Kommentare lesen und unlautere Sprache verwenden müssen.

    Der 5. Rat ist der wichtigste, weil er kombiniert die ersten vier.


    PS Als Kind war ich immer neugierig auf den Ameisenhaufen. Tausende Ameisen, die jeweils etwas taten, krabbelten durch ihr Geschäft. Der Prozess ist im Gange. Jetzt schaue ich auch mit Interesse zu. Auch für den Ameisenhaufen. Wo Tausende von Einzelpersonen in ihrem kleinen Geschäft tätig sind. Ich wünsche ihnen viel Glück bei ihrer schwierigen Aufgabe!


    ^ 1: Menschen sind anfällig für schickes Zeug. Nachdem alle genug gespielt hatten, wachten C + + -Programmierer auf und alles begann.


    ^ 2: Dies kann vorkommen, wenn in der Komponente B mehrere Abstraktionen vorhanden sind , die sie verbinden. Siehe Inversionskontrolle .


    ^ 3: Und am nächsten Tag, Bang, und der Bildschirm ist abgestürzt.


    ^ 4: Ich kümmere mich nicht um Monaden, ich habe nichts dagegen zu atmen, wie, schau, hier ist eine Monade, d.h. monoid in der monoiden kategorie von endofunctors! Applaus und zustimmende Nicken sind zu hören. Und irgendwo weit weg, kaum hörbar, jemand Orgasmus.


    Jetzt auch beliebt: