I realize that DDD advocates eventual consistency, thus allowing for a certain period of time in which the system might be inconsistent. Embracing eventual consistency, we can therefore model our aggregates in such a way that only 1 is updated per transaction.
However, my question is, what if the relationship between multiple aggregates is such that eventual consistency is either not acceptable, or compensating actions would be too complex to implement? Does that mean that DDD is not the right choice in that scenario, or does it mean that we simply cannot use the 1 aggregate per transaction rule? Or does this maybe mean that the multiple aggregates need to be merged into 1 greater aggregate?
To give a more concrete example, consider the following: An auction system, composed of Items, Auctions, Bids, Users and UserBalance. Users can place a bid on an auction if the following conditions are met:
They outbid the current highest bid, if any
Their balance has enough funds to place the bid
When a bid is outbid, the user that placed the bid should receive the funds used in placing that bid. Users can increase their UserBalance by other actions, such as purchasing, rewards, etc.
I envisioned the following aggregates: Auction composed of Bids, User and UserBalance.
Imagine Auction has a method called placeBid
that handles the bid placement logic.
In order to preserve the 1 aggregate per transaction rule, Auction should accept a userBalance object, and check if the bid placement is valid. If yes, it then proceeds to create a bid, commit the transaction and publish a domain event. However, it can happen that a UserBalance no longer has sufficient funds to pay for a bid by the time the BidPlacedHandler is triggered. This means that other users would see the newly placed bid before the balance is updated. And this also means that once the UserBalance update fails, the current highest bid will need to be deleted, and the previous bid reinstated as the highest bid, unless of course another bid was placed in the meantime.
While handling these compensatory cases might be slightly unreadable, or difficult to grasp, my bigger concern is the fact that users might be able to see an invalid bid as the highest bid for an auction. Is there any guidelines as to how this problem would be approached, in this particular case, or in general?
I envisioned the following aggregates: Auction composed of Bids, User and UserBalance.
-- None of those things are aggregates, except possibly Auctions. A User is an entity. A User Balance is a property of an account.Any rule that spans AGGREGATES will not be expected to be up-to-date at all times. Through event processing, batch processing, or other update mechanisms, other dependencies can be resolved within some specific time. [Evans, p. 128]
See also this post