Playbook
DDD im Code: Entity, Value Object und Aggregate (Ddd Im Code Entity Value Object Und Aggregate)
Wie funktionieren taktische DDD-Patterns? Value Objects, Entities, Aggregates, Domain Services, Application Services und Repository-Grenzen am Beispiel einer…
Die Frage dieses Kapitels
Das erste Kapitel begann mit Geschäftssprache und Regeln. Jetzt lautet die Frage: Wo leben diese Entscheidungen im Code? Wir bleiben bei derselben E-Commerce-Domain: Geld, Bestellpositionen, Bestellung und Zahlungsablauf.
Money + Address + Quantity → Value Object
OrderLine + Order → Entity
Order (Root) + OrderLine → Aggregate
Repository → lädt und speichert den Aggregate Root
Begriffe bei der ersten Verwendung
📦 Value Object
Ein Konzept ohne Identität, das durch seinen Wert definiert und unveränderlich gehalten wird.
📦 Entity
Ein Objekt, das durch seine Identität dasselbe bleibt, auch wenn sich Attribute ändern.
📦 Aggregate
Die Transaction Boundary für Objekte, die gemeinsam konsistent bleiben müssen.
📦 Aggregate Root
Der einzige externe Einstieg in ein Aggregate.
Zwei Money(100, "TRY")-Werte stehen für denselben Wert; zwei Bestellungen sind trotz gleichem Gesamtbetrag verschieden.
Mit Value Objects beginnen
Value Objects vermitteln die DDD-Denkweise besonders klar. Ein decimal ist nicht von selbst Geld: Währung, Rundung, Rabatt und Steuerregeln gehören zum Konzept. Bewahren Sie diese Regeln beim Konzept auf, statt sie über Services zu verstreuen.
public sealed record Money(decimal Amount, string Currency)
{
public Money Add(Money other)
{
if (Currency != other.Currency) throw new DomainException("Currency mismatch");
return new Money(Amount + other.Amount, Currency);
}
}
Value Objects sind immutable. Ein geänderter Wert wird zu einer neuen Instanz und verhindert Side Effects zwischen Preis-, Liefer- und Zahlungsschritten. Gleichheit ist strukturell: O(m) für m Felder, aber eine Regel an einer Stelle senkt spätere Änderungskosten.
Entity: Identität und Lebenszyklus
Order ist eine Entity. Adresse und Betrag können sich ändern, dennoch bleibt es dieselbe Bestellung. Entscheidend ist nicht, Setter zu vermeiden, sondern einen Übergang als Geschäftsverhalten zu modellieren.
❌ order.Status = Paid
✓ order.ConfirmPayment(payment)
❌ order.Total = total - discount
✓ order.ApplyDiscount(discount)
ConfirmPayment prüft Zahlungsnachweis, Stornierungszustand und den erlaubten Übergang an einer Stelle. Eine Entity muss ungültige Zustände in ihrem Lebenszyklus verhindern.
Aggregate: keine Objektgruppe, sondern Konsistenzgrenze
Bestellung und Positionen müssen in einer Transaction konsistent bleiben: Menge ist positiv, Total entspricht den Positionen, und nach Bestätigung dürfen Positionen unveränderlich sein. Daher ist Order der Aggregate Root von OrderLine.
Order aggregate
├─ OrderLine
├─ ShippingAddress
└─ Total
Externer Code → Order.AddLine() / Order.ConfirmPayment()
Externer Code ↛ schreibt nicht direkt in OrderLine
Ein großes Aggregate schafft keine Sicherheit, sondern Locks und Versionskonflikte. Aktualisieren Sie pro Write möglichst ein Aggregate. Referenzieren Sie andere Aggregates per ID und koordinieren Sie mit Application Orchestration oder Domain Events.
Domain Service, Application Service und Repository
Ein Domain Service modelliert reine Domain-Logik, die keinem einzelnen Aggregate gehört, etwa Wechselkurs-Preisfindung. Ein Application Service orchestriert den Use Case: Bestellung laden, Verhalten aufrufen, speichern, Transaction abschließen.
| Layer | Verantwortung |
|---|---|
| Value Object / Entity / Aggregate | Geschäftsregeln und Invariants schützen |
| Domain Service | Reine Domain-Berechnung ohne einzelnen Aggregate Owner |
| Application Service | Use-Case-Orchestrierung, Transactions, Adapter |
Ein Repository ist keine Tabellen-API. Es bietet Collection-artige Persistenz nur für Aggregate Roots. Direktes Laden einer OrderLine umgeht Root und Regeln.
order = orderRepository.get(orderId)
order.confirmPayment(payment)
orderRepository.save(order)
Diese Grenze macht Domain-Verhalten auch mit einem Fake Repository testbar, ohne das Model nach einem ORM zu formen.
Zuordnungen, die falsche Sicherheit erzeugen
❌ Value Object = kleiner DTO
✓ Es trägt Wert, Validierung und Verhalten.
❌ Aggregate = größtmöglicher Objektgraph
✓ Es ist eine bewusst kleine Transaction und Consistency Boundary.
❌ Domain Service = Ablage für Regeln
✓ Es ist reine Domain-Logik, die keinem einzelnen Aggregate gehört.
❌ Repository = CRUD API für jede Tabelle
✓ Es ist die Persistenzgrenze eines Aggregate Root.
Implementierungs-Checkliste
- Wandern
Money,Email,AddressundQuantityals Primitive durch den Code? - Verhindert jedes Entity-Verhalten einen echten ungültigen Zustand?
- Aktualisiert ein Write mehrere Aggregates atomar?
- Entscheidet der Application Service Regeln oder orchestriert er nur?
- Laden Repositories nur Aggregate Roots?
Beginnen Sie mit der teuersten Geschäftsregel; wandeln Sie nicht das ganze System gleichzeitig um.
Was im Gedächtnis bleiben sollte
Ein Value Object trägt Wert und Regeln eines Konzepts. Eine Entity schützt Identität und Lebenszyklus. Ein Aggregate zieht eine kleine Transaction Boundary für Konsistenz. Ein Repository verbindet diese Grenze mit Persistenz.
Taktisches DDD bedeutet nicht mehr Klassen, sondern verhindert, dass Geschäftsregeln in die falsche Schicht gelangen.
Im nächsten Kapitel betrachten wir diese Grenzen im großen System: Bounded Contexts, Context Mapping und Trennung innerhalb eines Monolithen.
FAQ
Häufige Fragen
Was ist Value Object?
Ein Konzept ohne Identität, das durch seinen Wert definiert und unveränderlich gehalten wird.
Was ist Entity?
Ein Objekt, das durch seine Identität dasselbe bleibt, auch wenn sich Attribute ändern.
Stimmt es, dass „Value Object = kleiner DTO“?
Es trägt Wert, Validierung und Verhalten.
Was legt dieser Teil fest?
Das erste Kapitel begann mit Geschäftssprache und Regeln. Jetzt lautet die Frage: Wo leben diese Entscheidungen im Code? Wir bleiben bei derselben E-Commerce-Domain: Geld, Bestellpositionen, Bestellung und Zahlungsablauf. Das erste Kapitel begann mit Geschäftssprache und Regeln. Jetzt lautet die Frage: Wo leben diese Entscheidungen im Code? Wir bleiben bei derselben E-Commerce-Domain: Geld, Bestellpositionen, Bestellung und Zahlungsablauf.
Gelernte Engineering-Prinzipien
- Value Objects verbinden primitive Daten mit Geschäftssemantik und Validierung.
- Aggregates sollen kleine, explizite Konsistenzgrenzen sein.
- Application Services orchestrieren; Domain-Verhalten entscheidet.
Weiterlesen
Weiterlesen
Verwandte Beitrage
DDD- Software nach dem Geschäft statt nach der Datenbank gestalten
Was ist Domain-Driven Design? Ein Leitfaden zu den Grenzen datengetriebenen Designs, zur Kraft einer gemeinsamen Sprache und dazu, wann sich DDD wirklich…
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 DDD in großen Systemen?
Wie skaliert DDD in großen Systemen? Ein Entscheidungsleitfaden zu Bounded Contexts, Context Mapping, Conway's Law, modularen Monolithen,…