C4 Model und Docs-as-Code
Die meisten Architektur-Diagramme lügen. Nicht aus Absicht, sie veralten einfach. Das C4 Model und Docs-as-Code drehen das um: vier saubere Abstraktionsebenen, als Text-Quelle im selben Git-Repo wie der Code, im Pull Request mitgereviewt und auf der Seite gerendert. So altert das Diagramm mit dem Code statt gegen ihn.
Das Problem: Diagramme, die lügen
Man kennt das Bild im Confluence: ein Architektur-Diagramm, gemalt in Visio oder PowerPoint, zuletzt angefasst vor zwei Jahren. Es zeigt drei Dienste, die es so nicht mehr gibt, und keinen der fünf, die seither dazugekommen sind. Niemand traut ihm, also schaut niemand hin, und weil niemand hinschaut, pflegt es niemand.
Der Grund ist immer derselbe: Die Doku lebt neben dem Code, nicht mit ihm. Sie liegt in einem anderen Werkzeug, hinter einem anderen Login, ohne Review-Gate. Eine Code-Änderung zwingt niemanden, das Bild nachzuziehen. Diagramm und Realität driften auseinander, leise, garantiert, vom ersten Tag an. Genau dieses Driften ist eine Form von Architektur-Schuld, wie sie auch die Systemarchitektur als Praxis adressiert.
C4 Model: Architektur in vier Zoomstufen, die jeder versteht
C4 ist eine Praktik, kein Werkzeug. Man beschreibt ein Software-System auf vier ineinander verschachtelten Abstraktionsebenen (Context, Container, Component, Code) und zoomt von „wer redet mit dem System" bis „welche Klassen". Eine Hierarchie statt ein-Diagramm-für-alles. Erfunden hat sie Simon Brown (c4model.com). Die Idee dahinter ist eine Landkarte mit Zoomstufen: erst das Land, dann die Stadt, dann die Strasse, nie alles auf einmal.
Ebene 1: System Context
Die oberste Ebene zeigt das System als eine einzige Black-Box, umgeben von den Menschen, die es nutzen, und den Fremdsystemen, mit denen es redet. Keine Technologie, keine inneren Bausteine, nur: Wer benutzt das? Womit spricht es? Diese Ebene ist für alle gedacht, auch für Nicht-Techniker.
C4Context
title Systemkontext einer Beispiel-Plattform
Person(kunde, "Kunde")
System(platform, "Beispiel-Plattform")
System_Ext(sso, "SSO / IdP")
System_Ext(pay, "Zahlungsdienst")
System_Ext(mail, "E-Mail-Versand")
Rel(kunde, platform, "nutzt", "HTTPS")
Rel(platform, sso, "authentifiziert")
Rel(platform, pay, "verbucht über")
Rel(platform, mail, "sendet über")
Eine Box in der Mitte, ein Akteur, drei Fremdsysteme. Mehr nicht. Wer dieses Bild liest, versteht in zehn Sekunden, wo das System im Gesamtbild steht, ohne eine Zeile Code zu kennen.
Ebene 2: Container
Jetzt wird dieselbe Box eine Ebene tiefer aufgeklappt. Ein Container ist in C4 „eine Applikation oder ein Datenspeicher … etwas, das laufen muss, damit das Gesamtsystem funktioniert" (c4model.com/abstractions/container), also eine deploybare Einheit mit eigenem Technologie-Tag: die Web-App, die API, die Datenbank, der Worker.
C4Container
title Container einer Beispiel-Plattform
Person(kunde, "Kunde")
System_Boundary(platform, "Beispiel-Plattform") {
Container(web, "Web-App", "Browser-SPA")
Container(api, "API", "Backend")
Container(worker, "Worker", "Async-Jobs")
ContainerDb(db, "Datenbank", "PostgreSQL")
}
System_Ext(sso, "SSO / IdP")
Rel(kunde, web, "besucht", "HTTPS")
Rel(web, api, "ruft auf", "JSON")
Rel(api, db, "liest/schreibt", "SQL")
Rel(api, worker, "stellt Jobs ein")
Rel(worker, db, "liest/schreibt", "SQL")
Rel(api, sso, "authentifiziert", "OIDC")
Dasselbe System, eine Ebene tiefer: Aus der einen Black-Box von Ebene 1 werden vier deploybare Einheiten plus ihre Verbindungen. Jeder Pfeil trägt ein Protokoll, jede Box eine Technologie, genug Detail für ein Architektur-Gespräch, wenig genug, um auf eine Folie zu passen. Wie diese Container-Grenzen entstehen, ist selten Zufall: Sie folgen oft den Team-Grenzen, die Conway's Law beschreibt, und der asynchrone Worker-Pfad ist der Einstieg in eine Event-Driven Architecture.
Ebene 3 und 4: Component und Code, bewusst knapp
Unter dem Container kämen die Components (die Bausteine innerhalb einer deploybaren Einheit) und darunter der Code (Klassen, Interfaces). Diese Ebenen halten wir hier absichtlich kurz, und das ist eine Praktik-Aussage, kein Auslassen.
- Component lohnt nur für die wenigen, wirklich komplexen Container. Für den Rest veraltet diese Ebene schneller, als sie Wert stiftet.
- Code zeichnet man fast nie von Hand. Die IDE generiert das Klassendiagramm in Sekunden und immer aktuell. Ein gemaltes Code-Diagramm ist veraltet, sobald man speichert.
Mehr dazu unten unter „Wann aufhören".
Docs-as-Code: der Workflow
Damit ein Diagramm nicht lügt, muss es dort leben, wo der Code lebt. Das ist Docs-as-Code: Die Diagramm-Quelle ist Plaintext (Mermaid-Markup), liegt im selben Git-Repo neben dem Code, ist diff-bar (kein Binär-Blob, den man nur im Tool öffnen kann) und läuft durch dasselbe Review-Gate wie jede Code-Änderung.
flowchart TB
Src["diagramm.md<br/>(Quelle im Git)"]
PR["Pull Request<br/>(mitgereviewt)"]
CI["CI rendert<br/>das Diagramm"]
Site["Site zeigt<br/>das Diagramm"]
Src -->|"committed neben dem Code"| PR
PR -->|"gemergt"| CI
CI -->|"publiziert"| Site
Site -.->|"Änderung im selben PR"| Src
Der Effekt: Wer den Code ändert, ändert das Diagramm im selben Pull Request, sonst fällt es im Review auf. Dieselbe „alles im Git"-Logik trägt auch GitOps und die strukturierten Entscheidungen in RFCs und ADRs.
Wann aufhören, nicht jede Ebene pflegen
Die wichtigste Praktik-Aussage steht in der C4-Doku selbst: „du musst nicht alle 4 Diagramm-Ebenen verwenden; nur die, die Wert stiften. Die System-Context- und Container-Diagramme reichen für die meisten Entwicklungsteams" (c4model.com/diagrams).
Als Faustregel:
- Context: fast immer wert. Billig zu pflegen, ändert sich selten, erklärt das System jedem.
- Container: fast immer wert. Das Arbeitspferd, die Ebene, auf der Architektur-Entscheidungen sichtbar werden.
- Component: selten. Nur für den einen, wirklich komplexen Container, und nur solange er komplex bleibt.
- Code: fast nie. Das überlässt man der IDE.
Pflege-Kosten gegen Halbwertszeit: Je tiefer die Ebene, desto schneller veraltet sie und desto teurer ist das Nachziehen. Ein Diagramm, das niemand pflegt, ist schlimmer als keines, weil es lügt. Dass diese Diagramme im Review wirklich mitgezogen werden, ist eine Frage gelebter Liefer-Disziplin.
Fallstricke
- „Container" ist nicht Docker. Der C4-Begriff ist älter und allgemeiner als der Docker-Hype. Gemeint ist jede deploybare Laufzeit-Einheit (eine SPA, ein Backend-Dienst, eine Datenbank), egal ob sie je in einem Docker-Image landet. Simon Brown nennt es selbst „unglücklich, dass Containerisierung populär geworden ist", weil viele heute „Container" reflexhaft mit Docker gleichsetzen (c4model.com/abstractions/container).
- Ebenen mischen. Jede Ebene bleibt sauber: Auf Context keine internen Bausteine, auf Container keine Klassen. Sobald ein Diagramm zwei Ebenen vermengt, wird es zum unleserlichen Wildwuchs, den niemand mehr liest.
- Diagramme zu Tode pflegen. Mehr Diagramme sind nicht mehr Klarheit. Gezeichnet wird nur, was Wert stiftet (siehe oben), der Rest ist Pflege-Schuld.
- Mermaid ist nicht das einzige C4-Werkzeug. Mermaid ist ideal, um Diagramme leichtgewichtig im Markdown zu rendern. Wer C4 streng nach Modell betreiben will (ein Modell, viele Sichten, automatisch konsistent), schaut sich Structurizr an, Simon Browns eigenes Diagram-as-Code-Werkzeug. Für die meisten Teams reicht Mermaid; Structurizr ist die Vertiefung, kein Muss.
Verwandte Themen
- Systemarchitektur, die übergeordnete Architektur-Praxis, die C4 visualisiert.
- RFCs und ADRs, die Entscheidungsdokumentation zu C4s Strukturdokumentation im Git.
- Domain-Driven Design und Bounded Context, die fachlichen Grenzen, die oft auf C4-Container abgebildet werden.
- GitOps, das mit Docs-as-Code das „alles im Git"-Prinzip teilt.
- Strangler Fig, der Umbaupfad, dessen Zwischenschritte C4-Diagramme sichtbar machen.
Reference Guide
- Simon Brown C4 Model. Die kanonische Definition der vier Ebenen und der Notation. (2018). c4model.com
- Mermaid Mermaid. Diagramme als Text, direkt im Markdown gerendert. (2014). mermaid.js.org
- Structurizr (Simon Brown) Diagram-as-Code-Werkzeug für „richtiges" C4 jenseits einfacher Diagramme. structurizr.com