This is the first in a series of posts I’ll be doing about software architecture.
In my experience, knowledge of architectural patterns is the missing ingredient from most developers’ recipe books. As developers, we’re encouraged not to design up-front. We’re told to let design ’emerge’ through bottom-up development methodologies. This can be misleading.
Proponents of agile development often dismiss architecture, placing it in the same category as project management. This is like throwing the baby out with the bath water!
Any sufficiently complex application requires both a bottom-up and a top-down development strategy. No amount of Test-Driven Development is going to produce a scalable, resilient architecture without some form of top-down input. Knowledge of architectural patterns, practices and principles is that essential input.
You refactor a codebase into patterns. Patterns don’t just emerge out of nowhere. And in order to do that you need to know what those patterns are to begin with.
I’m not a fan of long blog posts. So these posts will be as short and concise as I can make them. So let’s get started!
The first pattern that you should know about is CQRS.
What is CQRS?
CQRS stands for Command Query Responsibility Segregation. It’s about separating the read and write operations in your application.
In this case, we’re reading and writing to a relational database but this could just as easily be a NoSQL data store.
Commands modify state and don’t return anything. These include database create, update and delete operations.
Queries answer questions about state and do return a value. Queries represent database read operations.
Pro Tip: Create operations usually return an ID so there can be exceptions to the ‘don’t return anything’ rule!
Why might you use CQRS?
CQRS is an example of separating concerns. This makes your codebase cleaner and easier to reason about.
The main advantage, however, is that you can increase performance. This is because you can optimise the command and query stacks separately.
For example, if you’re using an ORM like Entity Framework or NHibernate, you might use separate contexts for read and write stacks. This can simplify queries and mean less data is loaded into memory when performing CRUD operations.
In production, you can deploy read and write stacks to separate API applications. These can then be scaled independently. Another advantage this gives you is greater control over security because you can apply different security rules to reads and writes.
CQRS is a great fit when you’re building a distributed application using event messaging. But it’s not an architecture that you would apply to your entire application. If you’re doing Domain Driven Development, for example, you might only use CQRS in some Bounded Contexts.
Why might you not use CQRS?
CQRS adds significant complexity to your application. So don’t use it if your domain or business logic is relatively simple.
You’re also creating two inconsistent pipelines to perform CRUD operations. By creating more production components, you’re adding to the maintenance overhead of your application. In this case, there’s a trade-off between performance and complexity.
How do you use CQRS?
There are a couple of main ways CQRS is used. I’ll go into a third way (called Event Sourcing) in another post.
1. Using a single database
In the simplest use case, CQRS uses the same database for reads and writes.
You can improve performance even further by adding a cache to the read stack and a queue to the write stack. In this architecture, write operations are added to a queue as event messages. A serverless function could process the messages as they’re added to the queue.
This results in a highly scalable architecture as shown here.
2. Using separate read and write databases
In this use case, you create two databases, each optimised for either reads or writes. The read database might contain denormalised data for faster performance.
Writes are pushed into the read database in one of two ways: either using a single co-ordinated transaction or using an Eventual Consistency pattern. This pattern will be covered in a future post.
Pro Tip: You can create as many read databases as you like. For instance, you might have a separate reporting database as well for aggregated data.
Now you know the basics of CQRS. Be sure to keep an eye out for future posts where I’ll cover other architecture recipes that every developer should know.