Design by Contract ist ein Entwurfsansatz von Bertrand Meyer, geprägt für die Sprache Eiffel, der jede Routine als Vertrag zwischen Aufrufer und Implementierung behandelt. Vorbedingungen nennen die Pflichten des Aufrufers, Nachbedingungen die Zusicherungen der Routine, Klasseninvarianten die Bedingungen, die jede Instanz stets erfüllt. Eine verletzte Klausel zeigt, auf welcher Seite der Fehler liegt.
Design by Contract
Details
- Auch bekannt als
-
DbC, Programming by Contract
Kernkonzepte:
- Vorbedingung (Precondition)
-
Die Pflicht des Aufrufers — eine Bedingung, die vor dem Aufruf einer Routine gelten muss. Wird sie verletzt, liegt der Fehler beim Client, nicht beim Supplier.
- Nachbedingung (Postcondition)
-
Die Zusicherung des Suppliers — eine Bedingung, deren Erfüllung die Routine beim Rücksprung garantiert, sofern die Vorbedingungen galten. Wird sie verletzt, liegt der Fehler beim Supplier.
- Klasseninvariante (Class invariant)
-
Eine Konsistenzbedingung, die für jede Instanz in jedem beobachtbaren Zustand gilt — vor und nach jeder öffentlichen Routine. Sie schränkt die Abstraktion über ihre gesamte Lebensdauer ein.
- Client/Supplier-Metapher
-
Eine Routine ist ein Vertrag zwischen Aufrufer (Client) und Implementierung (Supplier): Die Pflicht jeder Partei ist der Vorteil der anderen. Der Supplier muss Zustände, die seine Vorbedingungen ausschließen, nicht behandeln.
- Schuldzuweisung (Blame assignment)
-
Da jede Klausel genau eine verantwortliche Partei hat, lokalisiert eine verletzte Zusicherung den Defekt: eine gebrochene Vorbedingung beschuldigt den Aufrufer, eine gebrochene Nachbedingung oder Invariante die Implementierung. Keine defensive Doppelprüfung auf beiden Seiten.
- Vertragsvererbung (Contract inheritance)
-
Subklassen dürfen Vorbedingungen abschwächen (nicht mehr verlangen als die Oberklasse) und Nachbedingungen sowie Invarianten verstärken (nicht weniger zusichern). Das ist genau verhaltensbasierte Subtypisierung.
- Bezug zum LSP
-
Die obigen Vererbungsregeln sind die vertragsbezogene Formulierung des Liskovschen Substitutionsprinzips. Ein Subtyp, der sie einhält, ist ohne Überraschungen für Clients gegen seinen Obertyp austauschbar.
- Spannung mit Postels Gesetz
-
DbC sagt, sei strikt bei Vorbedingungen und scheitere hart bei Verletzung. Postels Gesetz sagt, sei liberal in dem, was du akzeptierst. Beide gelten an verschiedenen Grenzen — DbC regelt vertrauenswürdige interne Modulnähte; Postel regelt nicht vertrauenswürdige externe Eingaben am Systemrand. Eine Verwechslung lässt ungültigen Zustand nach innen lecken.
- Schlüsselvertreter
-
Bertrand Meyer, der den Begriff für die Sprache Eiffel prägte (~1986) und ihn in Object-Oriented Software Construction (1988, 1997) ausarbeitete. "Design by Contract" ist eine Marke von Eiffel Software (registriert 2004).
Wann zu verwenden:
-
Die Pflichten und Zusicherungen der öffentlichen API eines Moduls präzise spezifizieren
-
Klassenhierarchien entwerfen, die austauschbar bleiben müssen (verhaltensbasierte Subtypisierung)
-
Eingabevalidierung an eine einzige, klar definierte Naht schieben, statt defensive Prüfungen zu verstreuen
-
Ein LLM anweisen, Routinen mit expliziten Vor-/Nachbedingungen und Invarianten zu generieren
-
Über Korrektheit nachdenken, bevor man zu erschöpfenden Tests greift (ergänzt das Testen, ersetzt es nicht)
Verwandte Anker:
-
Liskovsches Substitutionsprinzip — die Vererbungsregeln von DbC formalisieren verhaltensbasierte Subtypisierung
-
SOLID-Prinzipien — DbC stärkt die Austauschbarkeitsgarantie, auf die SOLID baut
-
Postels Gesetz — gegensätzliche Haltung zur Eingabestriktheit; über die Grenzenscope versöhnt
-
EARS Requirements — Vor-/Nachbedingungen formulieren Anforderungen als prüfbare Zusicherungen
-
Defensive Programming according to McConnell — der umgekehrte Reflex, überall zu prüfen, wo schlechte Daten ankommen könnten; McConnells Barrikade versöhnt beides, indem sie einmal an der Grenze validiert
Kritik:
-
Bjarne Stroustrup zum C26-Contracts-Entwurf (https://www.theregister.com/2026/03/31/cplusplus26_approved/[The Register], 2026) — "It's claimed to be a minimal viable product. It's not minimal, it's not viable" — und er empfahl, Contracts in C nicht zu verwenden. Natives, durchgängiges DbC bleibt weitgehend auf Eiffel beschränkt; Mainstream-Sprachen erhalten nur teilweise oder umstrittene Unterstützung.
-
Ausdrucksgrenze (Supporting Design by Contract in Java) — in einer Teilmenge der Wirtssprache geschriebene Verträge können oft volle funktionale Korrektheit nicht ausdrücken und erzwingen umständliche Umwege; zur Laufzeit geprüfte Verträge fangen Verletzungen spät ab, statt ihre Abwesenheit zu beweisen.
Aktueller Status:
-
C-Contracts wurden 2019 aus dem C20-Arbeitsentwurf entfernt, von der Study Group SG21 neu begonnen und erst mit C26 in den Standard aufgenommen (https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2025/p2899r1.pdf[P2899 Rationale]; https://www.theregister.com/2026/03/31/cplusplus26_approved/[The Register], 2026) — DbC auf Sprachebene bleibt außerhalb von Eiffel also jung und umstritten. Trainingsdaten-Priors vor 2026 behandeln C-Contracts wahrscheinlich als fehlend oder experimentell.
-
Native Unterstützung gibt es in Ada 2012, Eiffel, D, Kotlin und anderen; Python setzt auf Drittanbieter-Bibliotheken (z. B.
deal,icontract) statt auf ein Sprachfeature.