Der Cleanroom Software Engineering Process von IBM lieferte 0,1 Defekte pro tausend Zeilen Code. Der Industriedurchschnitt zu dieser Zeit lag zwischen 10 und 50. Der Process wurde dokumentiert, repliziert und unabhängig über multiple Projekte und Sprachen hinweg verifiziert. Dann verschwand er.

Nicht, weil eine bessere Methode ihn ersetzt hat. Zero-defect engineering verschwand, weil sich die ökonomischen Bedingungen, die es wertvoll machten, änderten, und die Bedingungen, die es möglich machten, sich nie über eine Handvoll Government Contractors hinaus verbreiteten.

Das Problem: Defekte wurden von Anfang an designed in

Die meiste Software basiert auf der stillschweigenden Annahme, dass Bugs unvermeidlich sind. Man schreibt Code, führt ihn aus, findet die Probleme, behebt sie. Die Schleife fühlt sich produktiv an. Sie ist auch ein Zugeständnis daran, dass dein Process Defekte als normalen Output produziert.

Cleanroom wies diese Annahme vollständig zurück. Entwickelt von Harlan Mills bei IBM in den 1970ern, behandelte die Methode Software wie Halbleiterfertigung. Man testet keine Qualität in einen Chip nach der Fertigung hinein. Man verhindert die Bedingungen, die Defekte überhaupt erst entstehen lassen.

Die Methode hatte drei ineinandergreifende Praktiken. Incremental Development unter statistical process control. Function-theoretic design mit black-box, state-box und clear-box Strukturen. Und die Regel, die die meisten Köpfe brach: Diejenigen, die den Code geschrieben hatten, durften ihn nicht ausführen.

Das war kein Sadismus. Es war die forcing function. Wenn du deinen Code nicht ausführen kannst, um zu sehen, ob er funktioniert, musst du über Korrektheit nachdenken, bevor du tippst.

Die Zahlen waren kein Zufall

Die IBM Federal Systems Division wendete Cleanroom auf ein NASA Satellite Control System an und maß 0,1 Defekte pro KLOC im finalen Test. Ein COBOL Billing System erreichte 0,3. Ein Ada Real-Time System erreichte 0,4. Die Ergebnisse hielten über Teams, Anwendungsdomänen und Programmiersprachen hinweg stand.

Der Process komprimierte auch die Schedules. Industriedaten zu dieser Zeit zeigten, dass 50 bis 70 Prozent des Software-Aufwands für Testing und Debugging draufgingen. Cleanroom Teams verbrachten diese Zeit stattdessen mit Design. Der Code funktionierte beim ersten Mal, als er kompilierte.

Warum ein funktionierender Process aufgegeben wurde

Wenn die Methode so effektiv war, warum verschwand sie?

Die kurze Antwort ist, dass sich die Software-Ökonomie zwischen 1990 und 2010 umkehrte. Die lange Antwort ist, dass zero-defect engineering für eine Welt optimiert war, die aufhörte zu existieren.

In den 1970ern und 1980ern wurde Software auf physischen Medien ausgeliefert. Ein Bug in Production erforderte einen Recall, eine Patch-Disk oder einen Techniker vor Ort. Die Kosten eines Defekts waren enorm. Zero-defect engineering war teuer, aber ein einzelner vermiedener Recall bezahlte den gesamten Process.

Das Web änderte die Cost Function. Heute deployen wir over the wire. Ein Bug erreicht Production, wir rollen in Minuten zurück, wir patchen in Stunden. Die Kosten eines einzelnen Defekts fielen um Größenordnungen. Die Kosten von zero-defect engineering fielen überhaupt nicht. Sie erfordert nach wie vor formal verification, statistical process control und dass Entwickler ihren eigenen Code nicht ausführen. Diese Praktiken kosten Zeit, die modernes Product Development nicht aufbringen will.

Die Interdependency Trap

Cleanroom ist kein Menü. Du kannst nicht einfach die Teile adoptieren, die dir gefallen.

Statistical process control funktioniert nur, wenn du jeden Increment misst und anhältst, wenn defect targets verfehlt werden. Box structures funktionieren nur, wenn du jedes Level verifizierst, bevor du das nächste schreibst. Die no-execution rule funktioniert nur, wenn sie absolut ist. Ein Entwickler, der “nur schnell checkt, ob das kompiliert”, zerstört die forcing function.

Partielle Adoption gibt dir keine der Benefits und den gesamten Overhead. Ein Team kann Cleanroom nicht für einen Sprint ausprobieren. Sie müssen ihren gesamten Cycle umstrukturieren, jeden Entwickler umschulen und Process-Daten über Monate sammeln. Die meisten Manager, die diesem Proposal gegenüberstehen, stellen stattdessen einen weiteren QA Engineer ein.

Das Velocity Premium killed the Quality Premium

Moderne Software konkurriert auf time-to-market. Der first mover advantage in consumer software ist mehr wert als die Kosten, Bugs nach dem Launch zu beheben. Investoren belohnen growth curves, nicht defect density metrics.

Zero-defect engineering optimiert für ein anderes Scoreboard. Es nimmt an, dass correctness die primäre Constraint ist und schedule pressure sekundär. Dies war für NASA Satellite Control Systems wahr. Es ist nicht wahr für ein Startup, das vor seinem Competitor shippen will.

Die kulturelle Divergenz läuft tiefer. Entwickler mögen laufenden Code. Die immediate feedback loop von write-run-fix ist befriedigend. Cleanroom bittet dich, diese Befriedigung aufzuschieben, bis du jeden edge case durchdacht hast.

Die Industrie wählte einen anderen social contract. Wir tolerieren Bugs im Austausch für speed, und wir patchen sie im Austausch für continuous feedback. Es ist ein rationaler trade. Es ist auch der Grund, warum die durchschnittliche web application eine defect rate näher am Durchschnitt der 1980er Jahre hat als an IBMs Cleanroom-Zahlen.

Wofür wir es eingetauscht haben

Der Ersatz war eine Konstellation von Praktiken, die iteration über correctness priorisieren.

Continuous integration machte das Finden von Bugs schneller, aber es machte Code nicht correct by construction. Agile verkürzte feedback loops, aber es verkürzte auch design phases. Test-driven development nimmt immer noch die write-test-fix loop an, die Cleanroom zurückwies.

Keine dieser Praktiken ist schlecht. Der moderne Stack optimiert dafür, herauszufinden, was User wollen. Zero-defect engineering optimierte dafür, eine bekannte specification korrekt zu implementieren.

Was du stehlen kannst, ohne das ganze System zu adoptieren

Du kannst wahrscheinlich keinen vollständigen Cleanroom in deinem Unternehmen implementieren. Aber die underlying principles transferieren, und einige moderne Tools approximieren die rigour der Methode ohne deren overhead.

Write contracts, not just comments. Definiere preconditions und postconditions explizit, und enforce sie im Code.

from dataclasses import dataclass
from decimal import Decimal

@dataclass(frozen=True)
class Transfer:
    from_balance: Decimal
    to_balance: Decimal
    amount: Decimal

    def execute(self) -> tuple[Decimal, Decimal]:
        # Preconditions stated and checked
        assert self.amount > 0, "transfer amount must be positive"
        assert self.from_balance >= self.amount, "insufficient funds"

        new_from = self.from_balance - self.amount
        new_to = self.to_balance + self.amount

        # Postcondition: total value is conserved
        assert new_from + new_to == self.from_balance + self.to_balance
        return new_from, new_to

Durch das Encoding von Annahmen als executable checks verwandelst du implizites reasoning in explicit guards, die dich zwingen, während des developments edge cases durchzudenken.

Use property-based testing as statistical process control. Cleanroom nutzte statistical testing basierend auf usage profiles. Moderne property-based testing tools machen etwas Analoges, indem sie random inputs generieren und invariants verifizieren.

from hypothesis import given, strategies as st
from datetime import datetime, timedelta

@given(
    start=st.datetimes(min_value=datetime(2000, 1, 1)),
    delta=st.timedeltas(min_value=timedelta(0), max_value=timedelta(days=365))
)
def test_duration_roundtrips(start, delta):
    """Adding then subtracting the same duration must return the original."""
    assert start + delta - delta == start

Dieser Test assertet eine mathematical property über einen enormen input space. Wenn er ein Gegenbeispiel findet, shrinkt er auf den minimalen failing case. Du checkst die Struktur der computation, nicht spezifische Beispiele.

Make invalid states unrepresentable. Cleanrooms box structure methodology drehte sich darum, Verhalten auf zunehmenden Detaillevels zu definieren. Ein modernes Äquivalent ist die Nutzung von static types, um illegale states zu verhindern.

from typing import NewType

UserId = NewType("UserId", int)
OrderId = NewType("OrderId", int)

def fetch_order(order_id: OrderId) -> dict:
    ...

# This will not compile in a typed codebase:
# fetch_order(UserId(42))  # type error: expected OrderId, got UserId

Der type checker wird zu einer verification layer, die vor jedem Test läuft. Du kannst keine user ID dort übergeben, wo eine order ID hingehört, weil das type system den Fehler strukturell unmöglich macht.

Wo das noch wichtig ist

Zero-defect engineering ist nicht falsch geworden. Es wurde niche.

Es wird immer noch in safety-critical Domänen genutzt, wo ein einzelner Bug Menschen tötet. Medical devices, avionics und nuclear control systems nutzen nach wie vor processes, die von Cleanroom abgeleitet sind, weil die Kosten eines Defekts astronomisch bleiben. Die FDA und DO-178C Standards bewahren viele der gleichen Ideen unter anderen Namen.

Für den Rest von uns kostet ein Bug in einer web application ein support ticket und einen deploy. Ein Bug in einem pacemaker kostet ein Leben. Die Methode hat nicht aufgehört zu funktionieren. Wir haben aufgehört, sie zu brauchen.

Die uncomfortable truth

Zero-defect engineering verschwand nicht, weil es fehlschlug, sondern weil die Industrie success neu definierte. Das Ziel verschob sich von “software shippen, die beim ersten Mal funktioniert” zu “software so schnell shippen, dass broken versions ersetzt werden, bevor User sie bemerken.”

Das ist ein verteidigbarer trade. Er baute das moderne Internet. Es bedeutet auch, dass die meiste Software mit processes gebaut wird, die mathematisch garantiert Defekte hinterlassen, und wir dies akzeptieren, weil das Beheben später nun billig genug ist.

Du musst Cleanroom nicht adoptieren, um besseren Code zu schreiben. Starte mit einer function. Schreibe ihren contract vor ihrem body. Führe property-based tests gegen deine invariants aus. Nutze types, um illegale states unerreichbar zu machen. Track, wo deine Bugs herkommen, und behebe den process, der sie produziert.

Zero defects pro KLOC ist wahrscheinlich nicht dein Ziel. Aber das Verständnis, warum die Methode funktionierte und warum wir aufhörten, uns dafür zu interessieren, sagt dir etwas Wichtiges darüber, worauf dein process tatsächlich optimiert ist. Die meisten Teams haben diese Wahl nie explizit getroffen. Sie haben sie von einer Industrie geerbt, die vor Jahrzehnten velocity über correctness wählte, und nie zurückgeschaut.