2

I am confused on how to apply DDD principles for the design of domain entity clusters with Aggregate Root. According to my understanding, Aggregate Root enforces business validations and all entities within that aggregate should be accessed from its root. But this is leading to a huge aggregate of linked objects.

To give an example I have a domain with 3 entities: Contract, PurchaseOrder(PO) and Initative:

enter image description here

I consider Contract as Aggregate Root for my cluster. A User can add a Contract and then add a PO and add Iniatives for PO. But he/she can look up a PO by PO Number and add Iniatiative to it. So it feels odd that every time we add an initiative we have to load entire Contract (with all the dependencies) into memory and then add Initiative.

I could hydrate the PO domain entity from database and then add Initiative to it (and there by all the business logic is in the PO Domain entity), but isn't this going against the DDD principles of not accessing non-root entity of an aggregate cluster directly?

1 Answer 1

5

There are two different aspects in your question: where should the boundary be in your domain model? and how to implement your model?

The boundaries in the model

The definition of an aggregate is:

A cluster of associated objects that are treated as a unit for the purpose of data changes. External references are restricted to one member of the aggregate, designated as the root. A set of consistency rules applies within the aggregate’s boundaries.

Reading your question, it appears that:

  • a Purchase Order has a unique ID, and that identifies the object completely independently of the Contract. By the way, this is normal business practice: any PO must be easily retrieved in any situation, even without knowing the contract (e.g. warehouse workers receiving the shipping of an order do not care about the contract context).
  • Furthermore, you say that you could very well add an initiative to the PO directly. This suggest that the consistency of your model doesn't require the Contract to check the consistency.

These facts strongly suggest that PO and Initiative could be in an aggregate that doesn't include Contract. You need to confirm this deduction, by cross-check that the contract is not needed when you change the PO, add an initiative or change an initiative. Another useful question is what happens to the POs when the related Contract gets a status "cancelled" or is deleted.

The implementation

When you speak about hydrating the PO, etc... you are dsicussing about the implementation. This is NOT something to think about WHEN DESIGNING your domain model. There are plenty of patterns to implement an object oriented database application (e.g. identity maps, lazy loading, etc...). But first you need to think about the domain and understand it well.

For instance, if it appears that every change on a PO would require to cross check that some ceilings in the contract are not exceeded, and vice-versa, the change of some limits in the contract requires to check in real time that the new value is still above the total value of all the relevant orders, then a direct change to a PO would seem a little bit risky. It could then be a good idea to consider the aggregate root with the contract after all. You'll always find technical solutions to domain and business challenges. For example, under the mega aggregate assumption a query on PO number could very well return the corresponding aggregate. Up to you to channel the change to the PO through the contract to enforce consistency. You could also use the principle of lazy load to load an aggregate but hydrate only objects that are strictly needed.

Your Answer

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

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