2

How should I perform updates on nested children of an Aggregate Root?

Should I find the child object by traversal of associations and perform the update on it directly, or should I add a method on the Aggregate Root that takes care of it?

An example

I'm modelling an old project at our company which is a system we use to perform searches of customers against a suspicious person list:

The model

  • We run a Batch Search every night
  • The Batch Search contains a list of Searches for it.
  • Each Search contains a list of Matches and is associated with one Customer

The process

  • We check each Match and mark it as confirmed if it was a confirmed match.
  • We also tick a checkbox for each Search if all it's Matches where inspected

DDD model in diagrammatic form of the above description

The caveat

A Search can also run standalone, as in - not being a part of a Batch Search. In that case the Search naturally becomes the Aggregate Root.

Question

How should I be performing the update operations on the child items? The blue book states that all updates to children must go through the Aggregate Root.

There are 2 ways to perform this update:

Option 1

Traverse the graph and find the child object and perform the operation directly on it.

batchSearch = batchSearchRepo.find(1);
search = batchSearch.findSearch(5);
match = search.getMatch(3);
match.markConfirmed();
batchSearchRepo.save(batchSearch);

Option 2

Add a method on the Aggregate Root

batchSearch = batchSearchRepo.find(1);
search = batchSearch.markSearchMatchAsConfirmed(5, 3);
batchSearchRepo.save(batchSearch);

Which of the 2 update methods is more appropriate and why?

3

Aggregate roots exist to protect the data within them. If you tear the aggregate roots internal structures and do operations on the internals directly without incorporating the aggregate root, the aggregate root can no longer validate the operation is valid.

In DDD the second option is not only more appropriate, it is the only correct way to go (as stated in the quote you posted).


When you however encounter the nesting that you have, you could also ask yourself a question whether your design is 100% correct.

  1. Aren't perhaps some of the internals of BatchSearch aggregate roots on their own?
  2. Couldn't maybe Search exist outside of the boundary of BatchSearch?
  3. Does affecting a Search affect a BatchSearch?

If you answered yes to questions 1 and 2 and no to the third question, you have already eliminated one entire level on nesting and can now access a Search directly as a separate aggregate root. With this in mind, could you maybe to the same for a Match?

  • "Aggregate Roots exist to protect the data within them". Assuming that a Search is part of a Batch Search, every time a Search is marked as inspected I decrement a searches_pending_review_count counter on the Batch Search. Doesn't that make the Batch Search an Aggregate Root automatically? - As noted in the 'Caveat' section of my question though, a Search can exist standalone as well, in which case it becomes the Aggregate Root – Nik Kyriakides Jul 28 '17 at 12:48
  • @NicholasKyriakides If BatchSearch does provide the context for Searches to be made then having the BatchSearch is most likely necessary but operations have to flow through it. However, maybe even better idea would be to completely ditch the BatchSearch in favor of some process manager which would be working with events SearchPreparedForInspection and SearchInspectionCompleted. Creating a fold of the events would give you the searches which are yet to be inspected. I cannot tell you much more information without knowing a lot more about your domain. – Andy Jul 28 '17 at 12:58
  • That's OK, you've already answered a lot of my questions this far. Thanks. – Nik Kyriakides Jul 28 '17 at 13:00

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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