Skip to content

Transitioning to Event Sourcing, part 1: the DDD “light” application

by Julien on July 13th, 2010

Une version française de ce billet est disponible ici.

This post will present an example of a classic architecture trying to support DDD. You can download the fully working infrastructure described here, as well as a (very simple) application using it here. Feel free to use this code as you wish, including for commercial closed source application. But if you publish it, or part of it, please mention my name in the credits. Obviously, I would not recommend using this code, since the purpose of all these posts are to show you what I think is a better alternative.

This first post will probably be quite long, as I need to describe a complete application architecture. The next ones will be much shorter, since they will focus on replacing a small part of that architecture at a time.

The sample is using C#, with NHibernate as the ORM, Windsor Castle as the IoC Container, and ASP.Net MVC for the presentation layer.

I will assume you are already familiar with the concepts of Object Relational Mapping, Inversion of Control Container, and the Model View Controller pattern.

The (simplified) architecture looks like this:


Let’s get into the details.

1 – The query side

When you want to display information, you can query your entities. This is usually done through a repository. For example:

public interface IStudentRepository : IRepository<Student>
{
    IPaginable<Student> ByNameLike(string name);
}

The base interface looks like:

public interface IRepository<T> where T : IAggregateRoot
{
    T ById(Guid id);
    void Add(T toAdd);
    void Remove(T toRemove);
    IPaginable<T> All();
}

The idea is to put all your queries for a given entity in its repository. You are usually implementing the repository using an ORM like NHibernate or the ADO.Net Entity Framework.

The reason the queries are returning a IPaginable<T> is that you want to be able to sort and paginate, but you don’t want to return a IQueryable<T> which would allow queries to be done all over your code base. In my experience, the code is much more maintainable if all the queries are centralized in the repository. The interface for IPaginable<T> looks like this:

public interface IPaginable<T>
{
    int Count();
    T UniqueValue();
    IEnumerable<T> ToEnumerable();
    IEnumerable<T> ToEnumerable(int skip, int take);
    IEnumerable<T> ToEnumerable(int skip, int take, string sortColumn, SortDirection? sortDirection);
}

From there, it is easy to implement the MvcContrib‘s IPagination<T> interface so you can use the mvcContrib pager control. Your action methods becomes quite simple for displaying data. For example:

public ViewResult Index(int Page = 1, string Name = null)
{
    var model = new StudentSearchModel()
    {
        Name = Name,
        Students = studentRepository.ByNameLike(Name).AsPagination(Page)
    };

    return View(model);
}

public ViewResult Details(Guid studentId)
{
    var student = studentRepository.ById(studentId);

    return View(student);
}

And you are done for displaying your entity!

2 – The write side

Usually, application just don’t display stuff on the user’s screen. They do stuff. Let’s see how it works here.

The design rule of thumb is, for any action the user want to do, you should only call one method on one entity. If your interface supports batch actions, then the same method can be called on a list of entities.

That makes the write pretty simple. For example, if you want to register a student to a class:

public RedirectToRouteResult DoRegisterToClass(RegisterToClassModel  model)
{
    var student = studentRepository.ById(model.StudentId);
    var @class = classRepository.ById(model.ClassId);
    student.RegisterTo(@class);
    return RedirectToRoute(new
    {
        controller = "Student",
        action = "Index"
    });
}

What happen in the aggregate root student? Here it is:

public virtual void RegisterTo(Class @class)
{
    // Business rules
    @class.Validation().NotNull("class");
    if (registrations.Where(x => x.Class.Id == @class.Id).Count() > 0)
    {
        throw new InvalidOperationException("You can not register a student to a class he already registered");
    }
    if (passedClasses.Where(x => x == @class.Id).Count() > 0)
    {
        throw new InvalidOperationException("You can not register a student to a class he already passed");
    }

    // State changes
    registrationSequence = registrationSequence.Next();
    registrations.Add(new Registration(registrationSequence.ToId(), @class));
}

Some comments here. You can see that all the methods in the aggregate roots (including constructor) are divided in 2 sections:

  • Business rules are validating that the action can be performed. This part can throw exceptions.
  • State changes are actually performing the action. This part can not throw exceptions.

The idea is to not modify any entity before being reasonably certain the action will be performed with success. We will see in next posts that it also facilitate future refactorings.

You can notice that there is no code that is explicitly calling NHibernate for committing the changes to the database. This is because we are using a NHibernate session per request pattern. This is implemented in a IHttpModule:

void context_BeginRequest(object sender, EventArgs e)
{
    CurrentContainer.Container.Build<IPersistenceManager>().Open();
}

void context_EndRequest(object sender, EventArgs e)
{
    var pm = CurrentContainer.Container.Build<IPersistenceManager>();

    try
    {
        if (HttpContext.Current.Error == null) pm.Commit();
    }
    finally {pm.Close();}
}

The IPersistenceManager is a simple abstraction of NHibernate’s session and transaction, so you can use other persistence mechanisms.

And that is it for the write side!

3 – Aggregate roots and entities

There are subtelties in the way the aggregate roots and the other entities are implemented using NHibernate.

No setters!

Setters are an anti pattern in your domain. DDD is not about modeling data, or nouns. It is about modeling behaviors that are solving the domain problem, or verbs. So the public interface of your domain should solely consist in public methods on your aggregate roots. The idea is that each method represents a use case. If you feel the need to set a property value on an entity from your controller or application service, it is probably because you have not well identified your use cases for this aggregate. From a design perspective, it is also the only way to ensure your objects invariants. That way, your aggregates are always fully consistent. Consistent means aggregate roots are in a valid state at all time and are respecting all their invariants.

If DDD is about behavior, then getters also should be an anti pattern. And they are. But for now, we still need them for displaying them in the UI. We will see in the next post how to get rid of them.

Aggregate root id

Aggregate roots should have a universal identifier of some kind instead of , say, a integer. Since you don’t want any global lock, one of the best option is to use  a Guid. The reason is, you want your application to be ready for integration with other systems in your enterprise. So the identifier should be reasonably unique not only within your application, but also within all the other applications in your company. This will greatly simplify SOA style integration later on.

Entity id

The entities that are part of your aggregate also have an identity, but local to the aggregate. The reason is here again, you don’t want to have a global lock when selecting a new entity’s id. You could use a Guid here as well, but you may not want to carry its unnecessary storage and indexing price. A simple integer will be enough.

Generating ids

The other thing you should be cautious is to not let the database create the ids for you. This will lead to global locks in your database, and you want to avoid that for performance and scalability reasons.

The way you can do that is by using the technique described here.

So the aggregate roots can simply create a new id themselves:

public abstract class AggregateRoot : IAggregateRoot
{
    private DateTime? version = null;

    public AggregateRoot()
    {
        Id = Guid.NewGuid();
    }

    public virtual Guid Id {get; private set;}
}

For the entities, you need to manage the id yourself. So the base entity class looks like:

public abstract class Entity<T> where T : AggregateRoot
{
protected DateTime? version = null;

// NHibernate constructor.
protected Entity() { }

public Entity(T aggregateRoot, int id)
{
this.aggregateRoot = aggregateRoot.Validation().NotNull("aggregateRoot");
Id = id;
}

private T aggregateRoot;
public virtual int Id {get; private set;}

}

So the primary key in the database for this entity will be a composite of the aggregate root id and the entity “local” id. If you are wondering why there is an empty constructor, it is because NHibernate needs it for creating proxies.

When an aggregate root needs to create a new entity, it is responsible for creating the corresponding id. For example:

private IdSequence registrationSequence;

public virtual void RegisterTo(Class @class)
{
    // Business rules here

    // State changes
    registrationSequence = registrationSequence.Next();
    registrations.Add(new Registration(registrationSequence.ToId(),  @class));
}

The nice thing is you already have the ids, you don’t need to make a database call for that. The bad thing is concurrency issues. If 2 users are creating a new entity in the same aggregate, the second one will get a unique constraint violation. The vast majority of applications are not collaborative and can live with a low probability of that happening. The victim user will have to try again. You can also catch that type of exception, and update the identity in the entity, and automatically retry. Obviously, event sourcing will offer us a nicer approach to that problem.

That is it for the starting application. The next post will talk about getting a more efficient read side.

Running the sample

The sources for the entire serie is available on GitHub at http://github.com/jletroui/TransitioningToEventSourcing
. To run it, simply create a “DDDPart1″ new database in SQLExpress.

Credits

  • Original paginable and repository implementation: Benoit Goudreault-Emond
  • Entities ids: Greg Young

Transitioning to Event Sourcing posts:

From → Event Sourcing

Leave a Reply

Note: XHTML is allowed. Your email address will never be published.

Subscribe to this comment feed via RSS