CQRS
Separating read and write models to optimize each independently.
CQRS stands for Command Query Responsibility Segregation. The core idea is to use different models for reading and writing data.
In most applications, the same data model serves both reads and writes. This works fine at small scale, but as the system grows, the read and write sides often have conflicting requirements. Reads prefer denormalized, fast-to-query views. Writes need normalized, consistent data.
CQRS splits these into two separate paths:
- Commands change the state of the system. They don't return data.
- Queries read the state. They don't change anything.
Each side can use a different data model.
They can use the same storage or different ones, depending on the specific needs. The write side might use a relational database with strict consistency. The read side might use a denormalized view optimized for specific queries. Or they both could use the same database with different queries.
Sometimes, the two sides stay in sync through events: when a command changes state, it emits an event. Event handlers on the read side update the read models accordingly.
Even though CQRS works well with separate storages, remember that it's not a requirement. The key idea is you use two decoupled models in the code for reads and writes, regardless of how the data is stored.
References
- How to use basic CQRS in Go — Walks through a practical CQRS implementation in Go, splitting application logic into commands and queries. Explains naming conventions and shows how CQRS solves issues with complex, unmaintainable models.
- Combining DDD, CQRS, and Clean Architecture in Go — Shows how to connect DDD Lite, CQRS, and Clean Architecture in practice. Covers repository refactoring, command handlers, and maintaining constant development speed.
- How to implement Clean Architecture in Go (Golang) — Introduces Clean Architecture as a foundation for the series. Mentions CQRS as the next step to improve the application layer by splitting it into commands and queries.
- Increasing Cohesion in Go with Generic Decorators — Discusses splitting application logic into commands and queries, CQRS style, and applying generic decorators to add cross-cutting concerns like logging and metrics.
- Live website updates with Go, SSE, and htmx — Uses Watermill's CQRS component with EventBus and EventProcessor to publish and subscribe to events for real-time website updates.
- Microservices test architecture. Can you sleep well without end-to-end tests? — Revisits the testing layers after introducing CQRS and Clean Architecture. Shows how to test commands and queries at different levels of the architecture.
- The Repository pattern in Go: a painless way to simplify your service logic — Explores the repository pattern alongside CQRS. Mentions CQRS as the next step to clean up complex data models with separate read and write paths.
- Common Anti-Patterns in Go Web Applications — Lists CQRS as a pattern related to using different read models and write models, alongside Clean Architecture and the Repository pattern.
- Distributed Transactions in Go: Read Before You Try — Uses Watermill's CQRS EventBus and EventProcessor components to publish and handle events as part of distributed transaction patterns.
- Database Transactions in Go with Layered Architecture — References CQRS for structuring the application layer into commands and queries, keeping logic separate from implementation details like HTTP handlers.
- Watermill 1.3 released, an open-source event-driven Go library — Introduces a redesigned CQRS API for Watermill, deprecating the Facade in favor of separate CommandProcessor, EventProcessor, CommandBus, and EventBus with generic handlers.
- Golang CQRS, Metrics and AMQP - Watermill v0.3.0 released — Introduces Watermill's built-in CQRS component, based on the existing Router and PubSub, with support for custom marshalers and interoperability with non-Go infrastructure.
- Synchronous vs Asynchronous Architecture — Discusses CQRS as a pattern that works well with both synchronous and asynchronous approaches. References the CQRS article and explains how Command Query Responsibility Segregation fits into event-driven systems.
- Is Clean Architecture Overengineering? — Discusses integrating Clean Architecture with DDD and CQRS in Go. Mentions the blog post on combining these patterns and the Wild Workouts example project.
- Watermill CQRS Component
- Killing the legacy and other CQRS stories