Playbook

DDD in Produktion: Verteilte Systeme und Modernisierungsstrategien (Ddd In Produktion Verteilte Systeme Und Modernisierung)

Wie bleibt DDD unter Production-Change tragfähig? Ein Leitfaden zu Event Storming, Saga, Transactional Outbox, Anti-Corruption Layer und…

Production DDD practices for event discovery, legacy modernization, and safe distributed change

Die Landkarte dieses Kapitels

Dieses Kapitel ist keine Liste von Patterns zum Auswendiglernen. Es folgt, wie Geschäftsrealität aus einem Monolithen während Veränderung sicher weitergetragen wird.

Monolith
   ↓
Event Storming
   ↓
Bounded Context
   ↓
Saga
   ↓
Outbox
   ↓
Strangler Fig
   ↓
Production

Die eigentliche Frage in Produktion

DDD-Grenzen zu zeichnen ist der Anfang. In Produktion besteht die Prüfung darin, diese Grenzen, das System und Nutzervertrauen zu bewahren, während sich das Geschäft verändert. Einen Bestellfluss aus einem Legacy-Monolithen über Nacht neu zu schreiben wirkt verlockend, ist jedoch meist die riskanteste Option.

Monolith → aktuelle Geschäftsrealität
Neuer Context → saubereres Modell
Schrittweise Migration → messbares Vertrauen

Das Ziel sind nicht mehr Services. Das System soll sich sicher verändern können, wenn sich die Sprache des Geschäfts verändert.

Begriffe bei der ersten Verwendung

📦 Event Storming
Ein Discovery-Workshop, der Geschäftsereignisse, Commands und Risiken gemeinsam sichtbar macht.

📦 Saga
Ein Modell für lokale Transactions und fachliche Kompensation nach Fehlern in einem verteilten Workflow.

📦 Transactional Outbox
Ein Pattern, das Datenänderung und zu veröffentlichendes Event in einer lokalen Transaction speichert.

📦 Strangler Fig
Eine Modernisierungsstrategie, die ein Legacy-System schrittweise hinter neuen Grenzen ersetzt statt alles auf einmal.

Ein Domain Event ist eine Geschäfts-Tatsache im Präteritum: OrderConfirmed. Ein Command ist Absicht: ConfirmOrder. Das ist wichtig, weil Absicht abgelehnt werden kann, eine Tatsache jedoch ein Datensatz ist, auf den andere Contexts sicher reagieren können.

Mit Event Storming zuerst den unsichtbaren Ablauf finden

Eine Production-Migration beginnt mit dem Geschäftsfluss, nicht mit einem Code-Inventar. Produkt, Operations und Engineering ordnen Ereignisse im Präteritum an einer gemeinsamen Wand und ergänzen Commands, Actors, externe Systeme und rote Hot Spots.

OrderConfirmed ← ConfirmOrder ← Customer
       ↓
InventoryReserved ← ReserveInventory
       ↓
PaymentCaptured ← CapturePayment ← Payment Gateway

Lesen Sie den Ablauf auch rückwärts. Reverse Narrative legt Entscheidungen frei, die der Happy Path versteckt: Retouren, Teilzahlungen, Timeouts und manuelle Eingriffe. Ein Bounded Context liegt dort, wo Sprache, Entscheidung und Ownership wechseln, nicht dort, wo zufällig eine Tabelle endet.

🎯 Ziel dieses Abschnitts

Verstehen, wie fachliche Konsistenz erhalten bleibt, wenn Transaction-Grenzen verteilt sind.

Ist Geld bereits von einer Bank abgebucht, kann ein SQL Rollback es nicht zurückholen. Ist Bestand in einem anderen Context reserviert, kann ein Rollback in einer Datenbank das ebenfalls nicht korrigieren. Verteilte Systeme kompensieren deshalb eine fachliche Wirkung, statt einen Rollback vorzutäuschen.

Saga ist kein Rollback, sondern fachliche Kompensation

Payment, Inventory und Shipment leben in unterschiedlichen Contexts und teilen daher keine ACID Transaction. 2PC kann starke Konsistenz versprechen, doch die Kosten von Lock Retention und Verfügbarkeit bei Coordinator- oder Participant-Fehlern sind in Production schlechte Trade-offs. Eine Saga definiert stattdessen für jeden lokalen Schritt eine Kompensation.

Reserve inventory → Capture payment → Create shipment
                 payment fails → Release inventory

Auch ReleaseInventory muss idempotent sein: Ein Duplicate Event darf Bestand nicht zweimal erhöhen. Choreography kann für kurze lokale Flows genügen. Für lange, geschäftskritische Abläufe liefert Orchestration eine State Machine und einen Beobachtungspunkt.

🎯 Ziel dieses Abschnitts

Die Lücke zwischen Datenbank-Record und Event-Publish schließen.

Eine Bestellung wird erfolgreich gespeichert. Genau dann fällt der Broker aus. Die Bestellung existiert, aber OrderConfirmed nicht; Shipping und Notifications bleiben unbemerkt zurück. Outbox schließt die Lücke, indem Record und veröffentlichbares Event in einer lokalen Transaction gespeichert werden.

Outbox und Observability machen Migration beweisbar

Wenn eine Bestellung committet wird, während der Broker nicht verfügbar ist, entsteht eine Lücke zwischen Datenbank-Write und Message Publish. Dafür gibt es Outbox.

Local transaction
  → Order speichern
  → OrderConfirmed in Outbox schreiben
  → commit

Relay → Broker → Consumer → Projection

Consumer müssen bei at-least-once delivery Duplikate erwarten. Prüfen Sie Event Identity, Aggregate Version und fachliche Wirkung. Correlation ID verbindet einen End-to-End-Flow; Causation ID benennt die Entscheidung, die ein Event erzeugt hat. Im Incident beantworten sie nicht nur Logs, sondern “was ist passiert?” und “warum?”.

🎯 Ziel dieses Abschnitts

Zu einer neuen Domain-Grenze wechseln, ohne Legacy-Verhalten zu verlieren.

Ein ERP, das zehn Jahre läuft, können Sie nicht an einem Wochenende neu schreiben. Messen Sie zuerst, wo das neue Modell vom Live-Verhalten des Legacy-Systems abweicht; leiten Sie Traffic dann in kleinen, reversiblen Schritten um.

Legacy mit Strangler Fig modernisieren

Big-Bang-Migration riskiert, altes Verhalten zu verlieren, bevor seine Regeln entdeckt sind. Stellen Sie den neuen Context neben das Legacy-System; messen Sie zuerst Daten- und Verhaltensunterschiede, dann leiten Sie Traffic um.

1. Replication only  → Daten in neues Modell speisen
2. Shadow reads      → Legacy- und neue Antworten vergleichen
3. Partial reads     → kleinen Traffic-Anteil umleiten
4. Write migration   → an neuer Grenze schreiben, Kompatibilität wahren
5. Full cutover      → nach Metrik-Validierung wechseln
6. Decommission      → Brücken und alten Code entfernen

Die Anti-Corruption Layer schützt das neue Modell. Statt mehrdeutige Legacy-Felder in die Domain zu tragen, übersetzt sie: LEGACY_ORDER_STATE=7 wird zu einem sinnvollen FulfilmentStatus. Der Einflussradius des schmutzigen Modells bleibt in einem Adapter.

Das Akzeptanzkriterium: mehr als ein erfolgreicher Deploy

Eine Migration ist nicht erfolgreich, nur weil ein neuer Endpoint antwortet. Shadow-Read-Difference-Rate, P95 Latency Delta, Consumer Lag, DLQ Depth und ein Rollback Plan müssen sichtbar sein. Replay-Kosten sind O(n) in der Zahl der Events; Snapshots und segmentiertes Replay können sie senken, ersetzen aber keine verifizierte Historie.

Ein nicht beobachtbares System kann nicht betrieben werden. Jeder Event Contract braucht Owner, Versionierungsstrategie, Alert und Replay Runbook.

Zuordnungen, die falsche Sicherheit erzeugen

❌ DDD = Microservice-Migration
✓ DDD schützt Geschäftssprache und Entscheidungsgrenzen; Microservices sind manchmal ein Ergebnis.

❌ Saga = technischer Rollback
✓ Eine Saga kompensiert eine nicht rückgängig zu machende fachliche Wirkung.

❌ Outbox = Exactly-once Delivery
✓ Outbox verhindert Event-Verlust; Consumer brauchen weiter Idempotenz für Duplikate.

❌ Shadow Read = Test abgeschlossen
✓ Es ist laufende Evidenz über Verhaltensunterschiede im Live Traffic.

❌ ACL = unnötiger Layer
✓ ACL verhindert, dass Legacy-Sprache die neue Domain verunreinigt.

Checkliste für Production Readiness

  1. Macht Event Storming Hot Spots außerhalb des Happy Path und externe Systeme sichtbar?
  2. Hat jeder Saga-Schritt eine idempotente Kompensation?
  3. Schließt Outbox die Lücke zwischen Datenbank-Record und Event bei Broker-Ausfall?
  4. Sind Correlation ID, Causation ID, Consumer Lag und DLQ beobachtbar?
  5. Schützt der neue Context sich mit ACL vor dem Legacy-Modell?
  6. Sind Schwellwerte für Shadow Reads, schrittweisen Traffic und Rollback definiert?
  7. Sind Owner und Entfernungsdatum jeder Übergangsbrücke explizit?

Migrationskomplexität wird nicht an der Service-Anzahl gemessen. Messen Sie unabhängige Veränderbarkeit, Fehlerisolation und Evidenz für sichere Rückkehr.

Was im Gedächtnis bleiben sollte

  1. Production DDD bedeutet, dass das Modell unter Veränderung der Geschäftssprache treu bleibt.
  2. Event Storming entdeckt unsichtbare Entscheidungen und Risiken vor dem Code.
  3. Saga, Outbox und Idempotenz behandeln verteilte Fehler als Design-Eingabe.
  4. Strangler Fig und ACL teilen Legacy-Modernisierung in messbare, reversible Schritte.

Modernisierung bedeutet nicht, das alte System zu zerstören. Sie schafft einen sichereren Rhythmus der Veränderung, ohne Geschäftswert zu verlieren.

FAQ

Häufige Fragen

Was ist Event Storming?

Ein Discovery-Workshop, der Geschäftsereignisse, Commands und Risiken gemeinsam sichtbar macht.

Was ist Saga?

Ein Modell für lokale Transactions und fachliche Kompensation nach Fehlern in einem verteilten Workflow.

Stimmt es, dass „DDD = Microservice-Migration“?

DDD schützt Geschäftssprache und Entscheidungsgrenzen; Microservices sind manchmal ein Ergebnis.

Was legt dieser Teil fest?

Das Ziel sind nicht mehr Services. Das System soll sich sicher verändern können, wenn sich die Sprache des Geschäfts verändert. Production DDD bedeutet, dass das Modell unter Veränderung der Geschäftssprache treu bleibt. DDD-Grenzen zu zeichnen ist der Anfang. In Produktion besteht die Prüfung darin, diese Grenzen, das System und Nutzervertrauen zu bewahren, während sich das Geschäft verändert. Einen Bestellfluss aus einem Legacy-Monolithen über Nacht neu zu schreiben wirkt verlockend, ist jedoch meist die riskanteste Option.

Gelernte Engineering-Prinzipien

  • Production DDD verlangt, dass Events und Grenzen auch bei Fehlern fachliche Bedeutung bewahren.
  • Saga, Outbox und Idempotenz akzeptieren verteilte Zustellung als normal statt als Ausnahme.
  • Strangler Fig und ACL halten Legacy-Modernisierung klein, messbar und reversibel.

Weiterlesen

Weiterlesen

Verwandte Beitrage

Verwandte Beitrage

Verwandte Beitrage

Paylaş