Modul 4: Domain-Driven Design — Die Domäne ins Zentrum
DDD: Bounded Contexts, Aggregates, Entities, Value Objects, Repositories. Wie man Business-Logik modelliert, die bleibt.
Domain-Driven Design — Die Domäne ins Zentrum
Lektion 16 von 5
Was ist DDD?
Domain-Driven Design (Eric Evans, 2003) dreht die Architektur um: Nicht die Datenbank bestimmt das Modell, sondern die Geschäftsdomäne. Die Entwickler sprechen mit Domänenexperten in einer gemeinsamen Sprache (Ubiquitous Language) und modellieren die Business-Logik als ersten Burger.
Lesson 1: Ubiquitous Language
Code und Geschäft sprechen dieselbe Sprache. Heißt es im Geschäft "Versicherungsschein", heißt die Klasse Policy, nicht InsuranceRecord. Ein "Schadenfall" wird Claim, nicht DamageEvent. Diese gemeinsame Sprache zieht sich von Requirements über Tests bis in die Klassennamen.
Lesson 2: Bounded Contexts
Ein großes System hat mehrere Domänen mit unterschiedlichen Begriffen. Ein "Kunde" im Vertrieb ist nicht derselbe "Kunde" im Versand. Bounded Contexts grenzen eine Domäneneinheit ab: Jeder Context hat sein eigenes Modell, seine eigene Datenbank, seine eigene Sprache. Kontexte kommunizieren über explizite Schnittstellen (Anti-Corruption Layer).
Lesson 3: Entities und Value Objects
Entities haben Identität (eine ID) und Lebenszyklus. Zwei Customer mit derselben Adresse sind trotzdem verschieden. Value Objects haben keine Identität — sie sind durch ihre Werte definiert. Zwei Geldbeträge von 50 EUR sind identisch. Value Objects sind immutable und einfach zu testen. Faustregel: Was kein Lebenszyklus braucht, ist ein Value Object.
// Value Object: immutable, durch Werte definiert (Java Record)
record Money(BigDecimal amount, Currency currency) {
Money add(Money other) {
if (!currency.equals(other.currency()))
throw new IllegalArgumentException("Währungen müssen übereinstimmen");
return new Money(amount.add(other.amount()), currency);
}
}
// Entity: Identität + Lebenszyklus
class Claim {
private final ClaimId id; // Identität — nicht der Inhalt
private Money amount; // Value Object innen drin
void updateAmount(Money m) { this.amount = m; } // Zustand ändert sich, ID bleibt
}
Lesson 4: Aggregates und Aggregate Roots
Ein Aggregate ist eine Konsistenzgrenze: eine Gruppe von Entities und Value Objects, die zusammen geändert werden. Die Aggregate Root ist der einzige Einstiegspunkt — außen kann niemand ein LineItem direkt ändern, nur über die Order. Das Aggregate wahrt Invarianten (z. B. "Bestellmenge > 0").
Lesson 5: Repositories und Domänen-Services
Repositories kapseln Persistenz: save(), findById(), findByCustomer(). Die Domäne definiert das Interface, die Infrastruktur implementiert (JPA, Mongo). Domänen-Services enthalten Business-Logik, die nicht zu einer einzelnen Entity gehort (z. B. Preisberechnung über mehrere Policen).
Aggregate = Konsistenzgrenze, nicht nur eine Gruppe von Entities
Das Aggregate definiert, was zusammen geändert werden darf. Die Root wahrt die Invarianten. Ein Versto gegen die Invarianten innerhalb eines Aggregates ist ein Bug. Ein Versto zwischen Aggregaten ist eventuelle Konsistenz — und das ist in Ordnung.
Praxis-Szenario: Versicherung: Policy als Aggregate Root
Eine Policy hat mehrere Claims. Soll man Claim direkt über ein ClaimRepository ändern oder nur über Policy?
✅ Wichtige Erkenntnisse
Haken setzen, um deinen Lernfortschritt zu markieren: