The journeylism of @yreynhout

On CQRS, DDD(D), ES, …

EventBuilders

Some people have asked me to clarify what I’ve been saying over on twitter about using event builders. This post is an attempt at showing how I’ve been using them.

This is just one way of creating fluent builders for your events. If you search the net, you’ll find many more (start here).

Let’s dive in. I’m assuming there’s an event in place (called BeganTemplateRollout in this example) along with some minor infrastructure that tells me the class I’m dealing with is indeed an event.

//Could be your own, the one from your favourite messaging framework, 
//or none at all

public interface IMessage {} 
public interface IEvent : IMessage {}

public class BeganTemplateRolloutEvent : IEvent {
  public readonly Guid Id;
  public readonly long Version;
  public readonly Events.RolloutPeriod PeriodToRollout;

  public BeganTemplateRolloutEvent(Guid id, long version, Events.RolloutPeriod periodToRollout) {
    Id = id; Version = version; PeriodToRollout = periodToRollout;
  }
}

public class RolloutPeriod  { 
  //i.e. Events.RolloutPeriod, 
  //the event representation of a value object

  public readonly DateTime StartDate;
  public readonly DateTime EndDate;

  public RolloutPeriod(DateTime startDate, DateTime endDate) {
    StartDate = startDate; EndDate = endDate;
  }
}

So, given that event, what does its builder look like?

public interface IEventBuilder<in TEvent> 
  where TEvent : IEvent
{
  TEvent Build(Guid id, long version); 
}

public class BeganTemplateRolloutEventBuilder : IEventBuilder<BeganTemplateRolloutEvent> {
  Events.RolloutPeriod _periodToRollout;

  public BeganTemplateRolloutEventBuilder ForPeriod(RolloutPeriodBuilder builder) { 
    //Notice the builder? Makes it more fluent, that's all.
    _periodToRollout= builder.Build();
    return this;
  }

  public BeganTemplateRolloutEvent Build(Guid id, long version) {
    return new BeganTemplateRolloutEvent(id, version, _periodToRollout);
  }
}

public class RolloutPeriodBuilder {
  DateTime _startsOn;
  DateTime _endsOn;

  public RolloutPeriodBuilder StartsOn(DateTime value) { _startsOn = value; }
  public RolloutPeriodBuilder EndsOn(DateTime value) { _endsOn = value; }

  public Events.RolloutPeriod Build() { return new Events.RolloutPeriod(_startsOn, _endsOn); }
}

public abstract class AggregateRootEntity {
  Guid _id;
  long _version;

  protected void ApplyEvent(IEventBuilder<IEvent> builder) {
    ApplyEvent(builder.Build(_id, ++_version));
  }

  private void ApplyEvent(IEvent @event) {
    /* You know what goes here ... */
  }
}

Why the explicit event builder interface? Basically this is a contract between the derived aggregate root entities and an AggregateRootEntity base class, where the latter provides event sourcing capabilities as found in Greg Young’s m-r. It allows the derived classes to concern themselves with the purely domain specific part of an event, while the base class can provide event identity (i.e. the aggregate identifier) and versioning (i.e. incrementing a version number upon each change or calculation a version hash or …). The base class makes no assumption about how the information is stored inside the event, by virtue of that Build method.

Having event builders is great, but where can event builders be used in your codebase? The short answer is: pretty much everywhere you’d be using an event. Be it in a command handler test to assert the proper event was produced, inside an event handler/denormalizer test to properly compose an event to be handled, or inside an aggregate to build up events in a readable manner before turning them over to the ApplyEvent(…) method. Below is an example of its usage inside an aggregate.

public class Template : AggregateRootEntity {
  public void BeginRollout(Domain.RolloutPeriod periodToRollout) {
    Guard.Against(
      IsPeriodRolledOut(periodToRollout), 
      ErrorCode.PeriodAlreadyRolledOut);

    ApplyEvent(
      Build.BeganTemplateRollout.
        ForPeriod(periodToRollout) //Double dispatch
    );
  }

  public bool IsPeriodRolledOut(Domain.RolloutPeriod periodToRollout) {
    /* Do what is necessary */
    return false;
  }
  
  void ApplyEvent(BeganTemplateRolloutEvent @event) { 
    // change internal state here
    // if you care for it
  }
}

public class RolloutPeriod { 
  //i.e. Domain.RolloutPeriod

  private DateTime _startDate;
  private DateTime _endDate;

  internal void BuildEvent(BeganTemplateRolloutEventBuilder builder) {
    builder.ForPeriod(
      Build.RolloutPeriod.
        StartsOn(_startDate).
        EndsOn(_endDate));
  }
}

internal static class Build {
  public static BeganTemplateRolloutEventBuilder BeganTemplateRollout { 
    get { return new BeganTemplateRolloutEventBuilder(); } 
  }
  public static RolloutPeriodBuilder RolloutPeriod { 
    get { return new RolloutPeriodBuilder(); } 
  }
}

public static class EventBuilderExtensions {
  public static BeganTemplateRolloutEventBuilder ForPeriod(
    this BeganTemplateRolloutEventBuilder builder, 
    Domain.RolloutPeriod value) 
  {
    value.BuildEvent(builder); //Double dispatch magic
    return builder;
  }
}
Advertisements

4 responses to “EventBuilders

  1. Thorsten Krüger July 29, 2011 at 07:45

    Hello,

    thanks for the elaboration. With each of these examples it gets easier to understand the style you use with your domain and infrastructure code. I like it very much, tough I still have to get used to it. I can see that each action on a domain object takes some specific steps which are easy enough to follow once you get the overall picture. Still wondering how one manages to keep track of the connections between the different commands and events (and event-induced commands and their events and so on) without having a good map. But I guess that’s the price you get for all the goodies of a loose connection between these and being able to store events rather than current state. Wouldn’t be less complex without ddd anyway.

    This particular example seems to make good way toward even further clarification of the distinction between infrastructure code in the AggregateBase class and the domain logic in the domain objects themselves. Was that what drove you to it, or were there other reasons, too? Looking forward to try this one of these days, however, I am still a few steps behind.

    On a sidenote – I did convert the example to Java, because I’m still not used to the C# specialities. While doing that, I noticed that I had to give the BeganTemplateRolloutEventBuilder an additional ForPeriod(Domain.RolloutPeriod). I suspect Line 49 in the last Code example somehow attached the ForPeriod Method there to the existing class as an extension or whatnot?

    Thanks again for typing this up.

    Regards,
    Thorsten

  2. yreynhout July 29, 2011 at 10:27

    1. I’ll be doing a post on how to keep an overview of all those connections.
    2. What drove me to it was the exploration of various ways of coupling/decoupling events from the source that produces them. Basically you have a couple of choices:
    a. Use template method to get to the Id as demonstrated in Greg Young’s m-r sample. This puts the burden on the derived class with regard to tracking/deriving the identifier. As an aside, the version is a mutable field on the Event class.
    b. Use mutable fields/properties on the event class/interface as demonstrated in Mark Nijhof’s Fohjin sample
    c. Build the entire event in the derived classes and query the base class for aggregate identifier and the next version number, thus keeping the event immutable in code.
    d. Use builders, sharing responsibility between derived and base class, allowing each to extend the event with the state they know of, thus keeping the event immutable in code.
    e. I’m sure there are other ways.
    3. ForPeriod is indeed a c# extension method.

  3. Pingback: Value objects in an event sourced domain model « The journeylism of @yreynhout

  4. Pingback: EventBuilders – Revisited | The journeylism of @yreynhout

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: