System Wide CQRS

John Gilbert
3 min readOct 15, 2019

--

I have already discussed the importance of autonomous services and event-first architecture and how system wide event sourcing is a crucial part of the approach. In this posting I want to discuss how system wide CQRS solves the other half of the autonomous services equation for putting appropriate bulkheads in place and how it differs from more traditional uses of CQRS because of its perspective.

Traditional uses of the Command Query Responsibility Segregation (CQRS) pattern tend to have a local perspective. A service catering to a specific user role maintains a write data model and a separate read data model. This is beneficial when the read and write requirements are distinct enough that trying to combine them into a single model requires sacrifices. But most services do not need the complexity of CQRS. Yet we don’t want to lose out on the flexibility that CQRS brings to the system as a whole.

Local CQRS Example

In contrast, autonomous services leverage a system wide perspective of CQRS. The example below shows an upstream BFF service that supports a specific user role and creates data in its own data store. In this case the service uses a single CRUD data model because it has no direct need for CQRS. But other users/services need access to this data as well. So a trigger function publishes domain events to the event stream as state changes. Downstream services consume these events and store the data locally using separate read data models that support their users.

System Wide CQRS Example

The advantage of system wide CQRS is that it allows us to create autonomous services that have no direct, synchronous dependencies on other services. A downstream service uses the CQRS pattern to create a bulkhead between itself and upstream services by listening for well-defined domain events and caching the data locally in a highly available, fully managed, cloud-native database. They become self-sufficient (i.e. autonomous) because they manage their own materialized views and continue to function even when upstream services are unavailable. Meanwhile, the upstream services are free to use the CQRS pattern or not. Following the system wide event sourcing pattern they produce events to the event stream. This creates a bulkhead that avoids coupling with downstream services while providing downstream services the option to use the CQRS pattern.

I inevitably get reasonable questions about the cost implications of system wide CQRS and I address them here. It is actually very economical.

For more thoughts on serverless and cloud-native checkout the other posts in this series and my books: Software Architecture Patterns for Serverless Systems, Cloud Native Development Patterns and Best Practices and JavaScript Cloud Native Development Cookbook.

--

--

John Gilbert

Author, CTO, Full-Stack Cloud-Native Architect, Serverless-First Advocate