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
A high-level overview of an application built using the CQS pattern. A physical separation is possible and allows you to scale up on both “read” and “write” sides. But, this is fairly complex and leans more to CQRS
- This reduces bugs, improves readability, and makes code more testable
- It encourages you to write better code, that follows SOLID principles and allows the introduction of (better and more) Unit Testing
- CQS is well-suited towards complex domains where Domain-Driven Design is most useful
- Commands: Create, Update, Delete
- Queries: Read
- Commands: POST, PUT, DELETE, PATCH
- Queries: GET
- Commands: ALL (expect one)
- Queries: SELECT
- Commands: mutates state but does not have a return value SRP
- Queries: have a return value doesn't mutate state SRP
💩
interface JobInterface
{
public function getJob(string $title): object;
public function addJob(object $value): void;
}
❤️
final readonly class ReceiveJobsQuery
{
public function __constructor(private string $title)
{
}
}
final readonly class CreateJobCommand
{
public function __constructor(private object $value)
{
}
}
final readonly class CreateJobCommandHandler implements CommandBusInterface
{
public function __invoke(CreateJobCommand $command): void
{
}
}
final readonly class ReceiveJobsQueryHandler implements QueryBusInterface
{
public function __invoke(ReceiveJobsQuery $command): object
{
}
}