Reputation: 339
I'm building a DDD/CQRS Event Sourcing application. (.NET, EventStore)
I read a lot of articles about it, especially the famous bank account topic.
As reminder, we have the following events sequence:
But I've never found a blog post explaining how to validate the events sequence? I mean, what happen if I receive the Deposited event first, before BankAccountCreated? In other words, how do I check whether the bank account is created? How do I know the stream is in a valid state?
Do I have to call the read-model? every time? in each event? each method of the aggregate? What happen if the user sent it twice and the readmodel is not sync, yet?
I've read a lot of stuff about Event Sourcing, maybe not enough ^^, but I didn't find any information regarding the consistency about the events flow.
In my application, I cannot apply an event if the "first" event (ContactAdded) does not exist. Does it mean I have to call the EventStore each time I need to do something?
Thanks for your help.
Upvotes: 4
Views: 873
Reputation: 57259
How to validate the event flow in DDD - Event sourcing? How do I know the stream is in a valid state?
In domain driven design, the domain model has the responsibility for ensuring that the state satisfies your domain invariant. You can think of it as a function
everythingWeKnowNow = domainModel(everythingWeKnewBefore, newInformation)
As new information arrives, we integrate it with what happened before to produce a new version of "the truth".
In a CQRS world, this is all happening in the "write model" - we're working from the authoritative representation of "the truth", not a stale copy, and we modify it as requied by the domain.
The event sourcing part is really just a difference of representation: instead of computing a new state, then overwriting our previous copy, we compute changes, and append those changes to our previous (we can always recompute the state by simply enumerating over the list of changes).
So our authoritative copy of the state always has the events that were computed by the domain model in the order in which they were written.
The broad pattern here is the idea that the model is the authority for the information in the system, and event sourcing is just a different way of storing that information (one that supports temporal queries).
For parts of the solution that need an authoritative ordering of events, the trick is that you retrieve them from the event store as an ordered sequence, not by reading them one at a time and trying to reconstruct the sequence. In other words, you'll use a pull model, rather than a push model, to communicate the events from one system to another.
When you are working in a system based on a push model, and events may be mis-ordered, then you need to build that into your design. This tends to happen in the form of tracking what information is missing, and waiting until it arrives.
(You also have to pay more attention to time; message arrival time is a pretty lossy substitute for knowing when things happened).
Distributed systems are hard, and the short cuts we learned when everything was local don't work any longer.
Upvotes: 2
Reputation: 1222
There is a lot there.
How do I know the stream is in a valid state?
Each stream should have a monotonically increasing Version number on each event. Event 1 should precede Event 2 etc, per stream (Aggregate). EventStore will ensure this level of consistency by applying optimistic concurrency. You can provide an expected Stream Version (e.g. last Version written) when you write events to Event Store. When you read your stream of Events, you take the last Version number and you pass that along when you write Events to EventStore. If the event stream has grown since you last read, a concurrency error will be raised.
Do I have to call the read-model? every time? in each event? each method of the aggregate?
There is some confusion of terms here. Keep in mind Events vs Commands, Read vs Write models, and what purpose each one serves. You display data from your Read model. You validate and process against your write model.
What happen if the user sent it twice and the readmodel is not sync, yet?
Given the optimistic concurrency policy above, you essentially get a first-in-wins policy. To get past the issue, you can trap concurrency errors and reprocess your command from the beginning (getting the latest state from EventStore).
Does it mean I have to call the EventStore each time I need to do something?
Yes. On each Command, you would read the Event stream for your Aggregate and restore state. You can use Snapshots as an optimization, but the concept remains the same.
Upvotes: 7