Defensive Programming nach McConnell ist die Programmierpraxis aus Kapitel 8 von Steve McConnells Code Complete (2. Auflage, 2004), die ein Programm vor ungültigen Eingaben schützt, damit schlechte Daten nie ein stilles falsches Ergebnis liefern. Eine Barrikade teilt den Code: Öffentliche Schnittstellen außerhalb validieren Eingaben und behandeln Fehler, Code innerhalb gilt als sauber und nutzt Assertions für Zustände, die nie eintreten dürfen. Jedes System wählt zudem zwischen Robustheit und Korrektheit.

Defensive Programming according to McConnell

Details
Vollständiger Name

Defensive Programming, wie Steve McConnell es in Code Complete (2. Auflage, Microsoft Press 2004), Kapitel 8 „Defensive Programming“, beschreibt

Auch bekannt als

defensives Programmieren, defensive coding

Kernkonzepte:

Das Programm vor ungültigen Eingaben schützen

Daten von außen — aus Dateien, von Benutzern, aus dem Netz, aus anderen Systemen — werden geprüft, bevor das Programm sie verwendet. Eine schlechte Eingabe bekommt eine definierte Antwort: Ablehnung, Fehlercode, protokollierter und behandelter Fehler. Nie ein stilles falsches Ergebnis.

Die Barrikade

McConnell zieht eine Linie durch das Programm. Außerhalb gelten Daten als nicht vertrauenswürdig, und jede öffentliche Schnittstelle validiert. Innerhalb gelten sie als sauber, und interne Routinen wiederholen die Prüfungen nicht. Die Barrikade verhindert, dass defensives Programmieren zu Null-Prüfungen in jeder Hilfsfunktion verkommt.

Fehlerbehandlung außen, Assertions innen

Was im Betrieb vorkommen kann — eine fehlende Datei, ein kaputter Datensatz --, bekommt Fehlerbehandlung an der Barrikade. Was bei korrektem Code nie vorkommen darf — eine Hilfsfunktion, die einen Null-Puffer erhält --, bekommt innen eine Assertion. Eine Assertion dokumentiert eine Annahme und schlägt während der Entwicklung laut fehl; sie ersetzt keine Eingabevalidierung.

Robustheit gegen Korrektheit

Manche Systeme sollen mit einer schlechteren Antwort weiterlaufen, andere müssen anhalten, statt eine falsche zu geben. Ein Texteditor darf einen Standardwert einsetzen, eine Strahlentherapie-Steuerung nicht. Die Wahl gehört zur Praxis und ist keine Nebensache.

Defensiv gegenüber dem defensiven Programmieren

McConnells Kapitel endet mit einer Warnung vor dem Übertreiben. Prüfungen überall machen den Code langsamer, länger und schwerer lesbar, und Fehlerbehandlung, die Fehler versteckt, macht sie schwerer auffindbar. Reine Debug-Hilfen werden für die Produktion entfernt oder abgeschaltet; Prüfungen echter Eingaben bleiben.

Nicht Design by Contract, aber damit vereinbar

design-by-contract weist jede Prüfung genau einer Partei zu und lehnt doppelte Prüfungen auf beiden Seiten ab. Defensive Programming startet vom umgekehrten Reflex: prüfen, wo immer ein schlechter Wert ankommen könnte. Die Barrikade versöhnt beides — einmal an der Grenze validieren, innen mit Vertrag und Assertion argumentieren. Benennen, welches von beiden gemeint ist: schwächere Modelle vermischen sie, und ein getestetes Modell schrieb Defensive Programming Bertrand Meyer zu.

Wann zu verwenden:

  • Code, der Eingaben liest, die er nicht kontrolliert: Parser, Datei-Importer, API-Handler, Gerätetreiber

  • Entscheiden, wo in einem Modul validiert wird — einmal an der öffentlichen Schnittstelle statt in jeder privaten Hilfsfunktion

  • Für ein System zwischen Robustheit und Korrektheit wählen und die Wahl aufschreiben

  • Fehlerbehandlung reviewen, die Exceptions verschluckt oder für unmögliche Zustände plausible Standardwerte liefert

  • Ein Modell steuern: „wende Defensive Programming nach McConnell an, mit einer Barrikade an der öffentlichen API und Assertions innen“ verlangt eine Platzierung, nicht nur mehr Prüfungen

Häufige Missverständnisse:

  • ❌ „Defensiv heißt, alles in try/catch zu packen“ — Fehler zu verschlucken ist das Gegenteil der Praxis; ein versteckter Fehler ist schwerer zu finden als ein Absturz

  • ❌ „Jedes Argument in jeder Funktion prüfen“ — die Barrikade gibt es, damit interner Code die Grenzprüfungen nicht wiederholt

  • ❌ „Assertions sind Eingabevalidierung“ — Assertions fangen Programmierfehler und können wegkompiliert werden; Benutzereingaben brauchen echte Fehlerbehandlung

  • ❌ „Defensive Programming und Fail Fast sind Gegensätze“ — Assertions, die bei der ersten verletzten Annahme anhalten, gehören zur Praxis

  • ❌ „Defensive Programming ist eine Sicherheitsarchitektur“ — das ist defense-in-depth; hier geht es um eine Programmierpraxis innerhalb eines Programms

  • ✓ „An der Grenze validieren, innen Assertions setzen und entscheiden, ob dieses System Robustheit oder Korrektheit bevorzugt“

Kritik:

  • Probleme zu umgehen lässt Software langsam scheitern. Jim Shores Kolumne in IEEE Software richtet sich gegen die Robustheits-Hälfte der Praxis: „Some people recommend making your software robust by working around problems automatically. This results in the software 'failing slowly.'“ Sein Gegenmittel sind Assertions, die bei der ersten verletzten Annahme anhalten — und genau das enthalten McConnells Ratschläge zu Assertions und Barrikade bereits. Die Kritik trifft also die Alltagslesart „abfangen und weitermachen“, nicht das Kapitel. Shore, „Fail Fast“, IEEE Software 21(5), September/Oktober 2004, Design-Kolumne.