First of all, let me state that I am new to Command Query Responsibility Segregation and Event Sourcing (Message-Drive Architecture), but I'm already seeing some significant design benefits. However, there are still a few issues on which I'm unclear.
Say I have a Customer
class (an aggregate root) that contains a property called postalAddress
(an instance of the Address
class, which is a value object). I also have an Order
class (another aggregate root) that contains (among OrderItem
objects and other things) a property called deliveryAddress
(also an instance of the Address
class) and a string property called status
.
The customer places an order by issueing a PlaceOrder
command, which triggers the OrderReceived
event. At this point in time, the status of the order is "RECEIVED"
. When the order is shipped, someone in the warehouse issues an ShipOrder
command, which triggers the OrderShipped
event. At this point in time, the status of the order is "SHIPPED"
.
One of the business rules is that if a Customer
updates their postalAddress
before an order is shipped (i.e., while the status is still "RECEIVED"
), the deliveryAddress
of the Order
object should also be updated. If the status of the Order
were already "SHIPPED"
, the deliveryAddress
would not be updated.
Question 1. Is the best place to put this "conditionally cascading address update" in a Saga (a.k.a., Process Manager)? I assume so, given that it is translating an event ("The customer just updated their postal address...") to a command ("... so update the delivery address of order 123").
Question 2. If a Saga is the right tool for the job, how does it identify the orders that belong to the user, given that an aggregate can only be retrieved by it's unique ID (in my case a UUID)?
Continuing on, given that each aggregate represents a transactional boundary, if the system were to crash after the Customer
's postalAddress
was updated (the CustomerAddressUpdated
event being persisted to the event store) but before the OrderDeliveryAddressUpdated
could be updated (i.e., between the two transactions), then the system is left in an inconsistent state.
Question 3. How are such "violations" of consistency rules detected and rectified?
In most instances the delivery address of an order should be independent of any other data change as a customer may want he order sent to an arbitrary address. That being said, I'll give my 2c on how you could approach this:
Yes. You should have an
OrderProcess
.There is nothing preventing one from adding any additional lookup mechanism that associates data to an aggregate id. In my experimental, going-live-soon, mechanism called shuttle-recall I have a
IKeyStore
mechanism that associates any arbitrary key to an AR Id. So you would be able to associate something like[order-process]:customerId=CID-123;
as a key to some aggregate.In most cases they could be handled out-of-band, if possible. Should I order something from Amazon and I attempt to change my address after the order has shipped the order is still going to the original address. If your case of linking the customer postal address to the active order address you could notify the customer that n number of orders have had their addresses updated but that a recent order (within some tolerance) has not.
As for the system going down before processing you should have some guaranteed delivery mechanism to handle this. I do not regard these domain event in the same way I regard system events in a messaging infrastructure such as a service bus.
Just some thoughts :)