Skip to content

Transitioning to Event Sourcing, part 4: track state changes

by Julien on August 3rd, 2010

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

Overview

This step will not bring any technical benefit. The goal is to prepare the next step. We now want that our aggregates track their changes:

You probably already guessed that the changes of an aggregate will be stored in the form of events that happened to this aggregate. Each aggregate is responsible for tracking the changes that happened in them from the time they have been loaded from the persistence storage.

Benefits

Communication

Like for the commands, events describing what changed in an aggregate should be part of the ubiquitous language. This is a tool that might help you and the domain expert formalize what really happen in the domain when a given command is issued.

Cleaning

As you will see below in the implementation section, explicitly defining events and enforcing them will force you to respect one overlooked property of aggregates: their consistency boundaries.

Implementation

We basically add a list of uncommitted changes to the aggregate root:

public interface IAggregateRoot
{
    Guid Id { get; }
    IEnumerable<IEvent> UncommitedEvents { get; }
}

We also have still another project containing the events. Obviously, this project must not have a dependency on the domain model:

As we must enforce that the events are really carrying what has happened in the domain, we are delegating the state changes to a method taking the event as a parameter. For example:

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

    // State changes
    ApplyEvent(new StudentRegisteredToClassEvent(Id, @class.Id, @class.credits));
}

private void Apply(StudentRegisteredToClassEvent evt)
{
    registrationSequence = registrationSequence.Next();
    registrations.Add(new Registration(this, registrationSequence.ToId(), evt.ClassId, evt.Credits));
}

Notice that I had to fix an issue with the consistency boundary. Let’s look at the previous step implementation of the Registration entity (constructor omitted for clarity):

public class Registration : Entity<Student>
{
    internal Class _class;
}

A Registration is part of the Student aggregate. It should not have referenced a Class, which is an other aggregate.
Instead, we should have put in the Registration all what is needed to enforce it’s aggregate behavior:

public class Registration : Entity<Student>
{
    private Guid classId;
    private int classCredits;
}

This will allow us to have a StudentRegisteredClassEvent. Since events don’t have a dependency on the domain model, this event could not have carried the Class object that would have been necessary with the first version of the entity. With the second version though, the event becomes simple (constructor omitted for clarity):

public class StudentRegisteredToClassEvent : IEvent
{
    public readonly Guid StudentId;
    public readonly Guid ClassId;
    public readonly int Credits;

}

AggregateRoot.ApplyEvent()

The other important thing you might have notice in the aggregate is that the public method don’t call directly the Apply(SomeEvent evt) methods. Instead, they are calling void ApplyEvent<T>(T evt). This method located in the root will call the right Apply(SomeEvent evt) method, but will also add the event to the uncommitted event list.

On a side note, void ApplyEvent<T>(T evt) don’t use reflection to call Apply(SomeEvent evt). It is instead using the nice Expression Trees API to build the necessary delegates at startup.

Credits

  • For the orignal ApplyEvent() implementation: Greg Young
  • For the formatting of domain terms: Richard Dingwall

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 new “DDDPart4″ database in SQLExpress.

Transitioning to Event Sourcing posts:

From → Event Sourcing

10 Comments
  1. Remi Despres-Smyth permalink

    I’ve really been enjoying this series. It’s exactly the sort of thing I’ve been looking for: contrasting how I more-or-less currently build applications with event sourcing, to allow me to gain a concrete end-to-end understanding of the architecture and how it works.

    I’m really hoping you’re just gone on vacation and have not dropped the series entirely?

    Best regards,
    Remi.

  2. Julien permalink

    Yep, I am just back from my vacations… I will continue the serie very soon.

  3. Lek permalink

    Bonjour,
    je viens de dévorer les 4 posts que tu as écris sur le sujet et tenais absolument à te remercier pour ce travail remarquable. Vraiment merci de reprendre et clarifier l’event sourcing (et en français!!).
    J’espère que les futures articles arriverons bientôt.

    Encore merci,
    Lek.

Trackbacks & Pingbacks

  1. Transitioning to Event Sourcing, part 2: go CQRS with DTOs | Julien's blog
  2. Transitioning to Event Sourcing, part 3: commands | Julien's blog
  3. Transitioning your DDD “light” application to CQRS and Event Sourcing | Julien's blog
  4. Transitioning to Event Sourcing, part 1: the DDD “light” application | Julien's blog
  5. Transitioning to Event Sourcing, part 5: use events for updating your domain database | Julien's blog
  6. Transitioning to Event Sourcing, part 6: store events | Julien's blog
  7. Transitioning to Event Sourcing, part 7: build a view model | Julien's blog

Leave a Reply

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

Subscribe to this comment feed via RSS