L’interface est localisée ; les présentations et documents des Skills sont traduits automatiquement par IA dans votre langue. Le code, les commandes, chemins et termes techniques restent en version originale, et le document de l’auteur fait foi.
Explorer les Skills
Design et création · SKILL.md

ddd

ddd

Domain-Driven Design patterns. Bounded contexts, aggregates, entities, value objects, domain events, repositories, and application services. Strategic and tactical DDD for complex business domains. USE WHEN: user mentions "DDD", "Domain-Driven Design", "bounded context", "aggregate", "value object", "domain event", "ubiquitous language", "aggregate root", …

Independent GitHub snapshot · Automated classification · Original documentation governs

Documentation de la Skill

GitHub

name: ddd description: | Domain-Driven Design patterns. Bounded contexts, aggregates, entities, value objects, domain events, repositories, and application services. Strategic and tactical DDD for complex business domains.

USE WHEN: user mentions "DDD", "Domain-Driven Design", "bounded context", "aggregate", "value object", "domain event", "ubiquitous language", "aggregate root", "domain service"

DO NOT USE FOR: database schema design - use database skills; CQRS/Event Sourcing specifics - use event-sourcing-cqrs allowed-tools: Read, Grep, Glob, Write, Edit

Domain-Driven Design

Strategic DDD

┌─────────────────┐     ┌─────────────────┐
│  Order Context   │────▶│ Payment Context  │
│  (core domain)   │     │  (supporting)    │
└────────┬────────┘     └─────────────────┘
         │
         ▼
┌─────────────────┐     ┌─────────────────┐
│ Inventory Context│     │ Notification Ctx  │
│  (supporting)    │     │  (generic)       │
└─────────────────┘     └─────────────────┘

Tactical DDD (TypeScript)

Entity

class Order {
  private constructor(
    readonly id: OrderId,
    private items: OrderItem[],
    private status: OrderStatus,
    private readonly createdAt: Date,
  ) {}

  static create(items: OrderItem[]): Order {
    if (items.length === 0) throw new DomainError('Order must have at least one item');
    return new Order(OrderId.generate(), items, OrderStatus.PENDING, new Date());
  }

  get total(): Money {
    return this.items.reduce((sum, item) => sum.add(item.subtotal), Money.zero('USD'));
  }

  confirm(): DomainEvent[] {
    if (this.status !== OrderStatus.PENDING) throw new DomainError('Can only confirm pending orders');
    this.status = OrderStatus.CONFIRMED;
    return [new OrderConfirmed(this.id, this.total)];
  }
}

Value Object

class Money {
  private constructor(readonly amount: number, readonly currency: string) {
    if (amount < 0) throw new DomainError('Amount cannot be negative');
  }

  static of(amount: number, currency: string): Money {
    return new Money(Math.round(amount * 100) / 100, currency);
  }

  static zero(currency: string): Money { return new Money(0, currency); }

  add(other: Money): Money {
    if (this.currency !== other.currency) throw new DomainError('Currency mismatch');
    return Money.of(this.amount + other.amount, this.currency);
  }

  equals(other: Money): boolean {
    return this.amount === other.amount && this.currency === other.currency;
  }
}

Domain Event

class OrderConfirmed implements DomainEvent {
  readonly occurredAt = new Date();
  constructor(readonly orderId: OrderId, readonly total: Money) {}
}

Repository (Port)

interface OrderRepository {
  findById(id: OrderId): Promise<Order | null>;
  save(order: Order): Promise<void>;
  nextId(): OrderId;
}

Application Service

class ConfirmOrderUseCase {
  constructor(
    private orders: OrderRepository,
    private eventBus: EventBus,
  ) {}

  async execute(orderId: string): Promise<void> {
    const order = await this.orders.findById(OrderId.from(orderId));
    if (!order) throw new NotFoundError('Order', orderId);

    const events = order.confirm();
    await this.orders.save(order);
    await this.eventBus.publishAll(events);
  }
}

DDD Building Blocks

Building BlockPurposeIdentity?Mutable?
EntityDomain object with identityYes (ID)Yes
Value ObjectImmutable descriptorNo (structural equality)No
AggregateConsistency boundaryRoot entity has IDYes (via root)
Domain EventSomething that happenedEvent IDNo
RepositoryPersistence abstractionN/AN/A
Domain ServiceLogic not belonging to entityN/AN/A

Anti-Patterns

Anti-PatternFix
Anemic domain model (logic in services)Put business logic in entities
Aggregate too largeKeep aggregates small, reference by ID
Exposing entity internalsUse methods that express domain intent
Cross-aggregate transactionsUse domain events for eventual consistency
Repository returning DTOsReturn domain objects, map in application layer

Production Checklist

  • Bounded contexts identified and documented
  • Ubiquitous language in code matches business terms
  • Aggregates enforce invariants
  • Value objects for all descriptors (Money, Email, Address)
  • Domain events for cross-context communication
  • Repository pattern for persistence abstraction
Skills enregistrées