Before we plunge into the CQRS approach, a brief description of the CQRS architecture is in order.
CQRS stands for Command Query Responsibility Separation. For the common developer like you or I, this could be simplified to mean a 2-datastore architecture. In this architecture, we construct a read-only datastore and a write-only datastore. Of course these two are not ONLY for read and write, after all… the system needs to populate and maintain these stores. The naming is intended to define what the end-user’s interaction with each data-store is.
Before I go too much further, if you want the complete details from THE authoritative source on the topic, I highly suggest reading two thought leaders:
- Udi Dahan – Founder of NServiceBus, and all around nice guy
- Greg Young – World Traveller and Founder of CQRS Info.
By separating the reads from the writes, we enable some significant optimizations in our architecture. A read-only database can be configured to mirror layout and access patterns the end-users prefer when they consume our data. The write-only datastore can be optimized to allow fast append-only access to the store, and a minimum number of indexes allowing for very fast write-access.
Consider this: when users access your website, they are primarily reading data from your data store. In many environments, the users are less-frequently writing to the data store. When those users are writing to the data store, it is acceptable performance for that write-action to take a second or two to complete. However, Google now considers page speed in search ranking algorithms. So, lets optimize for lightning fast read-access, provide acceptable write access, merge the two and provide details to our end-users about when the last write occurred so they can make appropriate judgements about how to work with our data.
With the architecture, several choices are afforded to us because we are no longer tied to the necessity of keeping our read and write data in the same structure. The read-only datastore can actually be optimized to be file-stores on disk or we can also consider NoSQL offerings like MongoDb from 10Gen. On the write-only side, the strategy we will be discussing is the “ES” or EventStore strategy. In particular, I will be walking through the usage of the Jonathan Oliver Event Store library.
How do we tie these two datastores together? How do we ensure that they are consistent? This is the job of a messaging platform like NServiceBus or MassTransit. The scope of using these tools is beyond this discussion, but may be the target of a future blog post.
In the next post, we will begin constructing a Domain-Driven-Design class architecture to support the write-access to the data store. This will expose the Event objects to be stored. The composition of the read-only store will follow, and we will pull the three parts together in the following post.