Às vezes, a duplicação de código é o resultado de um "trocadilho": duas coisas parecem iguais, mas não são.
É possível que o excesso de abstração possa quebrar a verdadeira modularidade do seu sistema. Sob o regime da modularidade, você precisa decidir "o que provavelmente mudará?" e "o que é estável?". Tudo o que é estável é colocado na interface, enquanto o que é instável é encapsulado na implementação do módulo. Então, quando as coisas mudam, a alteração que você precisa fazer é isolada para esse módulo.
A refatoração é necessária quando o que você achou estável (por exemplo, essa chamada da API sempre leva dois argumentos) precisa mudar.
Então, para esses dois fragmentos de código duplicados, eu perguntaria: uma alteração necessária para um significa necessariamente que o outro também deve ser alterado?
Como você responde a essa pergunta pode fornecer uma melhor visão sobre o que pode ser uma boa abstração.
Os padrões de design também são ferramentas úteis. Talvez seu código duplicado esteja percorrendo alguma forma e o padrão do iterador deva ser aplicado.
Se o seu código duplicado tiver vários valores de retorno (e é por isso que você não pode executar um método simples de extração), talvez você deva criar uma classe que contenha os valores retornados. A classe poderia chamar um método abstrato para cada ponto que varia entre os dois fragmentos de código. Você faria duas implementações concretas da classe: uma para cada fragmento. [Este é efetivamente o padrão de design do Método de Modelo, que não deve ser confundido com o conceito de modelos em C ++. Como alternativa, o que você está vendo pode ser melhor resolvido com o padrão Estratégia.]
Outra maneira natural e útil de pensar sobre isso é com funções de ordem superior. Por exemplo, criando lambdas ou usando classes internas anônimas para que o código passe para a abstração. Geralmente, você pode remover a duplicação, mas, a menos que exista realmente uma relação entre elas [se uma mudar, a outra deve mudar], você poderá estar prejudicando a modularidade, sem ajudá-la.
Pessoalmente, eu o ignoro e segui em frente. As chances são de que, se for um caso estranho, é melhor duplicá-lo, você pode passar anos refatorando e o próximo desenvolvedor dará uma olhada e desfará sua alteração!
fonte
Sem um exemplo de código, é difícil dizer por que seu código não possui abstração prontamente identificável. Com essa ressalva, aqui estão algumas idéias:
A maior dificuldade deste exercício é que sua função provavelmente está incorporando muitos comportamentos não relacionados em um determinado nível de abstração e você precisa lidar com alguns deles em níveis mais baixos. Você supõe corretamente que a clareza é essencial para manter o código, mas tornar o comportamento do código claro (sua condição atual) é muito diferente de tornar clara a intenção do código.
Torne abstrato o como das partes de código menores, fazendo com que suas assinaturas de função identifiquem o quê, e as partes maiores devem ser mais fáceis de classificar.
fonte