should I create an intermediary aggregate between these two aggregates
something like SQL JOIN? In this one example, I'd like to see how
similar use cases where two aggregates communicate with each other are
implemented in Axon Framework.
Great question. I'm going to start by saying no, and then try to help you understand why.
Let's start with why aggregates exist. From the DDD reference:
Aggregates
It is difficult to guarantee the consistency of changes to objects in a model with complex associations.
[...]
Therefore:
Cluster the entities and value objects into aggregates and define boundaries around each. Choose one entity to be the root of each aggregate, and allow external objects to hold references to the root only
OK, so the reason for using aggregates is to avoid intermediaries.
Since you are doing CQRS (which implies DDD and event sourcing), you have a command side and a query side (Command Query Request Segregation). If you are more familiar with CRUD style applications and relational databases, chances are that you're focusing on the query side and not the command side.
Let's clarify a few things, in CQRS:
- Aggregates are only relevant to the command side
- Aggregates are responsible for handling commands and publishing events
- Aggregates are responsible for enforcing business rules
What this means is that for the command side:
Commands are passed to aggregates, which decide if they should publish events or deny the command.
On the query side:
Events originating from the command side are processed to build up a query model (probably what you refer to as the data model)
Hence, I am first focused on building the data model, not the domain
model
In an event sourced system, you typically focus on the domain model and the associated events. The query model can be fully built based on the events from the domain model.
Since you are not yet focusing on the domain model you don't yet have to care about aggregates :)
Again, back to your original question:
One of the basic requirements is that the user has borrowed the book
should I create an intermediary aggregate between these two aggregates
something like SQL JOIN?
Based on your domain, you already have a User and Book aggregate. You have single requirement that users can borrow books. Now I'm no expert on your domain, but ask yourself: why do you need another aggregate? What would this new aggregate be responsible for? What would be wrong with just having Book.borrow(userId)
which publishes a BookBorrowed(bookId, userId)
event if the user is allowed to borrow the book?