First of all I want to thank David Rettenbacher and Nathan Gonzalez for their help in setting up the first tries of Event Upconverting, without them I would probably still be wasting my time tempting to do it…

Event Conversion is a necessity, because the requisites changes, always. NEventStore team knows it. For that reason has given us some feature to manage it.
Why is so important? An event is something happened in the past and the past is…past! True, but at this point I know that every time I get an aggregate from the repository, NEventStore replay all the committed events to re-build the last state of the aggregate. These committed events could be some months old, and during this period new product version (with upgraded events class/handlers) could be released. So, How to handle the original events after event evolutions or fixes?

Here it is where Event Upconverter comes to help!

Event Versioning Strategies

Every time we need to modify an event class, we should always consider to create a new version of the event, keeping the old one still live, in order to re-hydrate the aggregate from the repository stream. So, it’ important to define a versioning strategy for the events.

There are different solutions explained by Damian Hickey in this post. In the same post David Rettenbacher proposed a variant that I like, because it leaves the same event’s full name in the last version of the event itself and so, the code seems to be more readable and maintainable: using Attributes.

Attribute Versioning setup

The strategy needs:

  1. a VersionedEvent attribute to link the concrete event classes with an alias for the event name (usually the event class name itself) and to associate that concrete event implementation with a version number.
  2. a custom Serializer that serialize/deserialize the event instances using a custom serialization binder, implemented according to the attribute versioning strategy
  3. a NEventStore instrumentation in order to use this serialization strategy
  4. a NEventStore instrumentation in order to enable Event-Upconversion

Attribute Versioning usage

At this point to use this versioning strategy we need to:

  1. Rename the old version of Event Class (i.e. className_V0) and mark the class with the VersionedEvent attribute's info
  2. Create the new version of the Event Class (with the same original name) and mark the class with the VersionedEvent attribute using a major version number
  3. Create the Event Upconverter that implements the event conversion logic

that’s all.

Some Consideration

Replaying Events

Replay all the events from the beginning could be useful in different scenarios: create a new projection, rebuild an existent one (for example during a product upgrade) and before do it, it’s very important having the event upconversion strategy set up. The following one it’s a simple event rebuilder that re-publish all the events previously committed.

public class EventsRebuilder : IEventsRebuilder
{
	private readonly IStoreEvents _store;
	private readonly IBus _bus;

	public EventsRebuilder(IStoreEvents store, IBus bus)
	{
		Contract.Requires<ArgumentNullException>(store != null, "store");
		Contract.Requires<ArgumentNullException>(bus != null, "bus");
		_store = store;
		_bus = bus;
	}

	public void Rebuild()
	{
		var commits = _store.Advanced.GetFrom(null).ToArray();

		foreach (var commit in commits)
		{
			var evts = commit.Events
				.Where(x => x.Body is Event)
				.Select(evt => (dynamic)evt.Body)
				.FirstOrDefault();

			_bus.Publish(evts);
		}
	}
}

Well begun is half done

Thinking about Event Upconversion should be one of the first strategies to define when you adopt Event Sourcing. That’s just because the events are the data saved and serialized from the beginning, during all the life of your application. So, defining at the very first moment how to serialize and deserialize the event data allow you to write more maintanable code, without having to adjust the target after. But in this sample application I wanted to put me in the worst condition: that’s, to add a event upconversion strategy after the application go-live. Using the VersionedEvent attribute as explained before allow me to add some more serialization/deserialization logic in order to face this situation.

Comments