Writing this in the Web UI which kind of sucks because I have not found a good blogging utility in unix yet. I kinda miss livewriter.
One of the biggest advantages of using Event Sourcing with CQRS is that is drastically changes how we even think about our problems. Let’s go through an example.
When I have an inventory item that is in a deactivated state and I deactivate it, it should throw an alreadydeactivatedexception
Or let’s try another one:
When a gold customer makes a purchase they should receive a 15% discount on their purchase.
Basically all of our use cases can boil down to “given some state, when some action, expect something”
Making statements like these leaves off many things. How do we know that an inventory item can even get into a deactivated state? If it can’t is there any purpose in testing what happens if it is? When we represent current state we talk about any possible state the object could have, not the finite number of states an object can get into. What happens if we never implement a deactivate method?
We also are coupling our use cases to the concept of current state. Unfortunately our representation of current state has a funny way of changing over time.
What happens when we Event Sourcing?
When an inventory item that has been deactivated is deactivated and alreadydeactivatedexception should be thrown
When a customer that has been marked as a gold customer purchases an item they should receive a 15% discount
These use cases are describing series of behavior not current state! We know that we are testing relevant items because we are giving series of behaviors that the object can do, as such the state that we end up with is necessarily a state the object could actually be in.
What is more important is that our use cases are being structured much differently. Instead of describing things as …
“given some state, when some action, expect something”
we are describing things as:
“given the system has done these behaviors, when some action, expect something”
The difference between these two is HUGE!!!
1) The first method requires specialization for every type of object (eg: state representation) where as the second one is a generic one for all use cases.
Given: A series of events
When: A command
Expect: A series of events
Since events and commands are simple messages this can be genericized in < 30 lines of code for all objects.
2) The first one couples our use case language to our internal domain structure where as the second one does not, it describes the actions in terms of a calculus of themselves. This is to me the most important part as we can freely change our internal structures without worry, and our tests will remain just as relevant.
Sorry for the run by posting but I hope some people gain something out of this.