DDD: Event handlers and aggregates in functional programming

cqrsdomain-driven-designevent-sourcingfunctional programming

When implementing a DDD driven system (based on event sourcing) using a functional programming language (Clojure), should one separate event handler functions from aggregate functions?

In my naive implementation an aggregate would be a namespace with

  • functions for handling commands which accept the current state data + command data and return event data
  • functions for applying event data to the aggregates state

Is there a reason to have additional command handler functions which get the command data and call functions on the aggregate namespace? What would one put into these handlers and not into the aggregate? And why?

Best Answer

Is there a reason to have additional event handler functions which get the command data and call functions on the aggregate namespace?

Yes. Part of the motivation for a "domain model" is to have all of the code responsible for ensuring the consistency of the data in "one" place. Evans describes solutions in the context of a three tiered architecture (application, domain model, persistence), and was discouraging the anti pattern of leaking the consistency checks into the application layer.

Consistency, here, means that we don't blindly change the data as described by the command, but instead make additional changes, if necessary, to ensure that the overall consistency is maintained.

In other words, domain models are typically associated with services, in the sense described by Udi Dahan. If we weren't interested in ensuring consistency of the commands, we would remove the domain model utterly and deal with the database directly.

So a signature like

f: CommandData -> Events

typically isn't adequate, because in the general case we need to understand the current state to allow the domain model to calculate its own changes.

Let's consider a domain model of a game of tic-tac-toe. We can think of the game state as a representation of which parts of the grid are occupied by symbols, whose turn it is to play, whether the victory condition has been met.

If we get a "Play an X in the center position" command, what events do we emit? And the answer is "that depends"; we can't know what events to emit unless we already know "is it X's turn to play?", "is the center position available?" The answers to these questions depends on the state of the game, which is to say the events that have already happened. We need to know the current state of the game to map "Play an X in the center position" to the correct behavior.

Thus, we need a signature that is analogous to

g: History -> CommandData -> Events

with both the history of the aggregate and the command data being used to compute the new events.

See also: A Functional Foundation for CQRS/ES, by Mathias Verraes