Repetição de código vs método multi-responsável


11

Tento seguir o Princípio de responsabilidade única (SRP) e também omitir repetições de código. No entanto, geralmente existem lugares onde há repetições de código que nada mais são do que blocos de invocações de código que são resistentes a extraí-las para um método nomeado pelo menos significativo:

DoAction1();
DoAction2();

if (value)
    DoAction3();

DoAction4();

Qual é a melhor maneira de extrair esse código em um método e como nomeá-lo?


1
Por que eles são resistentes a serem extraídos em um método significativo diferente?
Chandranshu

Todas as ações fazem algo não relacionado. Eu teria que escrever: void MethodThatDoAction1ThenAction2AndAction3IfValueAndThenAction4(). Eu preferiria ver mais significado em: CodeBlock1().
yBee

4
Então é apenas uma questão de nomear corretamente o método extraído, certo? Receio que não haja uma solução universal e você terá que fazer isso caso a caso. Se você está repetindo exatamente esse mesmo pedaço de código em mais de um lugar, é provável que haja um significado para suas ações e você precisa procurar muito (pode ser discutido) para encontrar esse significado e dar um nome a ele.
Chandranshu

1
Se houver algum consolo, o vencedor do Spring para nomes de classes longas AbstractInterruptibleBatchPreparedStatementSetteré apenas um pouco menor que o seu método.
Chandranshu

1
@ Chandranshu Eu acredito que seus comentários funcionariam bem como resposta a esta pergunta.
Simon Forsberg

Respostas:


13

Eu acho que é apenas uma questão de nomear corretamente o método extraído. Receio que não haja uma solução universal e você terá que fazer isso caso a caso. Se você está repetindo exatamente esse mesmo pedaço de código em mais de um lugar, é provável que haja um significado para suas ações e você precisa procurar muito (pode ser discutido) para encontrar esse significado e dar um nome a ele.

Se houver algum consolo, o vencedor da Primavera para nomes de classes longas é o de AbstractInterruptibleBatchPreparedStatementSetter49 caracteres.


11

Na verdade, você está sofrendo da tarefa mais difícil que um programador pode fazer - Naming Things . Desculpe por uma resposta tão madura, mas não pude resistir. Você pode descobrir que muitas pessoas sofrem com isso , mesmo na internet você pode encontrar esse tipo de ensaio .

Agora, se o seu código repetitivo estiver reunido, resultando em um trabalho e esses métodos não estiverem sendo usados ​​por outros métodos, eles serão simplesmente o método Helpers e o método resultante poderá ser nomeado como doXXXou makeXXX... Acho que você entendeu o ponto.

Como Chandranshu disse: "Se você está repetindo esse [...] significado e dê um nome a ele". é direto ao ponto e apropriado.

insira a descrição da imagem aqui

Pic cortesia: CodeChef Facebook Page Photo


2

Acho que você está levando o princípio da repetição de código longe demais. Pense no ponto de evitar a repetição de código. O objetivo é reduzir a quantidade de código que deve ser verificada quando houver uma alteração na lógica e aumentar a compreensão fatorando blocos obviamente similares.

As falhas de fatorar para evitar a repetição são que, se um dos blocos compartilhados precisar mudar, agora você precisará de uma herança ainda mais complexa ou de alguma alternância entre a implementação padrão e a não-padrão.

Portanto, avalie cuidadosamente a possibilidade de a lógica de um desses blocos mudar sem os outros, contra os benefícios de compreensão obtidos ao considerar essa semelhança. Se uma implementação puder se separar das outras, é melhor você repetir o código.

Enquanto mantém esse código repetido, à medida que se torna mais complexo e o domínio do problema se torna mais definido, você pode achar mais apropriado fatorar as seções repetidas, agora mais complexas, mas também mais definidas.

Normalmente, tento manter a uniformidade do editor de texto por um tempo até ver se algo que parece repetitivo acaba valendo a pena ser fatorado. Eu apenas mantenho a repetição, mas olho para o futuro desse bloco, mantendo textualmente fácil a correspondência mais tarde.

Na maioria das vezes, a mesma coisa e o possível fatoramento começam a se dissipar, como reais, caprichosas, regras de negócios e lógica altamente dependente, muitas vezes arbitrária; como lidar com as esquisitices de várias implementações comuns de banco de dados (ANSI_NULLS ou algumas delas vêm à mente); forçando o que parecia ser uma lógica pura a uma confusão distorcida, tentando fornecer uma lógica de decisão razoável e defensável quando confrontada com a confusão do estado da indústria.

Parece-me que se as pessoas tentassem calcular o que você está tentando calcular, teríamos uma biblioteca inteira de construções inúteis como Do1Then2If2False Do1IfTrueDo2.

Tem que ser mais complexo e mais claro que o bloco não vai mudar para garantir a sua contabilização.

É software . Você pode voltar e editar alguns blocos iguais agora. Vai demorar 5 minutos. E você pode economizar horas gastando em fatoração desperdiçada e, em seguida, mais horas em herança desperdiçada e desenvolvimento de comutação, deixando-o e certificando-se de ter um bom teclado anti-RSI.


I como a parte que extrai a essência da repetição de código: para reduzir a quantidade de código que tem de ser verificada quando há uma mudança na lógica
yBee

1

Se você está realmente seguindo o Princípio de responsabilidade única, esse bloco de código deve ter algum objetivo específico, certo? Caso contrário, esses métodos estariam em classes separadas.

Então, qual é o objetivo desse bloco de código? Determine isso e você poderá criar um nome.

Se você ainda não consegue descobrir o nome dessa coisa, talvez esses métodos não pertençam realmente juntos. Ou seja, esse bloco de classe / código tem mais de uma responsabilidade. Nesse caso, refatorar para dividir as tarefas pode revelar um nome melhor para a finalidade.


1

Eu tive uma situação que pode ser semelhante à sua:

Há uma classe que define a funcionalidade do objeto que ele representa:

class Functionality
{
protected:
void functionA();
void functionB();
...
void functionZ();
}

Depois, há uma classe que define os fluxos de trabalho para operações de alto nível que o objeto executa:

class Workflows: private Functionality
{
    void WorkflowA()
    {
        functionA();

        if (m_bValue) {
            functionB();
        }

        functionC();
    }
    ...
    void WorkflowB();
}

Se você estiver em uma situação semelhante, identifique o que suas classes representam (nesse caso, funcionalidade / fluxos de trabalho) e, em seguida, nomeie os métodos de acordo.

Isenção de responsabilidade: os nomes de classe usados ​​neste exemplo são muito imprecisos, mas os nomes dos métodos fornecem uma pista. Discrição recomendada.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.