I recently found out that I did not grasp those design patterns. There are a lot of resources on the Internet about them but they are not always accurate. That’s a shame because they are pretty simple. I will share my understanding of them with you.
What is Command Query Segregation (CQS)?
The fundamental idea is that we should divide an object’s methods into two sharply separated categories:
- Queries: Return a result and do not change the observable state of the system (are free of side effects).
- Commands: Change the state of a system but do not return a value.
This concept is not specific to Object Oriented Programming but improves the object’s design. The object methods only have a single purpose: reading or changing the object state. We can see an object as a living entity. We can ask a question to someone because we need information. For example, we can ask someone what time it is. This is a query. We can ask someone to do something, we don’t expect an answer but we want to get the job done. For example, we can ask a child to finish his/her spinach. This is a command.
We can apply this pattern to any object: like an aggregate. Let’s take an example! I would like to add markers on a map and then I would like to find which markers are the closest to a specific location (GPS Coordinates). k
class Map {
addMarker(label: string, latitude: number, longitude: number): void {
// ...
}
findClosestMarkers(location: Location): Marker[] {
// ...
}
}
The addMarker
method is in charge of mutating the object state without returning any result, while the ‘findClosestMarkers’ method finds the right markers without changing the object’s state. This object follows the CQS definition.
Do you speak French ? Tired of the same old CRUD applications, struggling with your framework, or feeling the pressure of production releases? It’s time to take your career to the next level.
Discover the power of Hexagonal Architecture and DDD to build robust and sustainable Symfony applications. Join me and kickstart your journey toward mastering advanced development techniques.
Let’s go further. If we design our aggregates following the CQS pattern, we should apply it to the classes that handle use cases.
interface MapService {
addMarkerToTheMap(label: string, latitude: number, longitude: number); void
findAllMarkersCloseToLocation(): Marker[]
}
This ensures there is no inconsistency in the codebase. The business services use and manipulate the aggregates. For example, if the MapService.addMarkerToTheMap
method returns a result, it might mean that the Map.addMarker
method will need to return the expected result.
What is Command Query Responsibility Segregation (CQRS)?
Starting with CQRS, CQRS is simply the creation of two objects where there was previously only one. The separation occurs based upon whether the methods are a command or a query (the same definition that is used by Meyer in Command and Query Separation, a command is any method that mutates state and a query is any method that returns a value).
Note: Greg Young’s blog does not exist anymore but his blog posts are still available thanks to archived.org.
CQRS is the separation of command and query into two different objects instead of only one. MapService does not follow the CQRS pattern because it has a query and a command. We need to cut this object in half.
interface MapReadService {
addMarkerToTheMap(label: string, latitude: number, longitude: number); void
}
interface MapWriteService {
findAllMarkersCloseToLocation(): Marker[]
}
That’s pretty simple, right? Anyway, we don’t need to introduce complicated things in our application to use this tactical design pattern. We don’t need a write and a read model, a command and query bus, an event sourcing architecture or multiple databases. Greg Young published this blog post in 2012 to explain what CQRS was not about.
CQRS is not a silver bullet
CQRS is not a top level architecture
CQRS is not new
CQRS is not shiny
CQRS will not make your jump shot any better
CQRS is not intrinsically linked to DDD
CQRS is not Event Sourcing
CQRS does not require a message bus
CQRS is not a guiding principle / CQS is
CQRS is not a good wife
CQRS is learnable in 5 minutes
CQRS is a small tactical pattern
CQRS can open many doors.
Note: This blog does not exist anymore but it has been archived by archived.org. The post is available here
Depending on the number of use cases the service classes can become really huge. CQRS helps to decrease their size but I am a big fan of them. I like to separate each use case into a dedicated class.
I’ve written a blog post to explain what is a commands and we can apply it to query too:
Thanks to my proofreader @LaureBrosseau .