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?

  • Did you mean "Additional command handlers"? Can you update that in the question? If that's what you meant, then I'd say, no. Commands are handled by the single aggregate that they are meant for, and they create events that are broadcast into the world for everyone that cares (which may include the aggregate itself). – Ivan Pintar Mar 21 '18 at 14:04

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

  • +1 for the Udi Dahan link, which is quite illuminating. I get lost about halfway through your answer though. – Robert Harvey Mar 2 '18 at 4:34
  • But what do event handlers do which is not domain? Your tic tac toe example would work perfectly with just an event handler reading state and executing the domain logic by emitting events. – Witek Mar 4 '18 at 21:09

I don't think you're using the term aggregate function in it's classical sense.

A command is something that can be refused. An event is a report that something has happened. It can't be refused. Only ignored. Events shouldn't throw exceptions or return values. They just happen and things react to them.

The difference is somewhat semantic. An event describes something in the past. A command describes something in the future. It's only because the prediction of the future can be wrong that the command is the one that can be refused.

Whether something should have an event handler is entirely about whether that something cares that the event has happened. It might change state. It might pass the event on to something else, maybe in a different form.

  • I get this. My question is if I need three functions instead of two? – Witek Mar 4 '18 at 21:12

There's ambiguity in your question between events and commands, especially when you say

functions for handling events which accept the command data

But they are really two separate things. In the domain, I prefer to talk about handling a command, with signature:

eventStream -> command -> event

and applying an event:

currentState -> event -> nextState

They don't happen at the same time - actually, event application may never be called even though you accepted the command at some point! That's because event application doesn't occur until you replay the events to load the aggregate.

Now there might be a third kind of function that doesn't belong in the Domain - event handlers in the sense of subscribers. They receive the event and trigger a number of side effects based on it.

  • Yes, I screwed up. It was a typo. I meant handling commands there. – Witek Mar 4 '18 at 21:14

Your Answer

