Aikido

Como eliminar a duplicação de código: reduzir a dívida técnica

Erro de lógica

Regra
Eliminar óbvio dentro do ficheiro duplicação.
O código código blocos aumentam a manutenção
manutenção e o risco de incoerência actualizações inconsistentes.
Idiomas suportados: 45+

Introdução

O código copiado e colado num único ficheiro cria pesadelos de manutenção que se agravam com o tempo. Quando a mesma lógica aparece em vários locais, as correcções de erros e as actualizações de funcionalidades têm de ser aplicadas a todas as ocorrências. Os desenvolvedores inevitavelmente perdem uma das duplicatas, levando a um comportamento inconsistente em que a mesma operação produz resultados diferentes, dependendo do caminho do código executado. Essa inconsistência é difícil de depurar porque a lógica duplicada parece idêntica à primeira vista, e as diferenças só surgem após uma comparação cuidadosa.

Porque é importante

Propagação de erros: Quando um bug existe em código duplicado, corrigi-lo num local não o corrige em todo o lado. Os programadores corrigem a primeira ocorrência sem se aperceberem que existem cópias noutros locais, deixando o erro ativo em condições diferentes.

Carga de manutenção: Cada bloco duplicado duplica o custo de manutenção. Alterar a lógica exige encontrar e atualizar todas as cópias e, à medida que os ficheiros crescem, torna-se mais difícil localizar os duplicados.

Exemplos de código

Não conforme:

class OrderProcessor {
    async processStandardOrder(order) {
        if (!order.items || order.items.length === 0) {
            throw new Error('Order must have items');
        }
        const total = order.items.reduce((sum, item) => 
            sum + (item.price * item.quantity), 0);
        const tax = total * 0.08;
        const finalAmount = total + tax;
        return { total: finalAmount, tax };
    }
    
    async processExpressOrder(order) {
        if (!order.items || order.items.length === 0) {
            throw new Error('Order must have items');
        }
        const total = order.items.reduce((sum, item) => 
            sum + (item.price * item.quantity), 0);
        const tax = total * 0.08;
        const expressfee = 15.99;
        const finalAmount = total + tax + expressFee;
        return { total: finalAmount, tax, expressFee };
    }
}

Porque é que está errado: A lógica de validação e o cálculo do total são duplicados. Se a taxa de imposto for alterada ou a validação precisar de ser melhorada, ambos os métodos necessitam de actualizações. Um programador pode atualizar o cálculo do imposto num método mas esquecer-se do outro, causando preços inconsistentes.

Conformidade:

class OrderProcessor {
    validateOrder(order) {
        if (!order.items || order.items.length === 0) {
            throw new Error('Order must have items');
        }
    }
    
    calculateSubtotal(items) {
        return items.reduce((sum, item) => 
            sum + (item.price * item.quantity), 0);
    }
    
    calculateTax(amount) {
        return amount * 0.08;
    }
    
    async processStandardOrder(order) {
        this.validateOrder(order);
        const subtotal = this.calculateSubtotal(order.items);
        const tax = this.calculateTax(subtotal);
        return { total: subtotal + tax, tax };
    }
    
    async processExpressOrder(order) {
        this.validateOrder(order);
        const subtotal = this.calculateSubtotal(order.items);
        const tax = this.calculateTax(subtotal);
        const expressFee = 15.99;
        return { total: subtotal + tax + expressFee, tax, expressFee };
    }
}

Por que isso é importante: A validação, o cálculo e a lógica do imposto são centralizados em métodos únicos. Alterar a taxa de imposto significa modificar um método, e não procurar duplicatas no arquivo. Cada método auxiliar pode ser testado independentemente, e ambos os tipos de pedido herdam automaticamente quaisquer melhorias ou correções de erros.

Conclusão

A duplicação dentro de um ficheiro é frequentemente a mais fácil de corrigir e proporciona benefícios imediatos. Extraia a lógica duplicada para funções ou métodos auxiliares assim que notar o padrão. A regra de três sugere que quando o código aparece três vezes, é altura de refactorizar. Não espere que a duplicação se espalhe por todo o ficheiro antes de a resolver.

FAQs

Tem perguntas?

Que quantidade de duplicação é aceitável antes da refacção?

A regra de três é uma boa orientação: se um código semelhante aparecer três vezes, extraia-o. No entanto, use o seu discernimento. Dois blocos complexos duplicados podem justificar a extração imediata, enquanto três simples declarações de variáveis podem não o fazer. Considere a probabilidade de mudança e o custo da inconsistência. A lógica crítica de segurança ou regras comerciais complexas devem ser deduplicadas imediatamente.

E se o código duplicado tiver pequenas variações?

Parametrize as diferenças. Se dois blocos de código diferirem apenas nos valores das variáveis, passe-os como parâmetros para uma função partilhada. Se o fluxo lógico diferir ligeiramente, utilize um padrão de estratégia ou parâmetros opcionais com predefinições sensatas. Às vezes, a duplicação com diferenças claras é melhor do que uma abstração complexa que obscurece a intenção, portanto, equilibre os princípios DRY com a legibilidade.

Devo extrair a duplicação mesmo que isso torne o código mais longo?

Normalmente, sim. Uma função com um nome descritivo clarifica muitas vezes melhor a intenção do que o código duplicado em linha, mesmo que o número total de linhas aumente. Os benefícios da manutenção de um ponto único superam as preocupações com a brevidade. No entanto, se a extração criar uma indirecção excessiva em que a leitura do código exija passar por várias chamadas de função, reconsidere se a abstração é adequada.

Como é que identifico código duplicado em ficheiros grandes?

Procure por padrões de copiar e colar, como condições if repetidas, loops idênticos ou estruturas de função semelhantes. Muitos IDEs destacam a duplicação estrutural. Durante a revisão do código, se você vir um código familiar ao ler um arquivo, procure por ele. A inspeção manual é frequentemente mais rápida para a duplicação dentro do ficheiro. Ao refatorar, comece com as duplicatas mais óbvias que aparecem próximas umas das outras no arquivo.

E quanto ao código de tratamento de erros duplicado?

Extraia o tratamento de erros para funções reutilizáveis ou utilize decoradores/padrões de middleware. Se várias funções partilham a mesma estrutura try-catch com registo e transformação de erros idênticos, vale a pena eliminar essa duplicação. Crie utilitários de tratamento de erros que envolvam operações com registo consistente, novas tentativas ou comportamento de recurso e, em seguida, utilize esses utilitários em vez de repetir a lógica de tratamento de erros.

Vale a pena refactorizar a duplicação em código legado que não estou a alterar ativamente?

Aplique a regra dos escuteiros: deixe o código mais limpo do que o encontrou, mas não refactorize o código em que não está a tocar. Se estiver a modificar uma função e notar uma duplicação no mesmo ficheiro, corrija-a como parte da sua alteração. Não crie grandes PRs de refatoração para código legado, a menos que a dívida técnica esteja bloqueando novos recursos. A melhoria incremental durante o desenvolvimento normal é mais sustentável.

Como é que evito a duplicação em primeiro lugar?

Antes de copiar e colar código, pergunte se deve extrair uma função. Durante a revisão do código, assinale os padrões duplicados e solicite a extração. Estabeleça convenções de equipa que desencorajem a duplicação, como exigir funções auxiliares para operações repetidas mais de duas vezes. Utilizar listas de verificação de revisão de código que procurem especificamente a duplicação. A prevenção é mais fácil do que a correção.

Obter segurança gratuitamente

Proteja seu código, nuvem e tempo de execução em um sistema central.
Encontre e corrija vulnerabilidades rapidamente de forma automática.

Não é necessário cartão de crédito | Resultados do scan em 32secs.