How should separate aggregate roots (AR) communicate with one another in an environment built on DDD principles using an event-sourced aggregate back-end?
For instance, I have a Facility
aggregate root (AR) which has a factory method responsible for creating a Booking
AR. The Booking
is a time-sensitive combination of a Person
AR and a Facility
AR. A Person
can only be booked in a single Facility
.
In DDD, I would have held references to the Booking
in Person
, and Person
in Facility
. However, when generating events for use in event-sourcing I think that trying to handle the event deserialization from the back-end would become prohibitive. Therefore, I've taken to only holding references to the value object-based unique id's. This brings up a new problem, however, when a method on an AR needs to call another method on another AR -- how do you handle that situation? Hit the event source repository from the domain AR?
What is the general use case in this scenario? Am I approaching this all wrong?
CQRS is implemented by a separation of responsibilities between commands and queries, and event sourcing is implemented by using the sequence of events to track changes in data.
An aggregate is a cluster of associated objects that we treat as a unit for the purpose of data changes. Each aggregate has a root and a boundary. The boundary defines what is inside the aggregate. The root is a single, specific entity contained in the aggregate.
In terms of Domain-Driven Design Aggregate is a logical group of Entities and Value Objects that are treated as a single unit (OOP, Composition). Aggregate Root is a single one Entity that all others are bound to.
Event sourcing is a powerful pattern and brings a lot of benefits to an application architecture if used appropriately: Makes write operations much faster as there is no read, update, and write required; write is merely appending an event to a log.
Aggregate Root boundaries define a consistency boundary. Inside the aggregate, consistency is guaranteed. Outside... it's not. So you should not have operations that spans several aggregates and have to be consistent. If you need a transaction that spans two aggregates, you should review your aggregate boundaries.
For things that happen outside the aggregate you should have an event handler that will send a command to other aggregates. If the logic of actions between aggregates is more complicated, you can define a process, a state machine that will listen to events and send commands to aggregates. Processes can be used to define long running transactions (with compensation instead of rollback), or take business decisions based on what's happening in the system at a large scale (even between bounded contexts).
When using Event Sourcing and CQRS the most elegant (at least in my opinion) way of inter-AR communication is messaging. You can look at Ncqrs project (it will be easier if you are a .NET guy), particularly 'Messaging' branch. The idea is, ARs implement IMessageHandler interface for every message type they handle and AR base class exposes method Send for sending there messages. By means of this API clients can invoke model behavior and model itself can communicate (between ARs).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With