Synchronous Communication — Queries & Cache (Part 1/3)

This write-up revolves around queries & CQRS to set up the ground for implementing a caching strategy.

Abhinav Kapoor
CodeX
4 min readOct 24, 2022

--

Photo by Hadija Saidi on Unsplash

In one of my previous articles, I wrote that if we could implement a publisher-subscriber communication model and the publishers could pack all the necessary information in the events about the state change then subscribers have all the data to operate upon, and queries could be avoided. While the pub-sub model usually results in a high throughput, scalable system by taking out complications from the application & moving them into the infrastructure, we cannot use the pub-sub model in all cases.

Systems do need to make read or search requests because either it models the use case better or because of its simplicity. Such a request to fetch data is called a query.

How does the segregation of reading and writing paths help?

Any software dealing with a data store can either keep the same path to update & read data, which is common in CRUD-style data access operations, or it can bifurcate the data update operation from the data read operation. This simple segregation is known as Command Query Responsibility Segregation Pattern (CQRS). Commands are responsible for changing the state, and queries are responsible for reading the state.

CQRS — Separation of data update and read

For academic interests, here are a couple of articles from 2010 & 2012 by Gregory Young (who coined the term CQRS), where he explains CQRS as only the separation of concern for the purpose of reading and writing by creating 2 separate objects. And clarifies the myths surrounding CQRS which often make it look more complicated than it was intended to be.

The pattern is simple & straightforward, but it opens up the mindset of having different perceptions, and asymmetrical needs while querying or updating data. And as this mindset is applied to different contexts, it starts growing into different forms.

For example, in the context of domain-driven design, maybe a cluster of domain objects form an aggregate and have to be updated together to maintain the integrity of the aggregate, although while reading it may be needed to simply get one or few of the domain objects out of data store.

Commands maintaining aggregate boundary while Query reading only specific domain objects

Or in the context of a relational database, where the read path may be using a view built on top of data tables.

RDBMS- Command Updates data table while query reads from a materialised view on the same physical database.

Or when the read data store is a separate physical node, either for a read efficient data store, information hiding or for asymmetrical read scaling requirements (or it could be a simple read replica).

CQRS on separate physical data stores

Or in Verticle slice architecture where the commands & queries help create separate verticle slices.

Or another possibility could be that the query data store is built over events, instead of building on the primary data store. As in this Udi Dahan’s example

  1. A command is sent to update the state.
  2. The state is updated in the database and the event is published.
  3. The query store, which is a cache in this example gets updated.

Depending upon how the read model is designed, either as CRUD-based data access or a bifurcated CQRS, it would be a possibility to apply one of the several caching strategies. In the next write-up, I’ll write about caching.

Link to Next Part

Credits https://learn.microsoft.com/en-us/azure/architecture/patterns/cqrs

--

--

Abhinav Kapoor
CodeX
Writer for

Technical Architect | AWS Certified Solutions Architect Professional | Google Cloud Certified - Professional Cloud Architect | Principal Engineer | .NET