Chapitre 1 · Leçon 2
Frontières de cohérence et communication entre contextes
Un Aggregate est un groupe d'objets (entités + value objects) traité comme une unité de cohérence. Toute modification passe par la racine de l'agrégat (Aggregate Root). Les Domain Events permettent la communication découplée entre agrégats.
snippet.typescript
1// Order Aggregate — racine d'agrégat
2class Order extends Entity<string> {
3 private _items: OrderItem[] = []; // Entités internes à l'agrégat
4 private _status: OrderStatus = 'draft';
5 private _total: Money;
6 private _events: DomainEvent[] = [];
7
8 // ❌ On n'expose PAS les items directement
9 // Toutes les mutations passent par des méthodes de l'agrégat
10
11 addItem(productId: string, name: string, price: Money, qty: number): void {
12 if (this._status !== 'draft') {
13 throw new DomainError('Impossible de modifier une commande confirmée');
14 }
15 const existing = this._items.find((i) => i.productId === productId);
16 if (existing) {
17 existing.increaseQuantity(qty); // mutation interne autorisée
18 } else {
19 this._items.push(OrderItem.create({ productId, name, price, qty }));
20 }
21 this._total = this.calculateTotal();
22 }
23
24 confirm(): void {
25 if (this._items.length === 0) {
26 throw new DomainError('Impossible de confirmer une commande vide');
27 }
28 this._status = 'confirmed';
29 // Domain Event — d'autres parties du système peuvent réagir
30 this._events.push(
31 new OrderConfirmed({
32 orderId: this._id,
33 total: this._total,
34 confirmedAt: new Date(),
35 })
36 );
37 }
38
39 private calculateTotal(): Money {
40 return this._items.reduce(
41 (acc, item) => acc.add(item.subtotal),
42 Money.of(0, 'XOF')
43 );
44 }
45}
46
47// Domain Event — immutable, passé simple
48class OrderConfirmed implements DomainEvent {
49 readonly name = 'OrderConfirmed';
50 readonly occurredAt: Date;
51 readonly orderId: string;
52 readonly total: Money;
53
54 constructor(props: { orderId: string; total: Money; confirmedAt: Date }) {
55 this.orderId = props.orderId;
56 this.total = props.total;
57 this.occurredAt = props.confirmedAt;
58 }
59}La règle d'or DDD : une transaction de base de données ne doit modifier qu'un seul agrégat. Si tu dois modifier deux agrégats en même temps, utilise des Domain Events pour déclencher la deuxième modification de façon asynchrone.
Entity = identité. Value Object = immuable + égalité par valeur. Aggregate = frontière de cohérence. Domain Event = fait métier qui s'est produit. Ces 4 concepts couvrent 80% du DDD tactique.