1

I am currently analysing the project ddd-library which is really helping in learning designing a system based on DDD principles. However there is one thing I have a problem with.

In case of placing a book on hold, first the Patron Aggregate is updated (it holds now a book) and then the Book Aggregate is updated. Whether it is an atomic transaction or eventual consistent, in both cases it is kind of problematic.

Atomic Transaction: Obviously we shouldn't modify 2 Aggregates in one transaction so there is that, but I dont think it would come with any other problems here (Maybe one could live with breaking the 'one aggregate modification per transaction' rule?)

Eventual Consistent: When the Patron is updated first and now 'holds' the book but the book Aggregate is not updated yet to become a BookOnHold, there might be a race condition when someone else at the same time tries to put it on hold. That patron aggregate would be updated and maybe its event is propagated first to the Book Aggregate. In this case the system would be in an invalid state, because the first Patron has a book on hold but the actual Book Aggregate is being hold by the second Patron.

Question: How would you solve this? Is there a better way to model the Aggregates? Is a Process Manager or Saga an appropiate Solution here?

Suggestions (Saga/Process Manager): It would start when the patron aggregate was updated. When after some time the referenced Book isn't updated, it could revert the Patron modification and raise some domain events to handle the case. So that way the eventual consistency solution wouldn't run into the problem I stated right? Or am I overthinking here or missing something?

2 Answers 2

0

The premise ‘we shouldn't modify 2 Aggregates in one transaction’ is false. As this answer states it's a consideration rather than a rule. It could also be an indication that the aggregate boundaries are not modelled correctly.

A more important principle is that a command shouldn’t invoke methods on multiple aggregates.

However, if a single method is invoked and that method raises a domain event, methods on other aggregates could be invoked by in-memory event handlers.

All of these in-memory changes can be wrapped in a single transaction when persisting the data.

3
  • 1
    Then the aggregates would depend on each other. I dont think that is how aggregates should be designed.
    – securita
    Commented Mar 28 at 22:37
  • Hi, I wrote that question a long time ago. Forget about transactions in a distributed system. You want queues. This is the direction we went after I posted that question and it has served us magnificently. I have the gut feeling, the OP was in a similar state of shock as I was back then, learning that microservice architecture just don't like transactions. Commented Apr 29 at 19:27
  • @securita: That's not what a dependency is. The ability for me to e.g. mass-archive a bunch of data does not somehow invalidate the independent nature of the aggregates. The persistence mechanic is unrelated to my domain logic. You are correct that the domain logic shouldn't use checks where one aggregate's update hinges on whether another aggregate's update worked; but this does not apply to the persistence mechanism used to store said aggregates.
    – Flater
    Commented Apr 29 at 23:42
-1

Note: this answer focuses specifically on "designing a system based on DDD principles" as you pointed out that this is your goal. I'm sidestepping ancillary considerations that DDD itself does not focus on.

TL;DR
When dealing with things like DDD, it's very important to understand the cause-and-effect relationship of what drives your design, and you have to take great care to no end up making domain design decisions for reasons that are in fact unrelated to the domain. Your current concern about database transaction is one such example of an unrelated concern.


Be careful about the ambiguity of the word "transaction", and how you express your needs about how you expect your transactions to work.

Domain aggregates are indeed independent items whose logic does not depend on the logic (or outcome) of another aggregate. But this is a design consideration for your domain.

When you use "transaction" to refer to a single command requiring two subsequent changes to two different aggregates in your domain logic, you are correct that we should avoid these at all costs.

But that's not the same as what a "transaction" is to your persistence mechanism. While it still fits the general bill of an "all or nothing" bundle of operations, this is not a domain consideration; it's a technical implementation detail of your persistence mechanism. Very intentionally, the domain does not and should not care about how the persistence mechanism works.

Similarly, the domain does not and should not care about how the surrounding application itself works. It merely defines how an aggregate operates. The domain does not get a say in whether the application chooses to orchestrate several individual domain operations, for whatever reason it chooses to do so.

As far as DDD is concerned, the only thing that needs to be independent is the actual command executed on your aggregate. DDD does not prescribe whether an application is allowed to call several of these independent commands, nor whether the underlying persistence mechanism chooses (or is allowed to choose) to employ a methodology to not allow for partial persistence (i.e. by using a database transaction).

When dealing with things like DDD, it's very important to understand the cause-and-effect relationship of what drives your design, and you have to take great care to no end up making domain design decisions for reasons that are in fact unrelated to the domain. Your current concern about database transaction is one such example of an unrelated concern.

9
  • OP: Evans cooked up that rule because of database transaction issues. He does not directly say so but he has reviewed and was pushing this PDF that most people have read when asking questions like this. This comical "it isn't this" or "isn't that" is just the "experts" like this one who comically never actually understood jack but won't tell you so. If they did, you would get a 3 liner answer on **what is is not an essay on what it isn't. Spare yourself the pseudo-philosophical noise. Commented May 1 at 14:13
  • OP: Evans cooked up that modelling rule because he wanted to avoid scalability issues that come along with global database transactions. There isn't some "grand" understanding behind it. Go read my answer, apply where appropriate and go build something instead of getting snared into this vapid & comically pseudointellectual circle jerk. Commented May 1 at 14:41
  • @nicholaswmin: By all means, you are free to comment on my answer if you have meaningful feedback about this answer. But right now it's coming across as a willful "tit for tat" because you didn't like my comment to your answer; and this is after a mod has already had to intervene once here.
    – Flater
    Commented May 1 at 23:30
  • @nicholaswmin To the more on-topic point you're making, you're missing the core message in this answer. The question asked here is tightly coupling the domain logic and persistence mechanism to a point where the OP is starting to design the domain based on persistence-based considerations, which is decidedly not domain-driven design. I never claimed that you need persistence transactions nor did I claim that it's not an important part of the application to consider; but as far as the question goes, which is tagged for DDD design principles, persistence store mechanics don't factor into it.
    – Flater
    Commented May 1 at 23:36
  • ... OP is starting to design the domain based on persistence-based considerations... Evans has put that rule down for a technical consideration. He might have convinced you otherwise at the time because a book called "Avoid database locks" wouldn't sell as much but the matter of fact is that you got sold on a design rule which you didn't really understand and still have no explanation. Everytime someone tries to figure out WTF that means, you jump in with your usual philosophical ponderings and entirely skip the technicalities. Commented May 2 at 0:33

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.