Contenido del curso

CQRS: separar comandos e consultas em C#

Resumen

O padrão CQRS (Command Query Responsibility Segregation) propõe uma ideia simples mas poderosa: separar as operações que escrevem dados das que apenas leem. Se trabalhas com arquitetura limpa e queres organizar melhor o teu domínio, esta separação muda a forma como pensas o código.

O que é CQRS e por que importa nesta arquitetura?

A sigla significa segregação de responsabilidades de comandos e consultas. A ideia central é dividir o teu modelo em duas partes que vivem separadas dentro da aplicação.

De um lado tens os comandos, que são operações de gravação ou que alteram o estado de algo. Guardar um utilizador, modificar uma propriedade de um objeto ou atualizar uma linha numa base de dados, tudo isso entra na categoria de comando.

Do outro lado estão as consultas, operações de leitura cuja única responsabilidade é obter resultados. Por exemplo, listar utilizadores registados nos últimos 30 dias ou devolver a data da última venda num sistema de comércio eletrónico.

¿Qual é a diferença entre comando e consulta no CQRS? Um comando escreve ou modifica o estado do sistema e não devolve dados de negócio. Uma consulta apenas lê informação e nunca altera o estado.

Numa aplicação tradicional, interface, lógica e fonte de dados partilham um único modelo para ler e escrever. No CQRS, esse modelo divide-se em dois: um para comandos e outro para consultas [01:36].

Por que separar leitura e escrita em modelos diferentes?

Há várias razões práticas para adotar esta separação, especialmente quando o sistema cresce.

  • Uma das partes pode ser muito mais intensiva que a outra, como gravações pesadas versus leituras frequentes.
  • A manutenção do código fica mais clara quando cada classe tem uma responsabilidade única.
  • Abre portas para escalar leitura e escrita de forma independente na infraestrutura.

Como se aplica CQRS num exemplo de código em C#?

O exemplo usado parte de um template especializado em arquitetura limpa com CQRS, aplicado a uma típica aplicação de to-do list [03:13]. A estrutura torna as camadas muito mais explícitas.

Que camadas aparecem na estrutura do projeto?

A organização segue uma divisão clara entre domínio, aplicação, infraestrutura e interface web.

  • Domínio: contém entidades, exceções, enumerações e value objects.
  • Aplicação: aqui acontece a separação entre comandos e consultas para cada parte do domínio.
  • Infraestrutura: agrupa gestão de ficheiros, identidade, persistência e serviços auxiliares num mesmo projeto.
  • Web: projeto específico para a interface ou API REST que liga tudo.

Como se escreve um comando para criar uma tarefa?

O comando vive na camada de aplicação e implementa a interface IRequestHandler, que define um pedido e uma resposta [05:20]. Curiosamente, o nome é igual ao que aparece nos casos de uso clássicos, mostrando que muitas implementações trocam nomes mas mantêm o fundo.

A classe recebe por injeção um contexto de base de dados, que funciona como wrapper sobre o Entity Framework, o ORM da Microsoft para persistência. O método principal cria a entidade, atribui-lhe um título a partir do objeto de comando recebido, executa a interação com a persistência e devolve um resultado.

E como fica a consulta para obter as tarefas?

A consulta segue o mesmo padrão. Implementa a mesma interface, define um método handle e recebe um pedido com os parâmetros necessários para filtrar os dados [07:08].

A regra de ouro aqui é direta: se estás numa classe de consulta, não executas comandos. Se estás num comando, não fazes leituras de negócio. Essa disciplina é a consequência mais importante de adotar CQRS.

Como o controlador consome comandos e consultas?

É neste ponto que a implementação muda em relação aos casos de uso tradicionais. O controlador, que vive na camada de interface web, não chama diretamente a consulta nem o comando.

Em vez disso, usa uma espécie de mediador. No exemplo, o framework utilizado chama-se Mediator [08:25]. O controlador lança um evento a pedir informação, e quem souber tratá-lo executa a operação correspondente.

O que é o Mediator no contexto de CQRS? É uma biblioteca que recebe pedidos da camada externa e os encaminha para o comando ou consulta correto, sem que o chamador conheça a implementação concreta.

O benefício é claro: o código fica muito mais desacoplado. A contrapartida também: torna-se mais difícil de depurar porque deixas de ter rastreabilidade direta entre invocação e resultado, passando a depender de eventos.

Em que níveis posso aplicar CQRS além do código?

A separação entre comandos e consultas escala por vários níveis da arquitetura.

  • Métodos: evita misturar leitura e escrita. Um método chamado procurar ou criar produto, que procura e, se não encontrar, cria, viola o princípio.
  • Classes: tens classes só de consulta e classes só de escrita.
  • Serviços ou backends: podes ter serviços completos dedicados a leitura e outros a gravação.
  • Bases de dados: em sistemas com forte concorrência, há bases de dados só de leitura e outras só de escrita, com mecanismos de sincronização entre elas [11:32].

A partir daí entras num território mais avançado, ligado à programação orientada a eventos e a problemas reais de escalabilidade. CQRS não é apenas um padrão de código, é uma forma de pensar como a tua aplicação cresce.

Se já experimentaste separar comandos e consultas no teu projeto, conta nos comentários como foi essa transição e que ferramentas usaste para gerir os eventos.