Search code examples
domain-driven-designaggregateroot

Should the Read side of an event-sourced or CQRS application return AggregateRoots too?


In an event_sourced environment, such as the Ruby toolkit event_sourcery the Aggregate Root has a clear function: to setup, compile data and emit events. As outlined in 'What's an Aggregate Root?'.

Events, emitted by that Aggregate Root, for example a Place, would emit a PlaceAdded event.

Subscribed processors then ensure a record is added to a projection, a table in a query database. For example the table proposed_places.

On the other side of the application, the Q part of CQRS, there are queries that can be performed; e.g. LatestProposedPlacesQuery will return a list of Proposed places from the proposed_places table.

So far the set-up (and I'm not confident this is entirely correct, either).

Now, I'm wondering if the aggregate mentioned above, the Place Aggregate, is the proper thing to return when querying. In other words, should the query of Proposed Places return a list of Places aggregate root objects? Or is the Aggregate only concerned with the command/write part of the application? Or am I completely misunderstanding this alltogether?


Solution

  • In other words, should the query of Proposed Places return a list of Places aggregate root objects? Or is the Aggregate only concerned with the command/write part of the application? Or am I completely misunderstanding this alltogether?

    TL;DR -- you don't typically process query messages with aggregate roots.

    In 2003, when the aggregate root pattern was introduced, that's how it was done; there is one data structure, and therefore one object that knows the details of that data structure, so if you want to ask a question of the data structure you forward it via the "object".

    So you'll still find plenty of literature that supports that approach.

    But in many cases, it doesn't really buy you very much. In particular, it is wasteful ceremony to copy data into an object for no other reason than to copy it back out again. Collections of objects scattered throughout memory aren't nearly as efficient as a carefully tuned data structure, and in many cases stale representations of the model provide full business value while being much easier to deliver and maintain.

    Event sourcing exaggerates that further, as logs of events tend to be a lousy representation for answering questions.

    Today? The aggregates aren't adding very much to the maintainability of your query handling code - just transform the data into the shape you need and get on with it.

    As a bonus benefit, you get better cohesion in the aggregates, as that code only needs to worry about maintaining the appropriate domain invariant for the data structure, and doesn't get cluttered with a bunch of methods unrelated to change.