8 Integration mit Domain Driven Design

Domain Driven Design und Event-Driven Architecture sind wie zwei Puzzleteile, die perfekt ineinander passen. Während DDD uns lehrt, Software um die Geschäftsdomäne herum zu strukturieren und die Fachsprache des Unternehmens in den Code zu überführen, zeigt uns EDA, wie wir diese fachlichen Konzepte durch Events natürlich miteinander verbinden können. Diese Synergie ist kein Zufall, sondern entspringt einer gemeinsamen Grundphilosophie: beiden Ansätzen geht es darum, die Komplexität von Geschäftsprozessen beherrschbar zu machen.

Denken Sie an ein großes E-Commerce-Unternehmen wie Amazon oder Zalando. Diese Organisationen müssen gleichzeitig mit Kunden, Produktkatalogen, Bestellungen, Zahlungen, Lagerverwaltung, Lieferungen und Marketing umgehen. Jeder dieser Bereiche hat seine eigene Fachsprache, eigene Regeln und eigene Experten.

Verschiedene Sichten auf den Begriff “Kunde”:

Bereich Sicht auf “Kunde” Wichtige Eigenschaften
Vertrieb Verkaufspotential & Präferenzen Lead-Status, Kaufhistorie, Interessen
Buchhaltung Zahlungsverhalten Kreditwürdigkeit, Zahlungshistorie, Mahnverfahren
Support Zufriedenheit & Probleme Ticket-Historie, Beschwerden, Lösungszeiten
Marketing Zielgruppensegment Demografische Daten, Kampagnen-Response

Ein Mitarbeiter aus der Logistik spricht anders über “Pakete” als ein Mitarbeiter aus dem Marketing über “Kampagnen”. Domain Driven Design hilft uns dabei, diese verschiedenen fachlichen Bereiche als separate Bounded Contexts zu modellieren, während Event-Driven Architecture uns zeigt, wie diese Contexts elegant miteinander kommunizieren können, ohne ihre Autonomie zu verlieren.

Was macht diese Kombination so mächtig? DDD gibt uns die Struktur und die Sprache, während EDA uns die Verbindungen liefert. Ein Bounded Context für “Order Management” kann Events wie “BestellungAufgegeben” publizieren, die von anderen Contexts wie “Inventory Management” oder “Customer Service” konsumiert werden. Dabei bleibt jeder Context in seiner eigenen fachlichen Welt, verwendet seine eigene Sprache und seine eigenen Modelle, aber sie können trotzdem nahtlos zusammenarbeiten.

Diese Integration ist besonders wertvoll, weil sie uns hilft, die richtigen Grenzen zu ziehen und die passenden Events zu identifizieren. Ohne DDD tendieren Teams dazu, Events entweder zu technisch zu modellieren (“DatabaseRowUpdated”) oder zu grob zu schneiden (“SomethingHappened”). Mit DDD als Leitfaden entstehen Events, die echte Geschäftsereignisse repräsentieren und für die Fachbereiche verständlich und wertvoll sind.

8.1 Bounded Contexts und Event-Streams

Um zu verstehen, wie Bounded Contexts und Event-Streams zusammenwirken, beginnen wir mit einer fundamentalen Erkenntnis aus Domain Driven Design: Verschiedene Teile einer Organisation haben unterschiedliche Sichten auf dieselben Konzepte. Das Wort “Kunde” bedeutet für den Vertrieb etwas anderes als für die Buchhaltung oder den Kundensupport. Der Vertrieb interessiert sich für Verkaufspotential und Präferenzen, die Buchhaltung für Zahlungshistorie und Kreditwürdigkeit, der Support für bisherige Probleme und Zufriedenheit.

Diese unterschiedlichen Sichtweisen führen in traditionellen Systemen oft zu dem Versuch, ein einheitliches “Kunden”-Modell zu schaffen, das alle Aspekte abdeckt. Das Ergebnis ist meist ein komplexes, schwer verständliches Datenmodell, das niemanden richtig zufriedenstellt. Domain Driven Design schlägt einen anderen Weg vor: Akzeptieren Sie, dass verschiedene Contexts verschiedene Modelle brauchen, und ziehen Sie klare Grenzen zwischen diesen Contexts.

Event-Driven Architecture macht diese Trennung nicht nur möglich, sondern natürlich und elegant. Jeder Bounded Context kann seine eigenen Events definieren und publizieren, die seine spezifische Sicht auf die Geschäftswelt widerspiegeln.

Event-Stream als Kommunikationskanal zwischen Contexts:

Der “Sales Context” könnte ein “ProspectContactedEvent” publizieren, wenn ein Vertriebsmitarbeiter einen potentiellen Kunden kontaktiert. Dieses Event enthält die Information, die für den Vertrieb relevant ist:

Der “Customer Service Context” muss nicht alle Details dieses Events verstehen oder verarbeiten. Er könnte lediglich daran interessiert sein, dass ein Kundenkontakt stattgefunden hat, um seine eigene Sicht auf die Kundenbeziehung zu aktualisieren. Dabei transformiert er das eingehende Event in sein eigenes internes Modell und seine eigene Sprache. Diese Transformation ist kein Zeichen schlechten Designs, sondern ein bewusster Akt der Kontextabgrenzung.

Event-Streams werden zu den Kommunikationskanälen zwischen Bounded Contexts. Angenommen jeder Context hätte seinen eigenen Radiosender, auf dem er regelmäßig sendet, was in seiner Welt passiert. Andere Contexts können diese Sender empfangen und entscheiden, welche Nachrichten für sie relevant sind. Wichtig ist dabei, dass der Sender nicht wissen muss, wer zuhört.

Context Published Events Consumed Events
Order Management OrderPlaced, OrderCancelled CustomerVerified, PaymentProcessed
Payment PaymentProcessed, PaymentFailed OrderPlaced
Inventory StockReserved, StockDepleted OrderPlaced, OrderCancelled
Shipping OrderShipped, DeliveryCompleted OrderPlaced, PaymentProcessed

Der “Order Management Context” publiziert “BestellungAufgegeben”-Events, ohne sich darum zu kümmern, ob und wie viele andere Contexts diese Events konsumieren.

Diese lose Kopplung zwischen Contexts ist entscheidend für die Skalierbarkeit und Wartbarkeit großer Systeme. Neue Contexts können hinzugefügt werden, die beginnen, bestehende Event-Streams zu konsumieren, ohne dass die produzierenden Contexts geändert werden müssen. Ein neuer “Analytics Context” könnte alle Bestell-Events konsumieren, um Verkaufstrends zu analysieren, ohne dass der “Order Management Context” davon weiß oder dadurch beeinflusst wird.

Die Herausforderung liegt darin, die richtigen Context-Grenzen zu identifizieren. Ein zu großer Context wird unüberschaubar und verliert die Vorteile der fachlichen Abgrenzung. Ein zu kleiner Context führt zu übermäßiger Fragmentierung und komplexer Orchestrierung. Die Erfahrung zeigt, dass Context-Grenzen oft entlang organisatorischer Grenzen verlaufen. Verschiedene Teams, verschiedene Fachbereiche oder verschiedene Verantwortlichkeiten deuten auf separate Contexts hin.

Praktisches Beispiel - Lagerbestand-Event:

Ein praktisches Beispiel verdeutlicht diese Konzepte: In unserem E-Commerce-System könnte der “Inventory Context” ein “LagerbestandNiedrig”-Event publizieren, wenn ein Artikel unter eine kritische Schwelle fällt. Verschiedene Contexts reagieren darauf in ihrer eigenen Weise:

Jeder Context reagiert mit seinen eigenen Geschäftsregeln, aber alle profitieren von der gleichen grundlegenden Information.

8.2 Aggregate-Event-Beziehungen

Aggregate sind eines der mächtigsten Konzepte aus Domain Driven Design, und ihre Beziehung zu Events ist fundamental für das Verständnis event-getriebener Systeme. Ein Aggregate ist eine Gruppe zusammengehöriger Objekte, die als Einheit behandelt werden müssen, um die Geschäftsinvarianten aufrechtzuerhalten. Wenn wir Events in diese Gleichung einbringen, entstehen Muster, die sowohl elegant als auch leistungsfähig sind.

Betrachten wir zunächst, was ein Aggregate charakterisiert. Es hat eine klar definierte Grenze, einen eindeutigen Identifier (die Aggregate Root) und kapselt Geschäftslogik, die sicherstellt, dass das Aggregate immer in einem konsistenten Zustand bleibt. In unserem E-Commerce-System könnte eine “Bestellung” ein Aggregate sein, das aus Bestellpositionen, Lieferadresse, Zahlungsinformationen und Status besteht.

Bestellungs-Aggregate Struktur:

Order Aggregate Root
├── Order ID (Identifier)
├── Customer Information
├── Order Items []
│   ├── Product ID
│   ├── Quantity  
│   └── Price
├── Shipping Address
├── Payment Information
└── Order Status

Das Aggregate stellt sicher, dass beispielsweise niemals Artikel zu einer bereits abgeschlossenen Bestellung hinzugefügt werden können.

Events entstehen natürlich aus den Geschäftsoperationen, die auf Aggregates ausgeführt werden. Wenn ein neues Bestellungs-Aggregate erstellt wird, führt dies zu einem “BestellungErstellt”-Event. Wenn sich der Status ändert, entsteht ein “BestellungsStatusGeändert”-Event. Diese Events sind nicht willkürlich, sondern spiegeln die bedeutsamen Geschäftsereignisse wider, die aus der Sicht des Aggregates aufgetreten sind.

Event-Entstehung aus Geschäftsoperationen:

Geschäftsoperation Ausgelöstes Event Fachliche Bedeutung
Neue Bestellung erstellen OrderCreated Kunde hat Kaufentscheidung getroffen
Artikel hinzufügen ItemAddedToOrder Warenkorb wurde erweitert
Zahlung verarbeiten PaymentProcessed Finanzielle Transaktion abgeschlossen
Bestellung versenden OrderShipped Physische Erfüllung gestartet
Stornierung OrderCancelled Geschäftsprozess wurde abgebrochen

Die Aggregate Root fungiert als Event-Publisher für ihr gesamtes Aggregate. Sie sammelt Events während der Ausführung von Geschäftsoperationen und publiziert sie, nachdem die Änderungen erfolgreich persistiert wurden. Diese Reihenfolge ist wichtig: erst die Zustandsänderung, dann das Event. Dadurch wird sichergestellt, dass Events nur publiziert werden, wenn die zugrundeliegende Geschäftsoperation tatsächlich erfolgreich war.

Ein wichtiges Prinzip ist, dass Events die Geschäftsoperationen widerspiegeln sollten, nicht die technischen Details der Implementierung. Ein “BestellungErstellt”-Event sollte die fachlich relevanten Informationen über die Bestellung enthalten, nicht die Tatsache, dass drei Datenbankzeilen eingefügt wurden. Diese fachliche Ausrichtung macht Events wertvoll für andere Contexts und für Geschäftsanalysen.

Konsistenzgrenzen und Event-Verarbeitung:

Die Granularität von Events sollte sich an der Granularität von Geschäftsoperationen orientieren. Eine komplexe Geschäftsoperation wie “Bestellung aufgeben” könnte mehrere interne Schritte umfassen: Verfügbarkeit prüfen, Preise berechnen, Rabatte anwenden, Lieferkosten ermitteln. Aber für die Außenwelt ist das ein einziger fachlicher Vorgang, der zu einem “BestellungAufgegeben”-Event führt, nicht zu einer Reihe von technischen Events.

Interne Schritte einer Bestellung:
1. Verfügbarkeit prüfen ─┐
2. Preise berechnen     ├─→ Ein "OrderPlaced" Event
3. Rabatte anwenden     │
4. Lieferkosten ermitteln ┘

Nicht: CheckAvailability, CalculatePrice, ApplyDiscount, ... Events

Aggregate-Event-Beziehungen helfen auch dabei, Konsistenzgrenzen zu definieren. Starke Konsistenz wird innerhalb eines Aggregates gewährleistet, während zwischen Aggregates eventual consistency über Events akzeptiert wird.

Konsistenzmodell:

Bereich Konsistenztyp Mechanismus
Innerhalb Aggregate Stark (ACID) Datenbanktranskation
Zwischen Aggregates Eventually Event-basierte Synchronisation
Zwischen Contexts Eventually Asynchrone Event-Streams

Wenn eine Bestellung aufgegeben wird, muss innerhalb des Bestellungs-Aggregates sofort sichergestellt werden, dass alle Bestellpositionen gültig sind und die Gesamtrechnung stimmt. Die Reduzierung des Lagerbestands in einem anderen Aggregate kann jedoch asynchron über Events erfolgen.

Event Sourcing ist eine besonders interessante Erweiterung dieser Konzepte. Anstatt nur Events zu publizieren, können Aggregates vollständig durch die Sequenz der Events rekonstruiert werden, die zu ihrem aktuellen Zustand geführt haben. Das Bestellungs-Aggregate würde dann aus Events wie “BestellungErstellt”, “ArtikelHinzugefügt”, “RabattAngewendet”, “BestellungBestätigt” aufgebaut.

Diese Herangehensweise bietet eine vollständige Audit-Spur und ermöglicht es, den Zustand zu jedem beliebigen Zeitpunkt zu rekonstruieren.

8.3 Ubiquitous Language für Events

Die Ubiquitous Language ist eines der wertvollsten Konzepte aus Domain Driven Design, und ihre konsequente Anwendung auf Events kann den Unterschied zwischen einem System ausmachen, das die Geschäftswelt klar widerspiegelt, und einem, das nur Entwickler verstehen. Ubiquitous Language bedeutet, dass Fachexperten, Entwickler, Produktmanager und alle anderen Beteiligten dieselbe Sprache verwenden, um über die Geschäftsdomäne zu sprechen.

Gute vs. schlechte Event-Namen:

❌ Technische Namen ✅ Geschäftssprachliche Namen Verbesserung
DatabaseRowInserted OrderPlaced Geschäftsereignis statt technisches Detail
EntityStateChanged CustomerUpgraded Spezifische Bedeutung statt allgemein
DataUpdated PriceAdjusted Klare Intention der Änderung
MessageProcessed PaymentVerified Fachlicher Prozessschritt
RecordModified ShippingAddressUpdated Konkrete Geschäftsaktion

Wenn wir Events benennen und strukturieren, haben wir eine außergewöhnliche Gelegenheit, diese gemeinsame Sprache zu stärken und zu verfeinern. Events repräsentieren die bedeutsamsten Momente im Leben einer Geschäftsdomäne. Sie sind die Geschichten, die das System erzählt: “Ein Kunde hat eine Bestellung aufgegeben”, “Eine Zahlung wurde verarbeitet”, “Ein Artikel wurde versandt”. Diese Geschichten sollten in einer Sprache erzählt werden, die sowohl für Geschäftsexperten als auch für Entwickler verständlich und meaningful ist.

Die Namensgebung von Events ist dabei der erste und wichtigste Schritt. Ein Event namens “OrderPlaced” spricht sowohl Entwickler als auch Geschäftsleute an. Es ist klar, präzise und verwendet die Terminologie, die im Unternehmen üblich ist. Im Gegensatz dazu wäre ein Event namens “DatabaseRowInserted” oder “EntityStateChanged” nur für Entwickler verständlich und würde die Gelegenheit versäumen, die Geschäftssprache zu stärken.

Event-Namenskonventionen:

Aber es geht über die reine Namensgebung hinaus. Die Struktur und der Inhalt von Events sollten die fachlichen Konzepte und Beziehungen widerspiegeln. Ein “BestellungStorniert”-Event sollte nicht nur eine ID enthalten, sondern alle Informationen, die für das Verständnis dieses Geschäftsereignisses relevant sind:

{
  "eventType": "OrderCancelled",
  "orderId": "ORD-2025-001234",
  "customerId": "CUST-98765",
  "cancellationReason": "Customer requested",
  "cancelledBy": "customer",
  "refundAmount": 149.99,
  "affectedItems": ["SKU-001", "SKU-002"],
  "cancellationTimestamp": "2025-01-15T14:30:00Z"
}

Die Entwicklung einer Ubiquitous Language ist ein iterativer Prozess, der Events als Katalysator nutzen kann. Wenn Teams beginnen, Events zu modellieren, entstehen natürlich Diskussionen über die präzise Bedeutung von Geschäftsbegriffen.

Klärende Fragen bei Event-Modellierung:

Diese Diskussionen führen zu einem schärferen Verständnis der Geschäftsprozesse und zu präziseren Definitionen.

Context-spezifische Event-Sprachen:

Die Konsistenz der Event-Sprache über verschiedene Bounded Contexts hinweg ist eine besondere Herausforderung. Verschiedene Contexts können unterschiedliche Terminologie für ähnliche Konzepte verwenden, und das ist oft richtig und notwendig.

Context Terminologie Event-Beispiele
Sales Leads, Opportunities, Prospects ProspectContacted, LeadConverted
Fulfillment Orders, Shipments, Deliveries OrderFulfilled, PackageDispatched
Customer Service Tickets, Cases, Issues SupportTicketOpened, IssueResolved
Marketing Campaigns, Segments, Conversions CampaignLaunched, SegmentUpdated

Integration Events, die zwischen Contexts fließen, bieten eine Gelegenheit für bewusste Übersetzung zwischen verschiedenen Ubiquitous Languages:

Sales Context:           Marketing Context:
ProspectConverted   →    NewCustomerRegistered

Internal Events:         Integration Events:
- ProspectStatusChanged  - CustomerRegistrationCompleted
- SalesOpportunityClosed - CustomerSegmentAssigned

Event-Workshop Agenda:

Event-Workshops mit Fachexperten sind ein mächtiges Werkzeug zur Entwicklung der Ubiquitous Language:

  1. Geschäftsprozess durchgehen (30 min)
  2. Ereignisse sammeln (45 min)
  3. Events benennen (30 min)
  4. Event-Inhalte definieren (45 min)

Die Dokumentation von Events sollte wie ein Geschäftslexikon fungieren. Jedes Event sollte nicht nur seine technische Struktur dokumentieren, sondern auch seine fachliche Bedeutung, die Umstände, unter denen es auftritt, und seine Auswirkungen auf andere Geschäftsprozesse.

Letztendlich führt eine konsequent angewendete Ubiquitous Language für Events zu Systemen, die nicht nur technisch robust sind, sondern auch als natürliche Erweiterung der Geschäftsprozesse empfunden werden. Events werden zu einer Sprache, in der sowohl Menschen als auch Maschinen über das Geschäft kommunizieren können, und schaffen so eine Brücke zwischen der technischen und der fachlichen Welt.