O CQRS não é excesso de engenharia?

15

Ainda me lembro dos bons e velhos tempos dos repositórios. Mas os repositórios costumavam ficar feios com o tempo. Então o CQRS se tornou popular. Eles eram legais, eram uma lufada de ar fresco. Mas, recentemente, tenho me perguntado repetidamente por que não mantenho a lógica correta no método Action do controlador (especialmente na API da Web, onde action é algum tipo de manipulador de comando / consulta).

Anteriormente, eu tinha uma resposta clara para isso: faço isso para testar, pois é difícil testar o Controller com todos esses singletons imbatíveis e a feia infraestrutura geral do ASP.NET. Mas os tempos mudaram e as classes de infraestrutura do ASP.NET são muito mais amigáveis ​​hoje em dia, principalmente nos testes de unidade (especialmente no ASP.NET Core).

Aqui está uma chamada típica da WebApi: o comando é adicionado e os clientes SignalR são notificados sobre isso:

public void AddClient(string clientName)
{
    using (var dataContext = new DataContext())
    {
        var client = new Client() { Name = clientName };

        dataContext.Clients.Add(client);

        dataContext.SaveChanges();

        GlobalHost.ConnectionManager.GetHubContext<ClientsHub>().ClientWasAdded(client);
    }
}

Eu posso facilmente testar / zombar dele. Além disso, graças ao OWIN, posso configurar servidores WebApi e SignalR locais e fazer um teste de integração (e bem rápido, a propósito).

Recentemente, senti cada vez menos motivação para criar manipuladores pesados ​​de comandos / consultas e tenho a tendência de manter o código nas ações da API da Web. Só faço uma exceção se a lógica for repetida ou for realmente complicada e eu quiser isolá-la. Mas não tenho certeza se estou fazendo a coisa certa aqui.

Qual é a abordagem mais razoável para gerenciar a lógica em um aplicativo ASP.NET moderno típico? Quando é razoável mover seu código para manipuladores de comandos e consultas? Existem padrões melhores?

Atualizar. Encontrei este artigo sobre a abordagem DDD-lite. Portanto, parece que minha abordagem de mover partes complicadas do código para manipuladores de comandos / consultas pode ser chamada de CQRS-lite.

SiberianGuy
fonte
1
Não vejo como o CQRS torna as coisas mais testáveis ​​/ ajuda em singletons / controladores / etc. Eles são em grande parte independentes. Além disso, você ainda está criando um comando no seu exemplo (contador?), O que é estranho.
precisa saber é o seguinte
Se você mantiver seu código com o código de infraestrutura (ou seja, obter o endereço IP do cliente), é difícil testar. Se você isolar a lógica em uma consulta / comando, será muito mais fácil. O exemplo de código era um pouco confuso, então eu o atualizei.
SiberianGuy
1
Consultas e comandos não têm lógica. Eles são DTOs idiotas. Então você tem seus manipuladores de comando / consulta , mas eles são exatamente os mesmos que serviços de aplicativo, interatores, serviços de negócios, o nome dele ... em um contexto não CQRS. Colocar a lógica do aplicativo / caso de uso em um objeto separado do Controlador não é uma coisa específica do CQRS.
precisa saber é o seguinte
Além disso, a questão da dependência injetada versus Singleton é completamente ortogonal ao CQRS. Você poderia ter um controlador de chamar um singleton CommandHandler que chama um singleton Repositório ...
guillaume31
1
@ guillaume31, o CQRS tende a ser mais complicado do que as chamadas de serviço de repositório / aplicativo. Eles geralmente precisam de 2 a 3 classes (ou seja, consulta, manipulador de consultas, resultado da consulta), infraestrutura etc.
Siberian

Respostas:

17

O CQRS é um padrão relativamente complicado e caro? Sim.

É excesso de engenharia? Absolutamente não.

No artigo original em que Martin Fowler fala sobre o CQRS, você pode ver muitos avisos sobre a não utilização do CQRS, onde não é aplicável:

Como qualquer padrão, o CQRS é útil em alguns lugares, mas não em outros.

O CQRS é um salto mental significativo para todos os envolvidos, portanto não deve ser enfrentado, a menos que o benefício valha a pena .

Embora tenha encontrado usos bem-sucedidos do CQRS, até agora a maioria dos casos em que me deparei não foi tão boa ...

Apesar desses benefícios, você deve ter muito cuidado com o uso do CQRS .

... adicionar CQRS a esse sistema pode adicionar complexidade significativa .

Minha ênfase acima.

Se o seu aplicativo está usando o CQRS para tudo, então não é o CQRS que tem excesso de engenharia, é o seu aplicativo. Esse é um excelente padrão para resolver alguns problemas específicos, especialmente aplicativos de alto desempenho / alto volume, nos quais a simultaneidade de gravação pode ser uma grande preocupação.

E pode não ser o aplicativo inteiro, mas apenas uma pequena parte dele.

Como exemplo ao vivo do meu trabalho, empregamos o CQRS no sistema de entrada de pedidos, onde não podemos perder nenhum pedido, e temos picos em que milhares de pedidos vêm ao mesmo tempo de diferentes fontes, em algumas horas específicas. O CQRS nos ajudou a manter o sistema ativo e responsivo, enquanto nos permitia escalar bem os sistemas de back-end para processar esses pedidos mais rapidamente quando necessário (mais servidores de back-end) e mais lento / barato quando não necessário.

O CQRS é perfeito para o problema em que você tem vários atores colaborando no mesmo conjunto de dados ou gravando no mesmo recurso.

Fora isso, espalhar um padrão feito para resolver um único problema para todos os seus problemas criará mais problemas para você.


Alguns outros links úteis:

http://udidahan.com/2011/04/22/when-to-avoid-cqrs/

http://codebetter.com/gregyoung/2012/09/09/cqrs-is-not-an-architecture-2/

Machado
fonte
3
Concorde em tudo, exceto na parte "padrão relativamente complicado e caro". O CQRS está apenas separando leituras de gravações. Você pode fazer isso com fita adesiva, zero middleware / ferramentas complicadas e manter o mesmo banco de dados de antes, apesar de tudo.
precisa saber é o seguinte
@ guillaume31, esse é um ponto justo. Eu acho que isso corresponde à idéia da pergunta original: "na Web API, onde ação é algum tipo de comando / consulta em si". Mas você já viu alguma amostra de CQRS em funcionamento (de preferência no github) que não usa classes separadas para comandos e consultas? É o que encontro quando tento ver como outras pessoas implementam o CQRS no .NET.
SiberianGuy
Sim, mas não é excesso de engenharia. É a premissa básica do padrão - separando consultas de gravações, modelo de leitura de modelo de domínio.
precisa saber é o seguinte
A abordagem CQRS pode ser mais matança em uma série de contextos, mas isso é uma história completamente diferente. Não é um exagero por causa de todos os pequenos detalhes técnicos que você atribui erroneamente ao CQRS no seu Q, é um exagero porque nem sempre você precisa do que o CQRS traz para você.
precisa saber é o seguinte
Eu acho que o argumento de Fowler é válido apenas até certo ponto. O SQL Views é um tipo de CQRS e está conosco por muito tempo e ninguém diz que é muito complexo. Como existem muitos sabores do CQRS, ou seja, projeções de fornecimento de eventos, que podem ser vistas como complexas em algumas áreas, enquanto podem ser triviais em outras.
Alexey Zimarev
3

O CQRS não é um substituto um para um dos Repositórios, exatamente porque é um padrão complexo e caro que só é útil em alguns casos.

Aqui está o que Udi Dahan tem a dizer em mérito:

A maioria das pessoas que usam o CQRS (e a Event Sourcing também) não deveriam ter feito isso.

[...]

Lamento dizer que a maioria dos aplicativos de exemplo que você vê online, mostrando que o CQRS está arquitetonicamente errado. Eu também seria extremamente cauteloso com estruturas que o orientam para um modelo CQRS raiz agregado no estilo de entidade.

( fonte )

Martin Fowler:

[...] você deve ter muito cuidado ao usar o CQRS . Muitos sistemas de informação se encaixam bem com a noção de uma base de informações que é atualizada da mesma maneira que é lida, adicionando o CQRS a esse sistema pode adicionar complexidade significativa.

( fonte )

Finalmente, Greg Young:

O CQRS pode ser chamado de padrão arquitetural.

[...]

Isso é muito importante para entender que a maioria dos padrões arquiteturais não é boa para aplicar em qualquer lugar. Se você vir padrões de arquitetura em uma diretriz de arquitetura, provavelmente terá um problema

[...]

A maior falha que vejo das pessoas que usam o sourcing de eventos é que eles tentam usá-lo em qualquer lugar.

( fonte )

Sklivvz
fonte