Life inside an Aggregate Root, part 2

This is the second half of a two-part article. Read the first half here: Life inside an Aggregate Root, part 1.

In part one I talked about how entities have reference their parent aggregate root. Today I will talk about how new entities are added to the aggregate. Let’s have a look at the spec again for my example training system:

A Training Programme is comprised of Skills, arranged in Skill Groups. Skill Groups can contain Sub Groups with as many levels deep as you like.

Here’s our original code for adding Skill Groups to a Training Programme:

SkillGroup subGroup = new SkillGroup("First Aid", programme);
programme.Add(subGroup);

// add skills to subgroup etc

There are three things wrong here.

  1. We’re breaking aggregate root boundaries. Skill Groups can only be constructed against one Training Programme, but can be added to as many Training Programmes as you like via the Add(SkillGroup) method.
  2. Anemic domain model: Training Programmes and Skill Groups are just dumb containers here. The actual logic is being performed in the application services layer.
  3. The application services layer knows too much about Skill Groups (how to construct them).

Rule #5: New objects inside the aggregate are created by existing objects

These sorts of problems can be avoided if we move the responsibility for creating Skill Groups to the Training Programme itself. The new keyword is a bit of a smell here — as Udi Dahan recently stated in a blog post, customers don’t just appear out of thin air. Let’s flip it around:

SkillGroup subGroup = trainingProgramme.AddSubGroup("First Aid");

// add skills to subgroup etc

Now the Training Programme knows about creating and adding Skill Groups, and can hide away any factory construction or injection required to construct them. It also eliminates the situation where you could add the same Skill Group to multiple programmes:

SkillGroup subGroup = new SkillGroup("First Aid", programmeA);
programmeA.Add(subGroup);
programmeB.Add(subGroup); // what happens now?

Much better!

7 thoughts on “Life inside an Aggregate Root, part 2

  1. Hi, thanks for the efforts for writing these articles! They help alot.

    Anways, I ve got some comments (even though this post is kinda old):

    SkillGroup subGroup = new SkillGroup(“First Aid”, programmeA);
    programmeA.Add(subGroup);
    programmeB.Add(subGroup); // what happens now?

    I case of “what happens now?”… Inside the programme.Add-Method, couldn”t there just be the appropriate business logic? Like:
    public void Add(SkillGroup group)
    {
    if(group.TrainingProgramme != null)
    throw new DomainExpception(…);
    }

    From my point of view, one good aspect of OOD is to pass objects around. This allows, in case of refactoring, to reduce the number of contracts to be changed.

    In your example, if SkillGroup would have more than one property, like 10 or 20, all these need to be passed via the Add-Method, right? So if SkillGroup gets a new property later on, I must change the SkillGroup constructor, probably a factory, and the Add-method to support the new property. Do you have any experience regarding refactoring in this case?

    Thanks in advance

    Chris

  2. @ Chris: you could pass in a Parameter Object. However it happens, the point was that the aggregate root is responsible for creating child objects (they don’t just appear out of thin air and get passed to it).

  3. How would you then add Skills?

    trainingProgramme.addSkill() ?

    OR

    trainingProgramme.getTopicById(topicId).addSkill() ?

  4. I would also be interested in more in this series, the two parts where written in an easy to read manner which didn’t take multiple attempts to sink in. Do you have any reading material recommendations?

  5. I really enjoyed this series and it helped me realize few important ddd concepts on the way. I am currently working on a bounded context that has 3 things–

    Client – has atleast one team (default team),
    Teams – belongs to client,
    Users – can be associated with multiple teams (but atleast one)

    I am trying to model this domain and here is where I am:
    Each one of them Client, Team and User are Aggregate roots
    Team has a reference to Client (Client property)
    User has reference to Team (Team property)

    That way I implement association (as mentioned above). But I am unable to understand, if this is the right way or would it be more appropriate to have List of teams in Client and List of Users in team. But then we will have to load each aggregate root fully each time we need to do anything with it.
    Any direction in this stuff is highly appreciated

    Thanks

Comments are closed.