Moving behavior around to be strongly consistent

133 views
Skip to first unread message

Alexandre Potvin Latreille

unread,
Jul 9, 2015, 12:26:44 AM7/9/15
to ddd...@googlegroups.com
I was looking at a very old post of yreynhout and what striked me in his example is that he's using information outside the boundary (Customer) of the aggregate processing the command (Order) to enforce the business process invariant: "a customer may not have more than five outstanding invoices to place an order".

Therefore, the rule could technically be broken through concurrency; not that there's a high probability that the customer's outstanding invoice count will change while he's placing an order, but it's still possible in theory. I'm already hearing the "what's the real business impact if that rule gets violated" and that's a valid question to ask, but I'm wondering if it would actually be possible to make the rule strongly consistent by moving behavior around...

Speculating that Customer holds the outstanding invoice count in it's boundary and that count is transactionnaly consistent, what if the placeOrder operation was put on Customer instead of Order? placeOrder could act as a factory for Order instances and easily enforce the rule stated above without reaching out of it's own boundary.

The only thing I'm wondering is that we would need to somehow make the optimistic concurrency version of the Customer increment, although placeOrder did not really mutate Customer, it just allowed the creation of a new AR which will be persisted in the same transaction.

Does that make any sense?




Freek Paans

unread,
Jul 9, 2015, 12:57:43 AM7/9/15
to ddd...@googlegroups.com
Didn't it mutate the customer by increasing the count? Also, how would customer be notified of order changes? If the order is fulfilled or cancelled you're gonna need to decrement the count.

--
You received this message because you are subscribed to the Google Groups "DDD/CQRS" group.
To unsubscribe from this group and stop receiving emails from it, send an email to dddcqrs+u...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Alexandre Potvin Latreille

unread,
Jul 9, 2015, 1:33:49 AM7/9/15
to ddd...@googlegroups.com
Well, in this case I guess it would... I was more focused on the general applicability of the approach than the real business example. If it does increment the count then the problem is solved for incrementing the optimistic concurrency version. What about other cases?

Also, decrements could be made eventually consistent I suppose. That means the rule could technically fail even thought there's 5 or less outstanding invoices (an outstanding one was fulfilled or canceled at the same time), but the invariant would still be protected.

@yreynhout

unread,
Jul 27, 2015, 2:36:30 PM7/27/15
to DDD/CQRS, alexandre.pot...@gmail.com
Guess what, I got the boundaries wrong :-) Artificial invariants, gotta love 'em.

Manuel Rascioni

unread,
Jul 28, 2015, 7:32:49 AM7/28/15
to DDD/CQRS, alexandre.pot...@gmail.com
I use to look an aggregate as a container of events, and, inside it you can enforce a rule in a consistent manner only if all the data (events) needed to enforce it are present in the aggregate boundary. The aggregate boundaries aren't something predefined, you have to build them in the more comfortable way.
So you are free to change who is the responsible of an event* from an aggregate to another in order to enforce a rule (eg. placeOrder from Order to Customer aggregate), but sometimes that event also contains data needed to enforce another rule in your domain, that will unbecome consistent moving that event away from the original aggregate.

In your case having the placeOrder in an aggregate it's only a part of the  data (event) needed to enforce at all your rule, as pointed out from freek, so the way to solve it is put all the operation to enforce the rule inside the aggregate, so you will need also the OrderFulfilled and OrderCancelled event in your aggregate therefore their command methods: fulfillOrder and cancelOrder. I think that removing them from the Order aggregate make the validation of the remains commands of the Order eventual consistent (what if you try to make some modify to a fulfilled order?), so you can think to put the entire order inside the customer aggregate.
Doing this cause other problems, because in this way if all the Orders are in the same aggregate they can't be modified concurrently, is this acceptable? If not you have to break the events and choose which are the less problematic rules and enforce them cross aggregate, using all the techniques to enforce a rule in an eventual consistency fashion (more expensive then a "normal" way inside the aggregate), so the question is "what's the real business impact if that rule gets violated"? :)

Hope it helps,

Cheers


* Who is the first that know that it happened, so that can be fully consistent with that state change

Jo Geraerts

unread,
Jul 30, 2015, 5:18:27 AM7/30/15
to DDD/CQRS, alexandre.pot...@gmail.com, yves.r...@gmail.com


Op maandag 27 juli 2015 20:36:30 UTC+2 schreef @yreynhout:
Guess what, I got the boundaries wrong :-) Artificial invariants, gotta love 'em.

What should have been the boundaries in this case then? 

@yreynhout

unread,
Jul 30, 2015, 8:58:08 AM7/30/15
to DDD/CQRS, alexandre.pot...@gmail.com, j...@umask.net
If you want strong consistency, I would make the OutstandingOrdersForCustomer its own thing. Serializing everything through that we'd never be able to go above 5. But then again, the example remains contrived.

Jo Geraerts

unread,
Aug 1, 2015, 2:23:01 AM8/1/15
to DDD/CQRS, alexandre.pot...@gmail.com, j...@umask.net


Op donderdag 30 juli 2015 14:58:08 UTC+2 schreef @yreynhout:
If you want strong consistency, I would make the OutstandingOrdersForCustomer its own thing. Serializing everything through that we'd never be able to go above 5. But then again, the example remains contrived.


Clear, thanks
Reply all
Reply to author
Forward
0 new messages