Eu tenho que comprometer: DRY, ou Command-Query-Separation?

10

Recentemente, refatorava um método que era um comando e um método de consulta.

Depois de separá-lo em um método de comando e um método de consulta, descobri que agora existem vários locais no código em que estou chamando o comando e obtendo o valor da consulta, o que parece uma violação do princípio DRY.

Mas se eu envolvesse esse código comum em um método, esse método seria um comando e uma consulta. Isso é aceitável?

Kris Welsh
fonte
ok, não sabia se a comunidade estava em consenso e não encontrei nenhuma discussão sobre esse tópico.
Kris Welsh
É mais comumente chamados CQRS google.com.au/...
Daniel Little
@ DanielLittle - não, não é. CQS e CQRS são assuntos distintamente diferentes. O CQRS é um padrão de arquitetura muito mais envolvido, enquanto o CQS é mais de padrão de design e muito mais fácil de entender e implementar. Veja codebetter.com/gregyoung/2009/08/13/command-query-separation
Erik Funkenbusch
@Erik Funkenbusch Você está certo
Daniel Little

Respostas:

11

Sempre há trocas a serem consideradas entre princípios de design conflitantes. A maneira de resolvê-lo é examinar as razões subjacentes aos princípios. Nesse caso, não é possível executar uma consulta sem executar o comando, mas é incapaz de executar um comando sem executar a consulta geralmente é inofensivo. Contanto que haja uma maneira de executar a consulta autônoma, não vejo razão para não adicionar o resultado da consulta ao comando, especialmente se for feito algo como isto:

QueryResult command()
{
   // do command stuff
   return query();
}
Karl Bielefeldt
fonte
4

Eu nunca ouvi falar em CQS (Command-Query-Separation) antes, mas parece que ele se relacionaria com o Princípio de Responsabilidade Única (SRP), que afirma que uma função / classe idealmente deve ser responsável por fazer uma coisa e apenas uma coisa .

Se o seu código de comando tiver 20 linhas de código e o código de consulta tiver outras 30 linhas e todos eles estiverem em um corpo de função, claramente você está violando o SRP e eu assumiria o CQS também e essas duas partes da lógica devem ser separadas uma da outra .

No entanto, seguindo o seu exemplo hipotético, provavelmente criaria um método de wrapper que combinaria seu comando e consulta para que DRY não seja violado em vários locais do código. Eu também não consideraria isso uma violação ao SRP (e talvez CQS), porque o wrapper ainda tem apenas uma responsabilidade: combinar comando com uma consulta e criar uma abstração de nível superior que seja mais fácil de consumir.

Eu acho que o método wrapper é uma solução perfeitamente aceitável e para ilustrar isso, vamos dar um exemplo adiante. E se você tivesse que executar 2 consultas em vez de 1 e executar uma ação de comando com base nisso. Portanto, suas 2 linhas de código seriam 6 ou 8. E se houvesse alguma validação / verificação de dados entre uma e outra, agora você tem 15 linhas de código. Você pensaria duas vezes antes de criar um wrapper que faça tudo isso, em vez de espalhar essas 15 linhas em vários arquivos?

DXM
fonte
Eu acho que o "princípio único" de um invólucro deve ser manter os outros métodos que precisam do comando e da consulta juntos DRY.
Droogans
Google CQRS: google.com.au/…
Daniel Little
Embora a solução de Karl para esse problema seja melhor, acho a sua elaboração de funções mais longas do wrapper um ponto muito bom.
Kris Welsh
-3

O DRY é mais importante, pois resolve uma necessidade muito mais fundamental - evitando esforços redundantes e efetivamente desperdiçados. Isso é fundamental - não é preciso ser um programador para entendê-lo.

O CQS é uma resposta à dificuldade, em idiomas sem suporte para efeitos de rastreamento, de entender o código que é executado tanto por seus resultados quanto por seus efeitos. Contudo:

  1. A necessidade de executar código para seus resultados não pode ser evitada, porque essa é a base para compor programas grandes a partir de pequenas unidades.

  2. A necessidade de executar código para seus efeitos também não pode ser evitada, porque, fora da matemática e da ciência da computação teórica, o valor de executar um programa reside no que ele pode fazer por nós.

  3. A necessidade de causar efeitos e produzir resultados no mesmo código não pode ser evitada, porque, na prática, precisamos de efeitos e composição, não apenas um ou outro.

A solução real para o problema de rastrear os efeitos ser muito difícil para humanos não assistidos é, é claro, ter computadores que nos ajudem ! O mesmo pode ser dito sobre o rastreamento de relacionamentos complexos entre valores de tempo de execução (como a validade dos índices da matriz), para os quais exceções e contratos impostos pelo tempo de execução constituem soluções (não).

Em conclusão, "soluções" como o CQS apenas atrapalham a criação de programas de acordo com princípios sólidos baseados na realidade. Vá para seco.

pyon
fonte
Às vezes, você precisa evitar o acoplamento para diminuir a complexidade. Você deve dar uma olhada no CQRS.
Daniel Little1 de
@Lavinski: A melhor ferramenta para evitar a complexidade (sem diminuí-la, que é inútil) é a abstração - dissociando a essência genérica dos problemas que estamos resolvendo dos detalhes específicos das instâncias dos referidos problemas genéricos. Receitas mágicas (ou "padrões de design", como soube que são chamadas) podem, na melhor das hipóteses, impedir que você cause muitos danos quando você errar o design, mas não podem transformar um design errado no correto.
Aug13
@Lavinski: No que diz respeito especificamente ao CQRS, a solução alternativa conceitualmente correta é 1. entender o modelo de dados (nenhuma quantidade de camadas de objetos pode eliminar a necessidade disso), 2. codificar o máximo de propriedades de correção possível no esquema do banco de dados. (Infelizmente, RDBMSes mais populares fornecer suporte limitado para o último, para não mencionar os NoSQL, que recebem este Minha pesquisa ainda mais errada atual está fornecendo uma solução melhor para isso..)
pyon
O CQRS funciona completamente de acordo com o Design Orientado a Domínio. Sugiro que você faça um pouco de pesquisa. O domínio dentro do aplicativo deve impor a correção, não o armazenamento de dados.
Daniel Little
1
@ EduardoLeón: Se você quiser provar que seu design está correto, tente escrever testes para o seu programa. Posso garantir que jogar o CQS apenas prejudicará seus esforços nisso.
Stefan Billiet