CQRS: Separando Leitura e Escrita para Melhor Performance
CQRS (Command Query Responsibility Segregation) é um padrão arquitetural que separa as operações de leitura (queries) das operações de escrita (commands) em modelos diferentes.
Proposto por Greg Young, o padrão quebra a premissa tradicional de que leitura e escrita usam o mesmo modelo de dados.
Motivação
Em sistemas tradicionais CRUD, usamos o mesmo modelo para ler e escrever. Isso gera problemas: modelo complexo tenta atender ambos os lados, queries lentas devido a JOINs, dificuldade em otimizar, escala limitada.
Conceitos Fundamentais
Command (Escrita): Representa intenção de mudar o estado do sistema. Nome em imperativo: CriarPedido, AtualizarCliente. Pode falhar (validações). Retorna sucesso/erro, não dados.
Query (Leitura): Busca dados sem alterar estado. Read-only, otimizado para visualização. Pode usar caches, denormalização agressiva.
Arquitetura CQRS
O cliente envia Commands para o lado de escrita e Queries para o lado de leitura. Commands vão para Write DB, Queries para Read DB. Podem ser bancos separados.
Exemplo Prático
No modelo tradicional, temos um único service com create, update, search, list. Mesmo modelo para tudo, queries complexas, difícil otimizar.
Com CQRS, temos CommandHandler (valida, cria agregado, persiste, emite evento) e QueryHandler (lê do read DB denormalizado, sem JOINs).
Níveis de CQRS
Nível 1: Modelos separados, mesmo DB. Mais simples mas menos flexível.
Nível 2: Bancos separados. Otimização independente mas eventual consistency.
Nível 3: CQRS + Event Sourcing. Write side usa ES, read side usa projeções. Máxima flexibilidade e complexidade.
Vantagens
Performance: Queries otimizadas separadamente, caches agressivos no lado de leitura, denormalização sem culpa.
Escalabilidade: Escalar read e write independentemente, read replicas, CDN para queries.
Segurança: Separação clara de permissões, commands auditáveis, queries read-only.
Modelos Específicos: Write normalizado com regras de negócio, read denormalizado otimizado para UI.
Desafios
Eventual Consistency: Write acontece, read demora alguns ms/segundos para atualizar. Solução: UI otimista, polling, websockets.
Complexidade: Mais código, mais componentes, mais pontos de falha. Solução: começar simples, aplicar apenas onde necessário.
Sincronização: Manter read DB sincronizado com write DB. Solução: event-driven, CDC, message broker.
Quando Usar
Use quando alta carga de leitura vs escrita desbalanceada, queries complexas matam performance, precisa escalar read e write diferentemente, ou UI precisa de modelos específicos.
Evite quando sistema CRUD simples, read/write balanceados, time pequeno sem experiência, ou eventual consistency é inaceitável.
Implementação
Commands e Queries são objetos com tipo, agregateId e dados. CommandBus executa handlers específicos. QueryBus busca dados específicos.
Sincronização via eventos: write side emite evento, read side ouve e atualiza view database.
Padrões Relacionados
Event Sourcing combina perfeitamente com CQRS mas pode existir sem. Domain Events comunicam mudanças entre sides. Saga Pattern coordena transações distribuídas.
Ferramentas
MediatR para .NET, Axon Framework para Java, NestJS CQRS para Node.js, Kafka/RabbitMQ para event streaming.
Conclusão
CQRS é poderoso para sistemas com leitura/escrita desbalanceada. Não é obrigatório aplicar em todo o sistema - use onde faz sentido.
Combine com Event Sourcing para máximo poder, mas esteja preparado para a complexidade adicional. Comece simples e evolua conforme necessidade.