Thanks for your response.
Unfortunately it did not get me much closer to crying heureka. About the fake domains, of course you are right. But the real domain would take an hour of reading to get familiar with, so even if I was at the liberty share it, it would be too scary and boring at the same time to get a response.
But okay, let’s try to do another attempt, trying to make it simple enough, but still describing the problem I face well enough.
Let’s imagine a very simple automated warehouse.There’s pallets and shelves. All pallets have a unique ID. All shelves have a unique address. We are building a system that always keeps track of where the pallets are, and can respond to queries for locating the pallets, or shelves with enough space left for additional pallets.
Between shelves the pallets are moved by forklifts. Client systems decide what pallets need to be moved and by which forklift, based on the information we provide (where’s a specific bin, where’s enough space to put it).
Each forklift is identified as well, and whenever a pallet is loaded on a forklift or unloaded onto a shelf, our software gets a location update for this pallet.
So any pallet that’s in the system is considered to be either on a shelf or on a forklift, and at any moment the system must be able to tell where a specific pallet is, and which are the shelves where a pallet can be put.
The final concept to intruduce is that any time the other system selects a shelf as a target to a pallet, it tries to reserve that shell, to stop other processes from sending a pallet to the same shelf. So from the client perspective when they’re trying to store a pallet, it’s:
- Query: shelf with enough space
- Select target shelf from result set
- Reserve target shelf
- Send a forklift (external)
- (after pallet has been loaded) Update pallet location -> forklift (and increase free space on source shelf)
- (after pallet has been unloaded on the shelf) Update pallet location -> shelf (also, reduce free space on target shelf!)
- Release target shelf
(Obviously, only one client can reserve a shelf at any time, and it remains reserved until released by that client. So one shelf can have zero or one client reservations).
So what I find is there’s events that affect:
- a shelf
- a pallet and a shelf and a forklift
No matter how I think about it, I see these options:
- introduce a process manager and work with multiple aggregates
- have a single aggregate that represents the entire warehouse and I let it do everything (processing location updates and making reservations)
- my aggregates are not the shelves, nor the pallets, nor the warehouse, but… something I cannot think of. The reservations? The location updates?
I feel that with the first approach I am trying to force a domain model that’s more natural to me, but is not well suited for the scenario.
But with the second approach I’m also unhappy, considering I have one “god” aggregate that enforces consistency alright, but every command goes to it, every event happens to it, and so it has to load Encyclopedia Britannica a hundred times a second. And I also feel that ending up using EventStore writing everything into a single stream, I’m doing something wrong.
And the third approach is not really an option until I manage to understand it. Hence this topic.