I’ve been reading the Microsoft patterns and practices CQRS journey, and it has been excellent.
A couple of thoughts struck me as I read. There seemed to be a lot of confusion on how to approach CQRS and where Event Sourcing fit in or even if ES did fit in. I’ve seen this a lot all over the place. Sitting down to think about this in terms of what I learned from Greg Young at his class I came up with the following.
For me it all boils down to that they got into trouble when they started focusing on CQRS. CQRS has got a lot of things going for it, not least a new and really recognizable name. But the real core pattern is Event Sourcing. CQRS’s greatest claim to fame is in that it allows you to use Event Sourcing.
It is also critically important to see why ES is the core: Event Sourcing is lossless. Event Sourcing is simply the history of all the things that happened in your system, in the order they happened in. Solid Gold. There is no better way to capture the sequence of every state change in your domain model and with that in hand you can do nearly anything.
Once you set your sights on enabling Event Sourcing and reaping it’s benefits, it answers all of the why questions that come up when looking at these other patterns.
If you think of the messages in the event store as simply parameter objects being passed into functions; you could capture and serialize every method call in your application through injecting wrapper functions. This store would look much like a transaction log in a DB without being nearly as useful. We don’t need to capture everything that happens, just what matters. I don’t really care that we called the logger. What matters the business problem.
So first we need to define the business part of the problem and separate it for everything else in the code. That brings in DDD and by following the patterns laid out by Eric Evans we can model the business problem as domain objects in the Bounded Context. Now we know what to track. Objects are state and behaviors. The behaviors are stored in the code, so what we are missing is the state of the domain objects.
We could then save the state of the domain in a RDBMS but those have impedance problems and worse yet they tend to overwrite data and lose state information. (That’s why transactions and rollbacks are such a big deal with relational databases, every time you update or delete you’ve destroyed data. You must have a way to ensure nothing changed midflight and undo if it did because as soon as you change it it’s gone.) Much better is to store the sequence of parameter objects we passed to the methods on the domain objects. This gives us a method call transaction log for every method call in the Domain Model.
Not all of the method calls will actually change the state of the objects though. If we apply Command and Query Separation (CQS) to our method calls, we can refine the methods into commands and queries. First discarding the queries from tracking, we can make one more refactoring on the Command methods to also apply State and Behavior Separation (SBS)* so that behavior and state changes are in separate methods. Now we are the point where tracking the sequence of parameter objects passed into the state modifying methods on the domain objects will allow us to reproduce the exact state of the business domain at any point in time with exact fidelity and the ability to ‘scroll’ forward and backwards through time at will. ‘Parameter objects passed into the state modifying methods on domain entities’ is a mouthful so let’s just call them Events. And then we can call the place where we store them the Event Store.
So now we have a domain model that can accept commands and produce a lossless event stream. We still need to query the model and present interesting things to the user and other systems. Domain models and event streams are not the best read models, and when we start modifying the domain to optimize for reads we start to violate any number of best practices. This is where CQRS really shines; by publishing the Event Stream to be consumed by any number of optimized read models we get to have our cake and eat it to. The readers can access dedicated read models and we have achieved an optimum level of separation of responsibility in the system. The one thing I hear again and again about CQRS implementations is, “the system was easy to change,” a sure sign of a well factored system.
When you start the system focused on a clear business problem with business events tracked in an Event Store everything else falls naturally into place.
Thanks,
Chris
*P.S. SBS State and Behavior Separation is type of refactoring approach I was first shown by Greg and I think it is important enough that it needs a Name. It really is that fundamental to isolating the state modification of the Domain Entities. The Behaviors should be public methods triggered either directly or indirectly by commands or external events and the State Methods should be private and triggered by internal events. Both method types are Commands from the CQS pattern where a public Behavior method will invoke logic that may or may not decide to change state by calling a private State method that will only modify state without any logic or exceptions. In Event Sourcing the parameter passed to the State method is the Event and name of the Event and the method are related by convention.
P.P.S. Applying the SBS a pattern on legacy systems will allow event generation, and event sourcing if combined with DB event capture systems.