[Conceitos] Command-Query Separation (CQS)

Blz, pessoal?

Retornando com mais um conceito neste post curto. Desta vez, falarei sobre o Command-Query Separation (CQS), princípio proposto por Bertrand Meyer.

Este princípio diz que um método pode ser um comando ou uma query, mas nunca ambos.

Um comando é um método que altera o estado do objeto que o define, não retornando nenhum valor:

public void AlterarEndereco(Endereco novoEndereco)
{
    this.endereco = novoEndereco;
}

Já uma query retorna algum resultado sem alterar o estado do objeto que a define. Em outras palavras, queries são funções livres de efeitos colaterais (side-effect-free functions):

public double CalcularMedia()
{
    return (this.X + this.Y) / 2;
}

Seguindo essa guideline, seus métodos ficam mais claros e com um único objetivo (o Princípio da Responsabilidade Única também deve ser considerado em métodos).

Além disso, eles passam a ser mais confiáveis. Uma query pode ser chamada mais de uma vez em sequência sem resultados indesejados. Outra forma de pensar sobre isso é que “uma query responde uma pergunta e responder uma pergunta não pode alterar a resposta”.

Portanto, vale a pena considerar esse princípio ao escrevermos nosso código.

Já consideraram? Quais os exemplos mais comuns que quebram esse princípio?

Até a próxima!

Anúncios

10 comentários em “[Conceitos] Command-Query Separation (CQS)

  1. Bem legal esse conceito!
    O padrão Find or Create não vai totalmente contra esse conceito?

    1. Olá, Francisco!

      Se seu método não altera o estado do objeto, ele continua atendendo o CQS (continua sendo uma query), pois ele não tem efeitos colaterais (você poderia chamar o método 2 vezes, por exemplo, que o resultado seria o mesmo), mesmo que ele esteja fazendo isso ora buscando um já existente, ora criando um novo.

      Ficou claro?
      Qualquer coisa, estamos aí.
      []s!

      1. Entendi sim, valeu pela explicação! Ficou bem claro e didático, parabéns pelo post, bem legal 🙂

  2. Haha! Martin Fowler deu um ótimo exemplo de quebra desse principio no Java, no C# poderíamos considerar o MoveNext do IEnumerator, Retorna True ou False, e move o enumerador para próxima posição, não sei se entraria no caso os métodos Try[AlgumaCoisa] da vida. Bom, o próprio Meyer disse que há exceções a esse princípio não? Que no caso seria:
    Desafio qualquer um a dar um ‘pop’ numa ‘stack’ sem quebrar esse principio.

    1. Parabéns!! 🙂
      Pois é, tem coisas mais conceituais que acabam sendo assim. Se está desempilhando já entrega o item retirado da pilha (“Normal”).

      Enfim, o CQS é um ótimo guia a se seguir pra escrever código limpo, mas tudo tem suas exceções.

      []s

  3. E como eu lidaria, com a lógica de comandos em linguagens dinâmicas, que sempre retornam algo, estilo ruby,
    Que sempre no final do método retorna a última linha, se não tiver um return explícito.
    Por exemplo o método alterarEndereço retornaria o endereço atualizado, lógico que eu tenho a opção de não utilizá-lo, e quando eu precisasse eu teria outro método query que me retornaria o novo endereço, porém eu não estaria não utilizando recursos da linguagem?

    1. Oi, Carlos

      A questão é: Por que eu usaria esse retorno, ie, por que eu faria “retorno = cliente.alterar_endereco(novo_endereco)” já que eu mesmo passei o novo endereço?
      Como você mesmo disse, eu simplesmente ignoro. Quanto a não utilizar recursos da linguagem, às vezes faz sentido não usar mesmo. Agora, não sou expert em Ruby, então deve haver situações onde essa característica da linguagem faça muito sentido.

      Independente dessa característica, acredito que o método não fere o CQS, já que você não está deliberadamente retornando algo, além de alterar o estado do objeto.

      E, por fim, creio que o cenário mais critico seja o inverso: quando seu método é aparentemente uma query (.calcular_media_do_blablabla ou .obter_blabla) e lá dentro ocorre algum side-effect.

      Qualquer coisa, comenta aí!
      []s

Participe! Vamos trocar uma ideia sobre desenvolvimento de software!

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair /  Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair /  Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair /  Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair /  Alterar )

w

Conectando a %s