0

I want to ensure that I understand the scenarios which CQRS is intended. For example, if a web service has two types of clients:

  1. many external clients who will only query via GET; they will never POST/PUT/PATCH/DELETE
  2. an internal client who will primarily populate (via POST/PATCH/PUT/DELETE) the data store that the service uses to fetch queried data for the external clients

service sample with many clients who read and one client who writes

Is this the scenario that the CQRS pattern was meant to satisfy, with a possible EventSource handling the updates to the data store from the internal client? Of course, I realize that external clients can update the data store too - I'm just using the above example as a requirement that came to me recently.

5
  • 1
    It might interest. You will read about some important considerations to take in account. In the theory, the architecture is a little bit more complex than the one you have drawn
    – Laiv
    Dec 6, 2016 at 18:00
  • Out of curiosity, which application did you use to draw that diagram ?
    – cwap
    Dec 6, 2016 at 20:03
  • Yes, @Laiv, Fowler's description was my first look into CQRS. But you're right, my diagram is very simplified by comparison.
    – Bullines
    Dec 6, 2016 at 20:58
  • @cwap, I used Visio to create the diagram.
    – Bullines
    Dec 6, 2016 at 20:58
  • Have you read Young's blog posts about CQRS? Just for having better overview of where are you getting in :-). It worth to read.
    – Laiv
    Dec 6, 2016 at 21:04

1 Answer 1

3

While CQRS can certainly be used for that, what it was developed for is not necessarily differing audiences with different usage requirements (read vs. write), but rather for scaling of the load.

By separating the read/query capabilities from write/command capabilities, it enables the underlying architecture a large amount of flexibility.

Ultimately this flexibility allows for two separate parallel implementations, one optimized for writing/update and the other optimized for reading/query.

The write path may be implemented using a relational store as normalized data is often very good for transactional updates.

Whereas the read path may use a denormalized (relational or non-relational) store because by pre-expanding the joins (thru denormalization) of heavily used queries, the queries can be simpler and run faster.


Event sourcing builds on that model, using an append-only log-style database of command events as the primary persistence mechanism. There may still be an normalized write store, but with ES, this can fail and be rebuilt using just the easy-to-persist events.


The interface separation encouraged by CQRS is useful if you need to go down the path of dual purpose-optimized parallel implementations for scale.

However, this is fairly complex stuff. The parallel implementations need to be synchronized with each other, and atomically as observed by readers and writers, unless you have some evidence to believe that your application performs stably when seeing temporarily inconsistent state. This means that as the synchronization mechanism is updating the denormalized store for any given update to the write side, that it ought to show query result consumers only results that include whole denormalized updates, and not partial, in progress updates.

In theory, you could separate the interfaces and yet not immediately add the complexity of the dual linked-but-separate implementations.

However, to truly separate query from commands, the commands need to be submit-only with pretty much no response from the server. Thus, in CQRS often we find clients issuing the primary key for a newly submitted entity, rather than the server. This adds a complexity even without using the dual parallel, linked data store implementations.

It would be difficult to guarantee you'd held the interfaces to the CQRS model if you are only using a single shared store as I believe there would be constant temptation to return values from a command unless a high degree of rigor is applied.

Some of the complexity involved is pushed back into the client who not only needs to provide primary keys for new entities, but also has to essentially wait for asynchronous changes to read the results of their own updates. All of this adds up to complexity that requires some not necessarily off-the-shelf available solutions.

1
  • You bring up a good point of separately scaling the queries and commands. I am interested in this because the querying clients will grow at a fast rate, whereas the Internal Service will grow minimally. Commands being submitted only does indeed apply to my use cases, as well as the client (the Internal Service) supplying the keys. It looks like much of my effort will be spent on the link between the de-normalized and normalized stores. Thankfully, the data structure has not changed much up to this point in the current implementation. You've given me a good place to start focusing on.
    – Bullines
    Dec 6, 2016 at 21:04

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.