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!

October 14th, 2009 | 1 Comment

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

One of the most important concepts in Domain Driven Design is the Aggregate Root — a consistency boundary around a group of related objects that move together. To keep things as simple as possible, we apply the following rules to them:

  1. Entities can only hold references to aggregate roots, not entities or value objects within
  2. Access to any entity or value object is only allowed via the root
  3. The entire aggregate is locked, versioned and persisted together

It’s not too hard to implement these restrictions when you’re using a good object-relational mapper. But there are a couple of other rules that are worth mentioning because they’re easy to overlook.

Real-life example: training programme

Here’s a snippet from an app I am building at work (altered slightly to protect the innocent). Domain concepts are in bold:

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. Skills can be used for multiple Training Programmes, but you can’t have the same Skill twice under the same Training Programme. When a Skill is removed from a Training Programme, Individuals should no longer have to practice it.

Here’s what it looks like, with our two aggregate roots, Training Programme and Skill:

Training Programme, Skill Groups and Skills

Pretty simple right? Let’s see how we can implement the two behaviours from the snippet using aggregate roots.

Rule #4: All objects have a reference back to the aggregate root

Let’s look at the first behaviour from the spec:

…you can’t have the same Skill twice under the same Training Programme.

Our first skill group implementation looked this like:

public class TrainingProgramme
{
    public IEnumerable<SkillGroup> SkillGroups { get; }

    ...
}

public class SkillGroup
{
    public SkillGroup(string name) { ... }

    public void Add(Skill skill)
    {
        // Error if the Skill is already added to this Skill Group.
        if (Contains(skill))
            throw new DomainException("Skill already added");

        skills.Add(skill);
    }

    public bool Contains(Skill skill)
    {
        return skills.Contains(skill);
    }

    ...

    private IList<Skill> skills;
}

What’s the problem here? Have a look at the SkillGroup’s Add() method. If you try to have the same Skill twice under a Skill Group, it will throw an exception. But the spec says you can’t have the same Skill twice anywhere in the same Training Programme.

The solution is to have a reference back from the Skill Group to it’s parent Training Programme, so you can check the whole aggregate instead of just the current entity.

public class TrainingProgramme
{
    public IEnumerable<SkillGroup> SkillGroups { get; }

    // Recursively search through all Skill Groups for this Skill.
    public bool Contains(Skill skill) { ... }

    ...
}

public class SkillGroup
{
    public SkillGroup(string name, TrainingProgramme programme)
    {
        ...
    }

    public void Add(Skill skill)
    {
        // Error if the Skill is already added under this Training Programme.
        if (programme.Contains(skill))
            throw new DomainException("Skill already added");

        skills.Add(skill);
    }

    ...

    private TrainingProgramme programme;
    private IList<Skill> skills;
}

Introducing circular coupling like this feels wrong at first, but is totally acceptable in DDD because the AR restrictions make it work. Entities can be coupled tightly to aggregate roots because nothing else is allowed to use them!

Continue reading: Life inside an Aggregate Root, part 2

October 13th, 2009 | 5 Comments

Deciding whether a service belongs in the domain or service layer can be a very tough question.

I think it’s important to remember that, just because a class:

  • Deals exclusively with objects in the domain model
  • Is called in turn by other application services
  • Has no dependencies on other non-domain services

…does not make it a domain service.

Try not thinking of it as the domain layer, but as the domain model. The domain model is a very strict abstraction of the business; domain layer is just a tier in your app where the model resides. It’s a small change of words but a big difference in perspective.

Is your service actually part of the domain model, or just manipulating it?

September 6th, 2009 | No Comments Yet

We’ve been using Udi Dahan’s excellent Domain Events pattern in a project at work. It’s best to keep them as coarse-grained as possible, but we have already identified a dozen or so events that need to be raised by the domain and processed by our services layer.

Naturally, however, I am forgetting to register some of the event handlers in our IoC container. So, as before with our domain services, I decided to write some integration tests to check everything is set up properly. This is very simple to achieve using NUnit’s trusty parameterized tests, ServiceLocator and a sprinkling of generics:

IEnumerable<Type> GetDomainEvents()
{
    var domain = Assembly.GetAssembly(typeof(Employee));

    return domain.GetTypes()
        .Where(typeof(IDomainEvent).IsAssignableFrom)
        .Where(t => !t.Equals(typeof(IDomainEvent)));
}

[Test]
public void Should_be_able_to_resolve_handlers_for_domain_event(
    [ValueSource("GetDomainEvents")]Type @event)
{
    var handler = typeof (IHandles<>).MakeGenericType(@event);

    ServiceLocator.Current.GetAllInstances(handler).Should().Not.Be.Empty();
}

This reveals a nice todo list of all the handlers we haven’t implemented yet. And the ones I forgot to register!

NUnit Should_be_able_to_resolve_handlers_for_domain_event

August 31st, 2009 | No Comments Yet