Accessing Read Models from the Write Side¶
In a system built with CQRS and Event Sourcing, it's tempting to reuse the read models inside the write-side logic. After all, they already contain the information you need – right?
But using read models on the write side is almost always a bad idea.
Let's explore why.
Why It's Tempting¶
Say you're handling a BorrowBook command. To check if the user has already reached their borrowing limit, you could look into a read model like:
Seems straightforward – but it violates a core principle of event-driven systems.
Why It's Dangerous¶
Read models are:
- Denormalized
- Optimized for display
- Eventually consistent
They're not guaranteed to be up-to-date at the moment a command is processed. Relying on them introduces subtle race conditions and correctness issues.
More importantly, using them from the write side reverses the direction of flow:
In event-driven systems, events flow from write → read, not the other way around.
Better Approaches¶
There are two main alternatives:
Use the Event Stream¶
Reconstruct the necessary information from the event history. For example:
- Load the member's event stream
- Count the number of active
BookBorrowedevents minusBookReturned
This approach is correct, but may become expensive if the stream is long.
Use Write-Side Projections¶
Instead of using a read model, maintain a small write-side index – an up-to-date, internal summary of state that can be accessed reliably within command handlers.
For example:
- A precomputed count of active loans per member
- Stored as part of the write model, updated on each event
This way, you stay consistent without relying on read-side projections.
Summary¶
The read side is for reading. The write side is for deciding.
Don't mix the two.
Next up: See what eventual consistency really means – and how to deal with it in the user experience.