Use case : Internet shop.
The customers creates an order containing: containing: BookA, BookB, BookC. and sends this order command to server, the moment the command begins to execute someone else bought BookC, and we are out of stock.
How we are supposed to validate this command on server, if we shouldn’t query reporting database in commands handlers? Udi has been asked similar questions at DDD Exchange 2010, by Eric and Greg. But he didn’t provided an answer.
I tried to respond on your blog but didnt have my credentials for wordpress. I wrote more than I thought so I will respond on my blog as well.
The example that you give of ordering is actually a quintessential one. You mention that a web system may want to prevent two people from ordering the last of the same product at the exact same moment (Inventory should be consistent). My guess is you have not worked at a large online retailer before.
So generally you want to allow these orders to come in. There are a few reasons for this. The first it that inventory is by definition not consistent. There are domain terminologies to describe its eventually consistent nature. Unfortunately when people break, misplace, or steal something they have a tendency of not updating the computer system as to the items new location. As such you often don’t have in physical inventory what the system says you do (this is partly why audits exist).
There is also further questions from a business point of view about things like lead times of getting the item or even buying the item from a competitor to keep the customer happy. Loads of examples of this happen daily in these situations (ever booked a hotel and been upgraded to another hotel?). They are perfectly willing to oversell in many scenarios. These types of substitutions are quite common…
However let’s assume for a moment that there is a valid use case here (I won’t just brush you off by looking at the use-case). With say a CQRS/ES based system you still have some amount of consistency within aggregate boundaries. For invariants that exist within boundaries you have everything fully consistent. For aggregates that are outside of the boundary there are a load of strategies.
The strategies mostly look at the ability to detect that this has happened and to minimize the chance of it happening. If my warehouse sells 1,000,000 items and 1 goes oversold we can likely deem that as a “nice problem to have”. It is far better to handle such a problem from a business perspective than to make large architectural constraints upon our system. The detection of the situation happening previously is key though in order to be able to do this. If you can’t detect a failure its hard to talk about minimizing the costs of a failure.
One way to do this is to say keep the last n seconds worth of transactions in memory (assuming single write server). You could then look through these transactions on top of what the read model had. This obviously has a downside to it in that it doesnt scale to many servers… Your queue (if you use one) may also support peeking inside of it at what messages have not been processed. Neither of these is perfect but can help in many scenarios.
The last strategy is to actually make everything full consistent. You can certainly bring in a lock (either a distributed lock, or use a database, or whatever). This has very well established trade offs but can be done. I would tend to error towards not doing this and mitigating risk through other means but there can certainly exist situations where the cost of a failure is so high that 100% prevention is required.