CQRS.
Separe o modelo que altera o estado (comandos) do modelo que lê o estado (consultas), de modo que cada lado possa ser modelado, escalado e otimizado de forma independente.
##Intent
Use um modelo para atualizar informações e um modelo diferente para lê-las. Comandos expressam a intenção de alterar o estado; consultas retornam dados formatados para exibição. Os dois não precisam mais fazer concessões em torno de uma única representação compartilhada.
##Problem
Em um design tradicional, um único modelo atende tanto escritas quanto leituras. As escritas precisam de validação rica e invariantes; as leituras precisam de formatos desnormalizados e prontos para exibição — muitas vezes vários diferentes para diferentes telas e relatórios.
Forçar ambos através dos mesmos objetos e tabelas leva a concessões desajeitadas: over-fetching, mapeamentos ORM complexos, contenção de locks e um modelo que não é bom em nenhuma das duas tarefas.
##Solution
O CQRS divide o sistema em dois. O lado de escrita trata os comandos por meio de handlers que carregam um agregado, impõem invariantes e persistem a mudança (opcionalmente emitindo eventos). O lado de leitura serve as consultas a partir de um ou mais read models formatados especificamente para as views que os consomem.
Os dois lados podem compartilhar um banco de dados ou usar stores separados. Quando estão separados, os read models são mantidos atualizados projetando os eventos do lado de escrita, aceitando consistência eventual em troca de escalabilidade independente e consultas mais simples.
##Structure
- Comando — uma requisição para alterar o estado, nomeada pela intenção (
PlaceOrder). - Command handler — valida e aplica o comando ao write model.
- Write model — agregados que impõem invariantes; podem emitir eventos.
- Read model / projeção — views desnormalizadas construídas para consultas, atualizadas a partir de eventos.
- Query & query handler — requisições somente de leitura servidas a partir do read model.
##Applicability
- Use-o onde leituras e escritas têm formatos ou cargas muito diferentes — muitas views de leitura, relatórios pesados ou uma alta razão entre leitura e escrita.
- Use-o em UIs baseadas em tarefas e domínios colaborativos, onde ele combina naturalmente com Domain-Driven Design e event sourcing.
- Evite-o em CRUD simples; um único modelo é mais simples e a divisão adiciona custo sem retorno.
##How to Implement
- Modele os comandos como intenções explícitas em vez de atualizações genéricas.
- Roteie cada comando para um handler que carrega o agregado relevante e impõe suas invariantes.
- Persista a mudança e, se estiver usando eventos, publique o que aconteceu.
- Construa read models adequados às suas views; se separados, atualize-os projetando eventos.
- Sirva as consultas diretamente a partir dos read models — sem lógica de domínio no lado de leitura.
##Pros & Cons
- Os lados de leitura e escrita podem ser modelados, otimizados e escalados de forma independente.
- Cada modelo permanece pequeno e focado em uma única tarefa.
- Encaixa-se em UIs baseadas em tarefas e compõe bem com event sourcing e DDD.
- Os read models podem ser adaptados por view, eliminando joins desajeitados.
- Mais partes móveis e mais código do que um único modelo CRUD.
- Stores de leitura separados introduzem consistência eventual, que a UX precisa tratar.
- Fácil de superengenheirar; raramente se justifica para domínios simples.
- Sobrecarga operacional de projeções e do encanamento de mensagens.