Skip to content

Domain events: let update/create surface what changed #40

Description

@btravers

Problem

The how-to guides model aggregates, but the DDD story stops at state: update returns the new instance and nothing else. Real aggregates want to announce what happened — InvoiceIssued, OrganizationRenamed — so the composition root can dispatch side effects (outbox, integration events, projections) without diffing two instances by hand.

Proposal sketch

Stay pure and I/O-free; events are values returned alongside the entity, never dispatched by the package:

const outcome = invoice.update({ status: "ISSUED" as InvoiceStatus });
// today: Result<Invoice, InvalidEntity>
// possible: Result<{ entity: Invoice; events: readonly DomainEvent[] }, InvalidEntity>

Open design questions (all genuinely open — this needs a design pass before any code):

  • Where events are declared. A per-entity events option mapping a name to a payload schema (branded, like everything else)? Or free-form, produced by domain methods in the class body?
  • Who produces them. Automatic field-diff events are tempting but wrong (they describe what changed, not why); explicit emission from behaviour methods matches the DDD intent but needs an ergonomic way for a class-body method to both update and emit.
  • Backward compatibility. The return-shape change is breaking; an opt-in surface (updateWith? a declared-events entity variant?) may be the honest cost of "one concept, one name" — to be weighed against surface growth and the "library can be done" philosophy.

If the design conversation concludes the package should stay state-only, the fallback is a documented pattern: behaviour methods returning Result<{ entity; events }> built from update — which needs no new API, only a how-to page.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions