CodePark/ questions / Domain-driven design
START PRACTICINGPRACTICE
Backend question · Software design & patterns › Domain-driven design

What are domain events, and how would you raise and handle them inside a single service?

class Order {
  private events: DomainEvent[] = [];
  pay(payment: Payment) {
    if (this.status !== "placed") throw new OrderNotPayableError(this.id);
    this.status = "paid";
    this.events.push(new OrderPaid(this.id, payment.amount));
  }
  pullEvents() { const e = this.events; this.events = []; return e; }
}

A domain event records something important that happened in the domain. It has a past-tense name in the ubiquitous language (the shared vocabulary of developers and domain experts), such as OrderPaid or CustomerRelocated.

Domain events let one part of the domain react to another part without calling it directly. This keeps the parts loosely coupled. They are also the usual way to apply rules that span more than one aggregate (a group of objects that is saved and changed as one unit).

A common way to do this inside one process:

  • The aggregate records events as its state changes, as in the code above.
  • The application service saves the aggregate.
  • Then the application service takes the aggregate's events and sends them to handlers. For example, one handler reserves stock and another sends a receipt.

Send the events after the database commit. This way, handlers never react to changes that were rolled back. If a handler's work must never be lost, store the event in the same transaction as the data. Then process it asynchronously later.

Domain events are internal. Events published to other services are called integration events. They are a public contract, so design and version them separately.

  • Domain events are past-tense facts named in the domain language.
  • Aggregates raise domain events when their state changes.
  • The application layer dispatches the events, usually after the commit.
  • Domain events are used for side effects and for consistency across aggregates.
  • Domain events are different from integration events published to other services.