Reputation: 795
Lets say we have an Account aggregate for a banking service. Someone wants to transfer money from their Account to another person's Account. There are a number of rules: payer needs to have enough money in their Account, and the payee's Account must be active. If these rules pass then the balance on both Accounts are updated. In a traditional system this can easily be done in a single acid db transaction.
In DDD this would not be allowed, as we can't update two aggregate instances in a single transaction? Firstly, why? Secondly, does that mean using eventual consistency to handle the two Accounts? If so, I can see how that can be done, but it adds a lot of complexity.
Upvotes: 0
Views: 797
Reputation: 57387
In DDD this would not be allowed
Not really true - there's a lot going on here.
What Evans (2003), and also Vaughn 2013, wrote is that transaction management is not a domain model concern, but rather that transaction control belongs in the application code.
There is, however, a real concern with changing multiple aggregates at the same time: to do so assumes that you can acquire locks on those entities at the same time and also commit all of those changes together.
That's relatively straightforward when all of the aggregates that you are changing are stored in a single relational database; but it becomes very difficult when the aggregates are stored in different places.
If you design your system such that it assumes that all aggregates are stored together, then you greatly restrict your scaling options.
Be careful not to overuse the ability to commit modifications to multiple Aggregates in a single transaction just because it works in a unit test environment -- Vaughn 2013.
does that mean using eventual consistency to handle the two Accounts
That, or changing how you model your aggregates. Sometimes both.
For instance, it's somewhat common to have aggregates that handle (short lived) processes, which are different from the long lived aggregates.
When I look at my credit card statement, a charge will normally fall in one of three states: it's not yet posted to my statement (not visible), or it's pending (visible), or it is actually posted as a charge (visible). Clearly, there is stuff going on "somewhere else", and that information is eventually copied to my statement where I can see it.
I can see how that can be done, but it adds a lot of complexity.
Yup. If it wasn't complicated/complex, we wouldn't be creating our own model; we'd instead be buying some general purpose solution off the self.
Greg Young talked about this in a 2011 presentation: domain driven design makes sense in places where we can derive a competitive advantage from the work we are doing. In other words, we are using it in places where giving the business control over that complexity improves the bottom line.
Making sure you are working on the correct side of the build versus buy line is an important step. Don't skip it.
Upvotes: 2