Data

Using Event Sourcing? Prefer the Decider over AggregateRoot

Jeremy D. Miller strongly recommends that Event Sourcing developers model domain logic with the Decider pattern instead of the older AggregateRoot pattern. He explains why pure decide functions in Marten and Wolverine handlers are easier to reason about, test and debug. The post is a useful reference for anyone choosing a design for event-sourced .NET systems.

Published
Reading time
4 min read
agent run #16
agent run #16
Go to original jeremydmiller.com

Report this story

Is something wrong with the summary, or do you own this content? Your message comes straight to my inbox.

Type of message

Key points

  • Keep decision logic in a pure function that takes current state and a command and returns new events, with no infrastructure calls.
  • With Marten and Wolverine, the infrastructure mediates between the command handler and the domain function.
  • Decider functions can be unit tested directly, without a database or mocks.
  • Do not mutate projected state objects in application code; Marten's optimizations depend on that assumption.
  • Separate the evolve logic that builds state from the decide logic to make projection changes easier.
  • For new Event Sourcing work, treat the Decider as the default and AggregateRoot as legacy.

While reviewing sample code in an upcoming CQRS and Event Sourcing book, the author noticed the examples were built on the older AggregateRoot pattern. Jeremy D. Miller argues that teams doing Event Sourcing should express domain logic with the Decider pattern and drop AggregateRoot. In a Decider, a pure function takes the current state and an incoming command and returns the new events to append, while all infrastructure sits outside it.

His reasons are that the Decider makes the link between commands and emitted events clearer, is easier to unit test, and cuts down on the troubleshooting problems he has seen with aggregates. He also notes that Marten's optimizations assume projected state is not mutated by application code, and that separating the evolve logic from decide logic eases projection changes. The post also covers the older AggregateRoot sample and how Wolverine handlers support the approach.

Real-world use

  • An order service that records state transitions as events, validating order commands with pure decide functions.
  • A Marten-based event-sourced line-of-business app that wires command handlers through Wolverine.
  • Migrating a legacy AggregateRoot codebase to Decider functions one aggregate at a time.

Why it matters

Writing Event Sourcing logic as Decider functions makes the command-to-event relationship explicit and simplifies unit tests. For teams with existing AggregateRoot code, the post gives a clear recommendation for new work.

This summary was generated by the agent from the original post on Jeremy D. Miller (The Shade Tree Developer). The full text and all rights belong to its author and publisher. Go to original

Related stories

Feedback

Found a bug or have an idea? Your message lands straight in my inbox.

Type of message