Playbook
Wie funktioniert DDD in großen Systemen? (Wie Funktioniert Ddd In Grossen Systemen)
Wie skaliert DDD in großen Systemen? Ein Entscheidungsleitfaden zu Bounded Contexts, Context Mapping, Conway's Law, modularen Monolithen, Microservice-Grenzen…
Zuerst die falsche Frage loslassen
Am ersten Tag gab es ein einziges Book-Modell. Dann brauchte Sales einen Preis, Shipping ein Lieferfenster und Marketing Kampagnendaten. Sechs Monate später war dieselbe Klasse ein Objekt, das niemand mehr vollständig verstand. Das Problem war nicht das wachsende Buch, sondern unterschiedliche Geschäftsabsichten in einem Modell.
Ein großes System in Microservices zu teilen bedeutet nicht, DDD anzuwenden. Zuerst muss klar sein, welche Geschäftsbereiche unterschiedliche Sprache, Entscheidungen und Änderungsrhythmen haben. Andernfalls wird aus einem Monolithen nur ein teurerer Distributed Monolith.
Ein Modell → soll jeden Bedarf tragen → Model Tension
Sales Context → Preis und Kundenkredit
Shipping Context → Lieferadresse und Paket
Catalog Context → Titel, ISBN und Metadaten
Die Frage dieses Kapitels lautet: Wie können Modelle derselben Geschäftswelt sprechen, ohne einander zu verunreinigen?
Begriffe bei der ersten Verwendung
📦 Bounded Context
Eine explizite Grenze, in der Modell, Sprache und Regeln konsistent bleiben.
📦 Context Mapping
Die bewusste Definition der Daten-, Macht- und Vertragsbeziehung zwischen zwei Contexts.
📦 Upstream / Downstream
Der Anbieter eines Modells oder Vertrags ist Upstream; sein abhängiger Verbraucher Downstream.
📦 Anti-Corruption Layer (ACL)
Eine Übersetzungsschicht, die verhindert, dass ein externes Modell in die eigene Domain eindringt.
Conway's Law einfach gesagt: Software spiegelt mit der Zeit wider, wie eine Organisation kommuniziert. Ein Bounded Context ist kein Microservice; er kann zuerst als eigene Sprach-, Ownership- und Code-Grenze in einem modularen Monolithen leben.
Das große Bild
Unternehmen
│
┌────────────────────┼────────────────────┐
│ │ │
Catalog Sales Shipping
│ │ │
Book Customer Recipient
│ │ │
└──────── OrderConfirmed event ────────┘
│
Outbox
│
Broker
│
Delivery projection
Das Diagramm beschreibt keine vorgeschriebene Zahl physischer Services. Es zeigt, wo Sprache, Ownership und Veränderung leben.
Warum scheitert die Suche nach einem einzig wahren Modell?
Im Katalog ist ein Buch Titel, Autor und ISBN. Beim Verleihen ist es ein physisches Exemplar im Regal. Im Verkauf ist es SKU und Preis. Alles in einer Book-Klasse zu vereinen ist keine Wiederverwendung, sondern verbindet unterschiedliche Absichten. Dasselbe gilt für Customer: Sales braucht Kredit und Rechnungsdaten, Shipping Adresse und Lieferpräferenz.
❌ Unified Customer
creditLimit + invoiceAddress + deliveryWindow + marketingConsent + ...
✓ Sales.Customer
creditLimit + billingProfile
✓ Shipping.Recipient
deliveryAddress + deliveryWindow
Das Problem ist nicht die Zahl der Objekte. Ein Modell wird von unterschiedlichen Teams aus unterschiedlichen Gründen geändert. Mit k betroffenen Contexts sind die Änderungskosten mindestens O(k); Tests und Abstimmung wachsen schneller, wenn Abhängigkeiten zunehmen.
Bounded Context: Grenze zuerst in Geschäftssprache ziehen
Folgen Sie nicht technischen Layern oder Datenbanktabellen. Achten Sie auf diese Signale:
- Bedeutet dasselbe Wort in Meetings unterschiedliche Dinge?
- Vermehren sich Sonderfälle wie
if (shipping)undif (sales)? - Warten Teams für eine Änderung wiederholt aufeinander?
- Sind Owner, Erfolgsmaß oder Änderungsrhythmus eines Felds unklar?
Conway's Law ist hier eine Warnung: Systemgrenzen spiegeln oft die Kommunikation der Organisation. Wenn ein Team unabhängig entscheiden soll, sollten Modell- und Deployment-Grenze soweit praktikabel unabhängig sein. Das ist eine Ownership-Entscheidung, kein technisches Ziel.
Im Monolithen beginnen; Microservices als Ergebnis sehen
Ein modularer Monolith ist der risikoärmste Weg, einen Bounded Context zu validieren. Jeder Context besitzt Application/Domain/Infrastructure-Komponenten, Datenzugriff und expliziten Vertrag, ohne schon die Betriebskosten verteilter Aufrufe zu tragen.
Catalog module ── published contract ──► Sales module
Sales module ── domain event ─────────► Shipping module
Wechseln Sie erst zu einem Microservice, wenn unabhängiges Scaling, Deployments, Sicherheitsgrenzen oder echte Teamautonomie nachgewiesen nötig sind. Bounded Context = Microservice ist die typische Gleichung hinter vorzeitiger Verteilung.
Context Mapping: Integration darf nicht zufällig sein
Die Beziehung zwischen Contexts bestimmen Machtbalance und Risiko der Model-Verunreinigung, nicht ein Endpoint.
| Situation | Strategie | Warum |
|---|---|---|
| Legacy-Modell ist chaotisch | ACL | Verhindert, dass externe Sprache in die Domain dringt |
| Viele Consumers | Open Host Service + Published Language | Teilt versionierten Vertrag statt internem Modell |
| Kein Einfluss auf sauberen Upstream | Conformist | Vermeidet unnötige Übersetzung |
| Kleiner stabiler gemeinsamer Teil | Shared Kernel, letzte Wahl | Akzeptiert bewusst Koordinationskosten |
Ein ACL kann CUST_TIER=7 eines Legacy-ERP in DeliveryEligibility innerhalb von Shipping übersetzen. Der ERP-Begriff betritt die Shipping-Domain nicht. Der zusätzliche Code hält den Einflussradius an einem Übersetzungspunkt.
Events, Outbox und Eventual Consistency
Ein Context sollte nicht die Datenbank eines anderen lesen. Bestätigt Sales eine Bestellung, kann es OrderConfirmed veröffentlichen; Shipping baut daraus seine Lieferansicht. Events verbieten synchrone Aufrufe nicht, reduzieren aber zeitliche Kopplung unabhängiger Abläufe.
Sales transaction
→ Order speichern
→ OrderConfirmed in Outbox schreiben
→ Commit
Relay → Broker → Shipping consumer → Delivery projection
Outbox ist nötig, weil Broker und Datenbank keine gemeinsame ACID Transaction haben. Existiert die Bestellung, existiert auch ein zu veröffentlichendes Event; der Relay kann retryen. Consumers müssen wegen normaler Duplikate idempotent bleiben. Eventual Consistency ist kein Fehler, sondern ein sichtbares Zeitfenster, das das Produkt akzeptieren muss.
Die Kosten dieses Designs
Context-Grenzen brauchen mehr Verträge, Observability, Versionierung und Teamdisziplin. Jeder Consumer ergänzt mehr als O(1) Code: Dashboards, Alarme, Retries, Ownership und Integrationstests folgen. Die beste Grenze erzeugt nicht die meisten Services, sondern senkt tatsächlich die Änderungskosten.
Zuordnungen, die falsche Sicherheit erzeugen
❌ Bounded Context = Microservice
✓ Zuerst ist es eine Sprach-, Ownership- und Modellgrenze.
❌ Ein Modell = Konsistenz
✓ Jeder Context kann sein eigenes konsistentes Modell besitzen.
❌ Shared Kernel = Wiederverwendung
✓ Es bedeutet gemeinsame Änderung und Koordinationskosten.
❌ REST Call = Integrationsstrategie
✓ Vertrag, Ownership und Fehlerverhalten bilden die Strategie.
❌ Eventual Consistency = Fehler
✓ Richtig gestaltet ist sie ein bewusster Trade-off unabhängiger Abläufe.
Checkliste für Strategic Design
- Wo beginnt dasselbe Wort unterschiedliche Dinge zu bedeuten?
- Hat jeder Context klare Sprache, Owner und Erfolgsmaß?
- Kann die Grenze zuerst im modularen Monolithen validiert werden?
- Dringt ein Upstream-Modell direkt in die Domain ein und braucht es ACL? In
ERP → ACL → Shippingsollte etwaCUST_TIER=7zu ShippingsDeliveryEligibilitywerden. - Ist der gemeinsame Vertrag versioniert und abwärtskompatibel?
- Was passiert, wenn eine Bestellung committed ist und der Broker ausfällt? Outbox schreibt Datensatz und Event in eine lokale Transaction; ein Relay retryt sicher, sobald der Broker zurück ist.
- Gibt es Produkt- und Betriebsentscheidungen für Lag, Duplikate und Replay?
Der Code wächst nicht nur um wenige Zeilen: Monitoring, Alarme, Retries und operative Ownership kommen hinzu. Codewachstum kann wie O(1) aussehen, doch Betriebskosten wachsen nicht linear. Messen Sie unabhängige Veränderbarkeit und Fehlerisolation, nicht die Service-Anzahl.
Was im Gedächtnis bleiben sollte
- Große Systeme haben kein einzig wahres Modell; jeder Bounded Context trägt seine eigene Geschäftsrealität.
- Ein Microservice ist nicht der Beginn einer strategischen Grenze, sondern kann ihr physisches Ergebnis sein.
- Context Mapping macht Vertrag, Macht und Model-Schutz sichtbar.
- Events und Outbox transportieren Veränderung sicher zwischen unabhängigen Contexts.
Eine Architekturgrenze beginnt nicht dort, wo Code liegt, sondern dort, wo eine Entscheidung in einer Sprache unter einem Owner getroffen wird.
Das letzte Kapitel betrachtet DDD in Production: Event Storming, Legacy-Migration, Anti-Corruption Layers und sicheren Wandel.
FAQ
Häufige Fragen
Was ist Bounded Context?
Eine explizite Grenze, in der Modell, Sprache und Regeln konsistent bleiben.
Was ist Context Mapping?
Die bewusste Definition der Daten-, Macht- und Vertragsbeziehung zwischen zwei Contexts.
Stimmt es, dass „Bounded Context = Microservice“?
Zuerst ist es eine Sprach-, Ownership- und Modellgrenze.
Was legt dieser Teil fest?
Die Frage dieses Kapitels lautet: Wie können Modelle derselben Geschäftswelt sprechen, ohne einander zu verunreinigen? Große Systeme haben kein einzig wahres Modell; jeder Bounded Context trägt seine eigene Geschäftsrealität. Am ersten Tag gab es ein einziges `Book`-Modell. Dann brauchte Sales einen Preis, Shipping ein Lieferfenster und Marketing Kampagnendaten. Sechs Monate später war dieselbe Klasse ein Objekt, das niemand mehr vollständig verstand. Das Problem war nicht das wachsende Buch, sondern unterschiedliche Geschäftsabsichten in einem Modell.
Gelernte Engineering-Prinzipien
- Ein Bounded Context ist zuerst eine Grenze von Geschäftssprache und Ownership, nicht zwingend ein Microservice.
- Context Mapping schützt die Domain bewusst vor externen Modellen.
- Events und Outbox transportieren Veränderung sicher und beobachtbar zwischen unabhängigen Contexts.
Weiterlesen
Weiterlesen
Verwandte Beitrage
DDD in Produktion: Verteilte Systeme und Modernisierungsstrategien
Wie bleibt DDD unter Production-Change tragfähig? Ein Leitfaden zu Event Storming, Saga, Transactional Outbox, Anti-Corruption Layer und…
Verwandte Beitrage
Wie funktioniert eine CQRS (Command Query Responsibility Segregation)-Pipeline? Anatomie von Command- und Query-Flows
Was ist eine CQRS Request Pipeline? Wie durchläuft eine HTTP-Anfrage Controller, MediatR, Pipeline Behaviors, Handler, Outbox und Read Model?
Verwandte Beitrage
Wie funktioniert ein Vertical Slice von innen?
Ein technischer Leitfaden zum inneren Ablauf eines Vertical Slice: Request, Validation, Handler, Aggregate, Outbox, Projection, Idempotenz, Performance,…