Dynamisches C4-Diagramm: Leitfaden mit Beispielen
Ein Container-Diagramm sagt Ihnen, dass die API mit dem Order Service spricht, der Order Service mit Kafka und der Notification Service aus Kafka liest. Es sagt Ihnen nicht, was passiert, und in welcher Reihenfolge, wenn ein Kunde auf Bestellen klickt. Wird die Zahlung vor oder nach dem Schreiben der Bestellzeile eingezogen? Wartet die Bestätigungs-E-Mail auf das Lager? Das sind die Fragen, die in einem Incident-Review gestellt werden, und die statischen Diagramme können sie nicht beantworten.
Genau das ist die Aufgabe des dynamischen C4-Diagramms. Es nimmt Elemente, die Sie bereits gezeichnet haben, und nummeriert die Interaktionen zwischen ihnen für ein bestimmtes Szenario. Dieser Leitfaden erklärt, was ein dynamisches Diagramm ist, wie es sich von einem UML-Sequenzdiagramm unterscheidet, wann es sich lohnt (seltener, als man denkt), zeigt ein vollständiges Beispiel, die üblichen Fehler und wie Sie verhindern, dass es veraltet, wenn sich das statische Modell ändert.
Wenn C4 neu für Sie ist, beginnen Sie mit was das C4-Modell ist. Das Beispiel unten baut auf der Art von Diagramm auf, die im Leitfaden zum Container-Diagramm behandelt wird.
Was ein dynamisches Diagramm ist
Das dynamische Diagramm ist eines der ergänzenden Diagramme des C4-Modells, neben dem System-Landscape- und dem Deployment-Diagramm. Es gehört nicht zu den vier Kernebenen. Es steht neben ihnen und leiht sich ihre Elemente.
Die Definition auf c4model.com ist kurz:
- Umfang: „Ein bestimmtes Feature, eine Story, ein Use Case usw."
- Elemente: „Nach Ihrer Wahl – Sie können Softwaresysteme, Container oder Komponenten zeigen, die zur Laufzeit interagieren."
- Zielgruppe: „Technische und nicht-technische Personen, innerhalb und außerhalb des Softwareentwicklungsteams."
- Empfohlen? „Nein, dynamische Diagramme sollten sparsam eingesetzt werden, um interessante/wiederkehrende Muster oder Features zu zeigen, die eine komplizierte Abfolge von Interaktionen erfordern."
Aus dieser Definition folgen zwei Dinge.
Erstens zeigt ein dynamisches Diagramm Instanzen von Beziehungen, die Sie bereits haben. Hat das Container-Diagramm einen Pfeil vom Order Service zu Kafka, sagt das dynamische Diagramm: „und in Schritt 4 des Checkouts wird dieser Pfeil genutzt, um OrderPlaced zu veröffentlichen". Die Structurizr-DSL macht das explizit: Laut ihrer Dokumentation zeigen Sie mit einer dynamischen View „Instanzen von Beziehungen, die im statischen Modell definiert sind", und die Beziehung muss dort zuerst existieren (Structurizr DSL reference). Diese Einschränkung ist nützlich. Sie verhindert, dass das dynamische Diagramm einen Aufruf erfindet, den das statische Modell nicht kennt.
Zweitens gilt ein Szenario pro Diagramm. Nicht „wie der Order Service funktioniert", sondern „Kunde gibt eine Bestellung auf, Kartenzahlung, Artikel auf Lager". Der Fehlerpfad bekommt ein eigenes Diagramm, falls er überhaupt eines wert ist.
Die Reihenfolge wird mit Nummern an den Pfeilen dargestellt. Das ist die ganze Notation: dieselben Kästen, dieselben Pfeile, plus eine Sequenznummer und eine Beschreibung dessen, was in diesem Schritt passiert.
Dynamisches Diagramm vs. Sequenzdiagramm
„C4-Sequenzdiagramm" ist eine häufige Suche, und die Verwechslung ist verständlich: Beide Diagramme beantworten dieselbe Frage. Die C4-Website sagt, dass das dynamische Diagramm in zwei Stilen gezeichnet werden kann, die dieselbe Information tragen:
- Kollaborationsstil. Frei angeordnete Kästen (meist dort, wo sie auch im Container-Diagramm stehen) mit nummerierten Pfeilen dazwischen. C4 merkt an, dass dieser Stil auf dem UML-Kommunikationsdiagramm basiert, früher Kollaborationsdiagramm genannt.
- Sequenzstil. Elemente als Spalten am oberen Rand, die Zeit läuft nach unten, Pfeile zwischen Lebenslinien. Das sieht aus wie ein UML-Sequenzdiagramm, aber die Teilnehmer sind C4-Elemente.
Ein dynamisches Diagramm im Sequenzstil ist also eine Art Sequenzdiagramm. Die eigentlichen Unterschiede bestehen zu einem klassischen, aus dem Code gezeichneten UML-Sequenzdiagramm:
| Dynamisches C4-Diagramm | UML-Sequenzdiagramm (typische Nutzung) | |
|---|---|---|
| Teilnehmer | Systeme, Container oder Komponenten aus Ihrem C4-Modell | Objekte, Klassen, oft auf Methodenebene |
| Was ein Pfeil bedeutet | Eine Nutzung einer Beziehung aus dem statischen Modell, mit ihrem Protokoll | Eine Nachricht oder ein Methodenaufruf |
| Detailgrad | Architektonisch: „veröffentlicht OrderPlaced (Kafka)" |
Oft Implementierung: validate(), save(), Rückgabewerte |
| Notation | Kästen und nummerierte Pfeile, eine Legende erklärt Ungewöhnliches | Lebenslinien, Aktivierungsbalken, kombinierte Fragmente (alt, loop, par) |
| Verbindung zu anderen Diagrammen | Verwendet Elemente aus dem Container- oder Komponentendiagramm wieder | Meist eigenständig |
Nutzen Sie den Kollaborationsstil, wenn die räumliche Anordnung Bedeutung trägt, etwa wenn die Leser das Container-Diagramm schon kennen und der Ablauf darüber erscheinen soll. Nutzen Sie den Sequenzstil, wenn die Reihenfolge der eigentliche Punkt ist, es mehr als etwa acht Schritte gibt oder viel Hin und Her zwischen zwei Elementen stattfindet (Request, Response, Callback). Keiner ist richtiger; C4 überlässt Ihnen die Wahl.
Wenn Sie alt- und loop-Fragmente brauchen, um ein Szenario zu erklären, ist das oft ein Zeichen dafür, dass Sie einen Algorithmus beschreiben statt einer Architektur. Zeichnen Sie die architektonische Fassung als dynamisches Diagramm und überlassen Sie die detaillierte Fassung einem UML-Sequenzdiagramm neben dem Code, falls jemand sie braucht. Unser Vergleich C4 vs. UML zeigt, wo welche Notation passt.
Wann sich eines lohnt (und wann nicht)
Die eigene Antwort von C4 auf „empfohlen?" ist Nein, und das sollte man ernst nehmen. Jedes dynamische Diagramm ist ein weiteres Artefakt, das sich ändern muss, wenn sich die Architektur ändert. Zeichnen Sie eines, wenn das Szenario mindestens eines dieser Kriterien erfüllt:
- Die Reihenfolge ist aus dem statischen Diagramm nicht ersichtlich. Checkout, Zahlungseinzug, eine Saga, die bei Fehlern kompensiert. Wenn ein Senior Engineer im Team die Reihenfolge falsch wiedergeben würde, zeichnen Sie sie.
- Das Szenario durchquert mehrere Container oder Systeme. Alles, was vier oder mehr Container berührt oder Ihr System verlässt und zurückkommt (Webhooks, Callbacks, Weiterleitungen zu Drittanbietern wie 3-D Secure).
- Es ist asynchron. Sobald eine Queue beteiligt ist, zeigt das statische Diagramm, dass A und B beide Kafka nutzen, aber nicht, dass B nach A läuft oder dass A nicht darauf wartet.
- Es wiederholt sich. Ein Muster, das an vielen Stellen verwendet wird (wie jeder Service einen Request authentifiziert, wie jeder Schreibvorgang ein Event auslöst), ist ein Diagramm wert, auf das der Rest der Doku verweisen kann.
- Jemand fragt in einem Review oder Incident danach. Das ist der beste Auslöser. Wenn ein Incident-Review zwanzig Minuten damit verbracht hat, einen Ablauf am Whiteboard zu rekonstruieren, verdient dieser Ablauf ein Diagramm.
Lassen Sie es weg, wenn:
- Der Ablauf eine gerade Linie ist. Browser, API, Datenbank, zurück. Das sagt das Container-Diagramm schon.
- Es CRUD ist. Fünf dynamische Diagramme für Create, Read, Update, Delete und List bringen nichts.
- Niemand es lesen wird. Ein dynamisches Diagramm für jede User Story ist ein Dokumentations-Backlog, keine Dokumentation.
Ein vernünftiges Ziel für ein typisches Produkt ist eine Handvoll: die zwei oder drei Journeys, die Geld bringen oder Leute nachts wecken, plus ein oder zwei wiederkehrende Muster.
Durchgearbeitetes Beispiel: „Kunde gibt eine Bestellung auf"
Nehmen wir das E-Commerce-System aus unserem vollständigen Leitfaden. Sein Container-Diagramm enthält eine React-Single-Page-App, ein Kong-API-Gateway, Go-Services für Bestellungen, Produkte und Benutzer (jeder mit eigener PostgreSQL-Datenbank), Kafka und einen Notification Service. Auf Ebene 1 spricht das System außerdem mit Stripe als Payment Gateway und mit SendGrid für E-Mails.
Hier sind die Beziehungen aus dem statischen Modell, die dieses Szenario nutzt. Jeder der folgenden Schritte muss einer davon entsprechen.
[Kunde] --> [Single-Page Application (React)] : Nutzt (HTTPS)
[Single-Page Application] --> [API Gateway (Kong)] : Ruft die API auf (HTTPS/JSON)
[API Gateway] --> [Order Service (Go)] : Leitet Requests weiter
[Order Service] --> [Product Service (Go)] : Prüft den Bestand (gRPC)
[Order Service] --> [Payment Gateway (Stripe)] : Autorisiert Zahlungen (HTTPS/REST)
[Order Service] --> [Order Database (PostgreSQL)] : Liest/schreibt Bestellungen (SQL)
[Order Service] --> [Message Queue (Kafka)] : Veröffentlicht Bestell-Events
[Notification Service (Go)] --> [Message Queue] : Konsumiert Bestell-Events
[Notification Service] --> [Email Service (SendGrid)] : Sendet E-Mails (HTTPS)
Das dynamische Diagramm im Kollaborationsstil
Die nummerierten Interaktionen, auf dieselben Kästen gezeichnet:
1. [Kunde] -> [Single-Page Application] : Klickt auf "Bestellen"
2. [Single-Page Application] -> [API Gateway] : POST /orders (HTTPS/JSON)
3. [API Gateway] -> [Order Service] : Leitet den authentifizierten Request weiter
4. [Order Service] -> [Product Service] : Reserviert Bestand für jede Position (gRPC)
5. [Order Service] -> [Payment Gateway (Stripe)] : Autorisiert die Karte über den Bestellbetrag (HTTPS)
6. [Order Service] -> [Order Database] : Schreibt die Bestellung mit Status "placed" (SQL)
7. [Order Service] -> [Message Queue] : Veröffentlicht OrderPlaced (Kafka)
8. [Order Service] -> [Single-Page Application] : Gibt 201 mit der Bestellnummer zurück (über das Gateway)
9. [Notification Service] -> [Message Queue] : Konsumiert OrderPlaced (Kafka)
10. [Notification Service] -> [Email Service (SendGrid)] : Sendet die Bestätigungs-E-Mail (HTTPS)
Auf dem Container-Diagramm angeordnet, erzählen die Nummern die Geschichte: Die Schritte 1 bis 8 sind synchron und passieren, während der Kunde wartet, die Schritte 9 und 10 passieren danach, und der Kunde wartet nie auf sie.
Dasselbe Szenario im Sequenzstil
| Nr. | Von | Nach | Was passiert | Synchron? |
|---|---|---|---|---|
| 1 | Kunde | Single-Page Application | Klickt auf „Bestellen" | ja |
| 2 | Single-Page Application | API Gateway | POST /orders |
ja |
| 3 | API Gateway | Order Service | Leitet den Request weiter | ja |
| 4 | Order Service | Product Service | Reserviert Bestand | ja |
| 5 | Order Service | Payment Gateway (Stripe) | Autorisiert die Karte | ja |
| 6 | Order Service | Order Database | Schreibt die Bestellung | ja |
| 7 | Order Service | Message Queue | Veröffentlicht OrderPlaced |
nein (fire and forget) |
| 8 | Order Service | Single-Page Application | Gibt 201 mit der Bestellnummer zurück | ja |
| 9 | Notification Service | Message Queue | Konsumiert OrderPlaced |
asynchron |
| 10 | Notification Service | Email Service (SendGrid) | Sendet die Bestätigung | asynchron |
Eine solche Tabelle ist eine völlig brauchbare Art, ein dynamisches Diagramm aufzuschreiben. Als Lebenslinien gezeichnet ist es der Sequenzstil.
Was das Diagramm Ihnen sagt
Beim Lesen der zehn Schritte können Sie Fragen beantworten, die das Container-Diagramm nicht beantworten konnte:
- Was passiert, wenn Stripe ausfällt? Der Bestand ist in Schritt 4 bereits reserviert, wenn die Autorisierung in Schritt 5 scheitert. Jemand muss ihn wieder freigeben. Das Diagramm macht offensichtlich, dass der Order Service einen Kompensationspfad braucht oder dass die Schritte 4 und 5 getauscht werden sollten.
- Kann der Kunde eine Bestätigung für eine Bestellung bekommen, die nicht existiert? Nein. Das Event wird in Schritt 7 veröffentlicht, nach dem Schreiben in Schritt 6. Wäre es umgekehrt, könnte ein fehlgeschlagener Schreibvorgang trotzdem eine E-Mail auslösen. (Wenn Schreiben und Veröffentlichen atomar sein müssen, kommt eine Outbox-Tabelle ins Spiel, und das ist einen ADR wert.)
- Was liegt auf dem kritischen Pfad des Kunden? Die Schritte 2 bis 8. Die E-Mail nicht, deshalb läuft sie über Kafka.
Hier dasselbe Szenario in der Structurizr-DSL, für Teams, die ihr Modell als Code pflegen. Es kompiliert nur, wenn jede Beziehung im statischen Modell existiert, also genau die oben beschriebene Einschränkung:
dynamic webshop "PlaceOrder" "Customer places an order" {
customer -> spa "Clicks Place order"
spa -> gateway "POST /orders"
gateway -> orderService "Routes the request"
orderService -> productService "Reserves stock"
orderService -> stripe "Authorizes the card"
orderService -> orderDb "Writes the order"
orderService -> kafka "Publishes OrderPlaced"
notificationService -> kafka "Consumes OrderPlaced"
notificationService -> sendgrid "Sends confirmation"
autoLayout lr
}
Schritt 8, die Antwort, ist im statischen Modell keine eigene Beziehung und fehlt deshalb in der DSL-Fassung. Antworten ergeben sich meist aus dem Request; zeichnen Sie sie nur, wenn die Antwort selbst wichtig ist.
Häufige Fehler
Zu viele Schritte
Ein dynamisches Diagramm mit dreißig nummerierten Pfeilen ist eine Abfolge, die niemand im Kopf behalten kann. Wenn ein Szenario über etwa fünfzehn Schritte hinausgeht, teilen Sie es: „Checkout bis zur Zahlung" und „Checkout nach der Zahlung", oder ein Diagramm pro System, das der Ablauf durchquert. Unsere eigene Flows-Dokumentation empfiehlt aus demselben Grund 5 bis 15 Schritte pro Flow.
Ebenen mischen
C4 lässt Sie die Ebene wählen (Systeme, Container oder Komponenten), aber wählen Sie eine pro Diagramm. Ein Diagramm, in dem Schritt 3 zum Container „Order Service" geht und Schritt 4 zur Komponente PaymentClient darin, zwingt den Leser, mitten in der Geschichte den Zoom zu wechseln. Braucht ein Schritt Komponentendetails, zeichnen Sie ein zweites dynamisches Diagramm, das auf diesen Container begrenzt ist.
Pfeile, die es im statischen Modell nicht gibt
Zeigt das dynamische Diagramm, dass der Notification Service den Order Service direkt aufruft, und das Container-Diagramm hat diese Beziehung nicht, dann ist eines der beiden falsch. Meist ist es das dynamische Diagramm, aus dem Gedächtnis gezeichnet. Behandeln Sie das statische Modell als Source of Truth und lassen Sie jeden Schritt auf eine seiner Beziehungen verweisen.
Jeden Aufruf zeichnen
Health Checks, Token-Refreshes, Log-Shipping und Metrik-Scrapes sind real, aber sie sind nicht das Szenario. Lassen Sie alles weg, was in jedem dynamischen Diagramm auftauchen würde, das Sie zeichnen. Ist es wichtig, bekommt es einmal ein eigenes Diagramm für wiederkehrende Muster.
Asynchrones hinter synchron aussehenden Pfeilen verstecken
Die Schritte 9 und 10 oben passieren, nachdem der Kunde bereits eine Antwort hat. Werden sie mit denselben Pfeilen gezeichnet wie die Schritte 1 bis 8, nehmen Leser an, dass die E-Mail vor dem Laden der Seite verschickt wird. Kennzeichnen Sie asynchrone Schritte (gestrichelte Linie, ein „async"-Label oder eine separate Nummerierung wie 9a) und erklären Sie die Konvention in der Legende.
Den Fehlerfall weglassen, auf den es ankommt
Ein Happy-Path-Diagramm ist der richtige Standard. Wenn Sie den Ablauf aber zeichnen, weil die Frage lautet „was passiert, wenn die Zahlung fehlschlägt", dann zeichnen Sie diesen Pfad, nicht den Happy Path.
Aktuell bleiben, wenn sich das statische Modell ändert
Ein dynamisches Diagramm hängt doppelt vom statischen Modell ab: von seinen Elementen und von seinen Beziehungen. Deshalb gehört es zu den ersten Dingen, die veralten. Jemand benennt den Order Service in „Checkout Service" um, ersetzt Kafka durch SQS oder verlagert die Bestandsreservierung in einen neuen Inventory Service, und jedes dynamische Diagramm, das diese Kästen berührt hat, ist nun falsch. Nichts sagt es Ihnen.
Drei Gewohnheiten helfen:
- Zeichnen Sie aus dem Modell, nicht daneben. Ein dynamisches Diagramm in einem Zeichenwerkzeug ist eine Kopie des Container-Diagramms, und Kopien driften. Eine dynamische View, die Modellelemente über Bezeichner referenziert (die Structurizr-DSL tut das), übernimmt zumindest Umbenennungen und schlägt laut fehl, wenn eine Beziehung verschwindet.
- Halten Sie die Liste kurz. Fünf dynamische Diagramme, die Sie jedes Quartal prüfen, schlagen dreißig, die Sie nie öffnen.
- Prüfen Sie sie, wenn sich die Container ändern, die sie berühren. Ändert ein Pull Request einen Container oder eine Beziehung, gehören die dynamischen Diagramme, die ihn nutzen, zum Review.
Wie Flows in archyl funktionieren
In archyl ist ein dynamisches Diagramm ein Flow: eine geordnete Liste von Schritten, jeder mit einem Quellelement, einem Zielelement, einer Beziehung und einer Beschreibung, die Schritt für Schritt über dem Diagramm abgespielt werden (Flows-Dokumentation). Sie können einen Flow von Hand erstellen, indem Sie Beziehungen aus Ihrem Modell auswählen, oder das Szenario beschreiben und den KI-Flow-Generator die Schritte aus Ihrem C4-Modell entwerfen lassen. Der Generator prüft jeden Schritt gegen das Modell, bevor er ihn speichert: Quelle und Ziel jedes Schritts müssen existieren, und die zitierte Beziehung muss diese beiden Elemente verbinden. Ein Schritt, der nicht passt, wird verworfen statt gezeichnet.
Zwei Grenzen, offen benannt, weil sie genau das Problem betreffen, um das es in diesem Abschnitt geht:
- Ein Flow speichert einen Snapshot der Elemente und Beziehungen, die er nutzt, aufgenommen beim Hinzufügen eines Schritts. Dadurch bleibt ein Flow lesbar, selbst wenn ein Element später gelöscht wird, aber es bedeutet auch, dass das Umbenennen eines Containers im Modell ihn in bestehenden Flows nicht umbenennt. Wenn sich das Modell ändert, öffnen Sie die Flows, die es berühren, und prüfen Sie sie.
- Der Drift-Score prüft kein Verhalten. Der Drift-Score von archyl sagt Ihnen, ob die dokumentierten Elemente noch im Code existieren. Wird ein synchroner Aufruf zwischen zwei Services zu einer Queue-Nachricht und nichts wird umbenannt oder verschoben, ändert sich der Score nicht, und der Flow auch nicht.
Mehr zur Praxis, einschließlich wie wir Flows als Dokumente mit Vorbedingungen und Fehlerbehandlung schreiben, finden Sie unter User Flows dokumentieren.
FAQ
Gehört das dynamische Diagramm zum C4-Modell?
Ja, als ergänzendes Diagramm. Die vier Kernebenen sind System Context, Container, Component und Code. Das C4-Modell ergänzt drei Diagramme: System Landscape, dynamisch und Deployment. Das dynamische Diagramm verwendet Elemente aus den Kernebenen wieder und zeigt, wie sie in einem Szenario interagieren.
Was ist der Unterschied zwischen einem dynamischen C4-Diagramm und einem Sequenzdiagramm?
Ein dynamisches C4-Diagramm kann im Kollaborationsstil (freie Anordnung, nummerierte Pfeile) oder im Sequenzstil (Lebenslinien, die Zeit läuft nach unten) gezeichnet werden. Der Sequenzstil sieht aus wie ein UML-Sequenzdiagramm, aber seine Teilnehmer sind C4-Systeme, -Container oder -Komponenten, und jeder Pfeil ist eine Nutzung einer Beziehung aus dem statischen Modell, kein Methodenaufruf.
Welche Ebene sollte ein dynamisches Diagramm verwenden?
Die Ebene, die die Frage beantwortet, und nur eine pro Diagramm. Die Container-Ebene ist am häufigsten, weil die meisten Szenarien, die sich zu zeichnen lohnen, mehrere deploybare Einheiten durchqueren. Nutzen Sie die System-Ebene für Abläufe zwischen Systemen und die Komponentenebene, um das Innere eines Containers zu erklären.
Wie viele Schritte sollte ein dynamisches Diagramm haben?
Es gibt keine offizielle Grenze. Ab etwa fünfzehn Schritten verlieren die meisten Leser den Überblick, teilen Sie das Szenario also in Teile oder zeichnen Sie ein Diagramm pro durchquertem System.
Kann ein dynamisches C4-Diagramm asynchrone Nachrichten zeigen?
Ja. Zeigen Sie das Veröffentlichen und das Konsumieren als getrennte nummerierte Schritte und machen Sie sichtbar, auf welche Schritte der Aufrufer wartet und auf welche nicht: eine gestrichelte Linie, ein „async"-Label oder ein separates Nummerierungsschema, erklärt in der Legende.
Unterstützt archyl dynamische C4-Diagramme?
Ja, als Flows. Jeder Schritt referenziert ein Quellelement, ein Zielelement und eine Beziehung aus Ihrem Modell, und der Flow wird Schritt für Schritt über dem Diagramm abgespielt. Sie können Flows von Hand erstellen oder einen Entwurf aus einer Textbeschreibung generieren. Flows speichern einen Snapshot der Elemente, die sie nutzen, prüfen Sie sie also, wenn sich die Container ändern, die sie berühren.
Möchten Sie Ihren ersten Flow über ein Modell zeichnen, das es schon gibt? Testen Sie archyl kostenlos und erzeugen Sie zuerst das C4-Modell aus Ihrem Code. Weiterlesen: Was ist das C4-Modell? Ein vollständiger Leitfaden | Leitfaden zum C4-Container-Diagramm | User Flows dokumentieren | Flows-Dokumentation.