Search code examples
architecturedomain-driven-designaggregateroot

DDD: aggregate root needs information from another aggregate root


I'm thinking about the design of a fairly simple problem, but it I would like to hear other solutions to handle it properly.

At his moment I have 2 aggregate roots:

  1. User: holds information about a user like display name, linked accounts, and a profile, which can be a patient profile or a care provider profile. Such patient profile holds information like birth date and gender. I have a UserRepository that takes care of getting and saving users.
  2. Screening: holds information about health, like length and weight measurements, and all kind of calculated information such as 'short term evolution", based on those lengths and weights. I have a ScreeningRepository that takes care of getting and saving users.

So there is a Calculate() method in Screening, and the goal is that when a weight and/or length is added to the screening, the health properties like short term evolution are recalculated immediately, so that the screening is always in a consistent and correct state.

The problem is dat this calculation also needs gender and birth date of the user, which are stored in the patient profile.

So basically, the aggregate root screening has a dependency on the aggregate root user. So I'm wondering how to go about it...

  1. According to DDD, an aggregate root should not reference another aggregate root. And also, if I would make user a property of screening, the ScreeningRepository would also be responsible to dematerialize user as well, which is of course not his task.

  2. If screening has no reference to user, then Calculate() does not have all needed information. So this means I should probably move it to a domain service, which get user and screening as input, and do the calculation. Fine. But then, how can I make sure that when a measurement is added to the screening, the Calculate is triggered?

  3. The other option I was thinking about was to not make screening an aggregate root, and make it just an aggregate with parent user. This also allows me to better validate the screening, because I can access the User as well. It would solve all issues about the calculation, because I would have all information at hand, but this way, the UserRepository would be responsible to also handle screening, and my aggregate root becomes responsible of users and screenings.

At this point the last option seems to be the only one that makes it easy to fix the problem, but I would love to hear any thoughts on things since I might be missing obvious concepts.


Solution

  • There is no magic.

    If the domain logic for Screening requires gender and birth date, then you are going to need to get copies of those values into the aggregate. That in turn means that either (a) you pass the values in, or (b) you pass in a capability that supports querying the values.

    It's often the case that an aggregate will cache a local copy of data that "belongs" to another aggregate. In which case you may need to work through what happens if that cached data needs to be invalidated (ex: what happens if we later discover a data entry error on birthdate?)