It's been a while since I made a blog posting so this one might be a little lengthy. Let's chat up Event Sourcing...
What is Event Sourcing and why do I care?
First off, Event Sourcing is not new. It has been around a long time, but the buzz around Command Query Responsibility Separation and DDD has pushed it back into the nerdy mainstream. The basic concept behind event sourcing is that we record state changes in the form of events, instead of the entire state of the object each time.
Using this technique adds a few nice benefits too; First, a reliable audit log becomes a first class citizen in your architecture, and not an after-thought. Second the persistence code becomes remarkably simpler. Third, your event storage can be implemented by as many options as you can imagine (RDBMS, flat file, xml, Object DB, BigTable, CouchDB, etc). Finally, you can replay these events to create the state of an object at any point in time...which kicks up the cool many, many notches.
Let's cover a little bit about one way you could implement event sourcing to persist and recreate a domain object. Before I begin, a little proviso to keep the bliki piranha at bay: this code is taken from a Contact Manager sample app I am in the process of writing in java to demonstrate the CQRS architecture. It is definitely a work in progress. Before you say it, yes I am well aware that implementing a contact manager in CQRS is crazy over-architected ;}
The code can be found on BitBucket
here if you are interested in following along.
With that out of the way, the first thing we should discuss is how to develop your domain objects to take advantage of Event Sourcing. This snippet comes from my Contact object, which is an aggregate root in my domain. Each of the methods that modify the state of my object, translate that state change into an Event. For example,
The HomeAddressChanged object represents an Event. It is representative of the fact that the state of the address changed in my domain. Notice also that it is a past tense verb. This is important if you are trying to create DDD type UL. That said, DDD is out of scope for this posting, so let's move on.
After you've made all of your state changes, it's time to save the entity. The Contacts object, which is an implementation of the Repository pattern, will pull the events generated by state changes from the Contact aggregate (1 to *), and store them in the event store. Finally, the markChangesCommitted() method clears the event cache in my contact object.
The last part of persistence is saving these events in the event store. My example is *extra* simple because I am simply using an InMemoryEventStore, but your event store can literally be just about anything. I may do a separate post on the event store to delve into that topic a bit more.
A couple of key points. First, we ONLY ever insert into the event store, never update or delete. This is to preserve the lifecycle of the aggregate and build a solid audit trail. Second, it is very helpful if your aggregate has a identity that is unique throughout your enterprise. I chose a UUID for simplicity, but it isn't the only way to generate uniqueness.
Ok, now we have a series of events in the event store, lets talk a bit about replaying events to recreate an aggregate. First step is to get the events for a given id. In my case, I just grab them out of the event store:
Then I loop through this collection of events and in order, invoke the replay method of the aggregate to rebuild its state.
Notice the vanilla replay(Event event) method which uses Reflection to invoke the correct replay method for the type of event it is. This is not the most efficient way to build this functionality, but it is pretty darn simple to maintain, so I'm sticking with it for now. I'd be interested in hearing about other ways java folks have implemented this same piece without Reflection..perhaps an AOP implementation?
So when this loop finishes, you have the aggregate back in the exact state it was in when you stored it last. Here's an example of testing the storage and then the replay:
That concludes this little ditty about Event Sourcing. In a future post, I will demonstrate different types EventStore implementations. When I am satisfied with my CQRS Demo I will also do a series of posts about that topic.
If you are interested in CQRS, here are two great presentations by
Greg Young and
Udi Dahan.
That's it for now, I am interested to hear your experiences with Event Sourcing and ways I can tweak my code to make it more efficient or amp up the cool.