Transitioning to Event Sourcing, part 8: remove the domain database, go event sourced
Une version française de ce billet est disponible ici.
Overview
Finally we can terminate this refactoring. It is now trivial to use events to load our aggregates.
Benefits
Complete responsibility segregation
Loading our aggregates from the events allows us to “free” the persistent tables that are still performing the role of view model. This view model can now evolve independently, there is no more coupling to the transactional part of the application. And as always, less coupling means easier maintainability, and should speed up the addition of new features.
It also means that the transactional part of your application is no longer tied to a relational model. It is therefore much more easier to make it evolve. From the DDD point of view, it lowers the complexity barrier that push some teams to not re-factor their domain model as their understanding of the business evolve.
Implementation
What changed
What we need to change is the way we are loading our aggregates in the repository:
{
var events = eventStore.LoadEventHistory(key);
var resVal = (T)constructor.Invoke(new Object[] { events });
AddToContext(resVal);
return resVal;
}
As you can see, we are first loading all the event history of the particular aggregate, and pass them to a new constructor on the aggregate.
Let’s look at the event store new method first:
{
using (var reader = persistenceManager.ExecuteQuery("SELECT [Version], [Data] FROM [Events] WHERE aggregate_id = @AggregateId ORDER BY [Version] ASC",
new { AggregateId = aggregateId }))
{
var events = new List<IEvent>();
var version = 0;
while (reader.Read())
{
version = reader.GetInt32(0);
var data = ((SqlDataReader)reader).GetSqlBinary(1).Value;
events.AddRange(Deserialize(data));
}
return new SimpleEventInputStream(events, version, aggregateId);
}
}
It is basically concatenating events of the commits of the given aggregate.
The new constructor in the aggregate root is even simpler. It is just calling the aggregate’s “Apply()” methods we already defined in part 4:
{
Version = events.Version;
foreach (var evt in events.Events)
{
ExecuteHandler(evt);
}
}
private void ExecuteHandler<T>(T evt) where T : IEvent
{
var handler = applyDelegates[this.GetType()][evt.GetType()] as Action<AggregateRoot, IEvent>;
if (handler != null) handler(this, evt);
}
And that is it. You now have a fully working CQRS / Event Sourced application!
Running the sample
The sources for the entire series is available on GitHub at http://github.com/jletroui/TransitioningToEventSourcing
.
To run this sample, simply create a new “DDDPart6″ database in SQLExpress before launching it.
Last 3 steps of this series being very small and composable together, the single “part 6″ sample is actually covering parts 6 to 8.
Transitioning to Event Sourcing posts:
- Part 1: the DDD “light” application.
- Part 2: go CQRS with DTOs for the read side.
- Part 3: define commands explicitly.
- Part 4: track state changes.
- Part 5: use events for updating your domain database.
- Part 6: store events.
- Part 7: use events to build a view model.
- Part 8: remove the domain database, go event sourced.
- Part 9: a brief word on versioning, smart merging strategies, eventual consistency, scaling the read side, scaling the write side.
Trackbacks & Pingbacks
- Transitioning to Event Sourcing, part 3: commands | Julien's blog
- Transitioning to Event Sourcing, part 1: the DDD “light” application | Julien's blog
- Transitioning to Event Sourcing, part 2: go CQRS with DTOs | Julien's blog
- Transitioning to Event Sourcing, part 5: use events for updating your domain database | Julien's blog
- Transitioning your DDD “light” application to CQRS and Event Sourcing | Julien's blog
Thank you for this series. It is very nice to see the pattern(s) put into practice.