Let’s start by decoding the acronym CQRS – this stands for Command and Query Responsibility Segregation. From this we can see the intent is to segregate our code into command and query responsibilities.
So what’s a command in this context and what’s a query?
- A command is “any method that mutates state” (analogous to a setter type operation)
- A query is “any method that returns a value” (analogous to a getter type operation)
It’s probably pretty obvious, but we can liken the command to the CRUD operations, CREATE, UPDATE and DELETE, whereas a RETRIEVE would map to a query (probably self-explanatory).
There’s nothing too complicated about this except in terms of how we’d code such things. The idea would be to split our code into two classes whereby we might have something like this
public class EmployeeCommands { public void CreateEmployee(int employeeId /* other params */) {} public void UpdateEmployee(int employeeId /* other params */) {} public void DeleteEmployee(int employeeId) {} } public class EmployeeQueries { public Employee GetEmployee(int employeeId) { /* implementation */ } }
If adhering explicitly to a CQRS pattern then we can also think of queries returning state but never changing it and commands as changing state and always returning void (i.e. not returning anything). This can become too restrictive in some situations but obviously one should have a valid reason for deviating from this pattern otherwise you’re not really following the CQRS way.
This is basically the core design principle behind creating a CQRS architecture. One of the key concepts here is that the separation of command and query means we can also do away with a common domain or data model for the commands or queries. Conceptually this separation gives us more freedom to not only design our data models but also in scenarios whereby our reads might come from a different locations/store to our writes, we’re again separating these pieces.
Another interesting side affect of a separation of command and query is, generally a command will warrant a different set of security requirements/permissions to a query. This is not to say we do not require security on queries, especially when sensitive data exists, but obviously we might be far more restrictive on who can amend a data object than who can view one. With this separation we can declare our permissions on our read/write data sources differently if we want.
Separating reads and writes!?
I previously stated that we might have our reads coming from one location and our writes from another, this may sound (initially at least) slightly strange. However, several documents on the concepts behind CQRS mention this scenario.
Notice, I said might, obviously this isn’t a requirement for us to be using a CQRS archtecture.
It’s not unusual to have a data store, such as a database to exist along with one or more data caches. The idea being writes are sent to the DB, the DB updates and the caches are then updated to keep in sync with the DB, but when we query data it’s (depending upon requirements) far faster to get data from the cache and return this. Hence we have a decoupling of the write and the read, so to speak, which means we might maintain a single DB but maintain multiple caches at different locations to ensure the fastest access/reads.
You may have thought – “if we have a situation whereby the DB is written to but the cache then gets updated, isn’t there a possible scenario where the cache’s data is not yet ‘consistent’ with the DB’s data?”
This is indeed the case of this separation, we’re really (sort of) doing something that a lot of No-SQL data stores do, which is have “eventual consistency”. This is eventual consistency, not at the DB level (like MongoDB) but as at an architectural level. In other words our DB will be immediately “consistent” but the cache’s will be “eventually consistent”.
From my understanding, the above is basically what we, as developers, need to do or how we need to think in terms of implementing CQRS.
Most CQRS documents also go on to talk about architectural design. Such as, we see CRQS documents talk about Event Stores as part of the overall design. An event store is used to store each transaction/change in data as single entities and can be used to regenerate the whole database from each of these entities. However I do not want to go into architectural choices/options as CQRS in this post.
References
CQRS Journey
CQRS Journey Source
CQRS, Task Based UIs, Event Sourcing agh!
Building an Event Storage