Você está certo - copiar e colar funciona muito bem e o DRY não faz sentido em que sua tarefa é produzir um programa para o qual o modelo copiado ou a cópia não precisarão ser mantidos ou evoluídos no futuro. Quando esses dois componentes de software têm um ciclo de vida completamente diferente, acoplá-los ao refatorar o código comum em uma lib comum que está em desenvolvimento pesado pode de fato ter efeitos imprevisíveis para o esforço. Por outro lado, ao copiar seções de código dentro de um programa ou sistema de programa, todas essas partes normalmente terão o mesmo ciclo de vida. Ilustrarei abaixo o que isso significa para DRY e gerenciamento de projetos.
Sério, existem muitos programas por aí: por exemplo, a indústria de jogos de computador produz muitos programas que precisam ser mantidos por um curto período de alguns meses ou um ano no máximo, e quando esse tempo termina, copiar e colar código antigo de um jogo anterior em que o período de manutenção é excedido, a base de código de um novo jogo é perfeitamente adequada e pode acelerar as coisas.
Infelizmente, o ciclo de vida da maioria dos programas com os quais tive que lidar nos últimos anos é muito diferente disso. 98% dos requisitos ou solicitações de correção de erros que me chegaram foram solicitações de alteraçãopara programas existentes. E sempre que você precisar alterar algo em um software existente, "gerenciamento de projetos" ou planejamento funcionará melhor quando seus esforços de teste e depuração forem muito baixos - o que não será o caso se você alterar algo em um só lugar, mas devido à cópia lógica de negócios bem planejada, você esquece facilmente que também precisa mudar uma dúzia de outros lugares na base de código. E mesmo que você consiga encontrar todos esses lugares, o tempo para alterá-los todos (e testar as alterações) provavelmente é muito maior, como se você tivesse apenas um lugar para trocar. Assim, mesmo você pode fazer uma estimativa precisa da mudança, tendo os custos uma dúzia de vezes mais altos do que o necessário, podendo facilmente colidir com o orçamento do projeto.
TLDR - sempre que você desenvolver um programa em que não haja necessidade ou responsabilidade pela correção de erros e manutenção do original ou da cópia, fique à vontade para copiar. Mas se você, sua equipe ou sua empresa for ou puder se tornar responsável, aplique DRY sempre que puder.
Exemplo
Como adendo, deixe-me explicar o que significa "correção e manutenção de bugs" e como isso leva a imprevisibilidade no planejamento, especialmente dentro de um produto, por um exemplo do mundo real. Eu realmente vi esse tipo de coisa acontecer na realidade, provavelmente não com 100 instâncias, mas os problemas podem começar quando você tem apenas uma instância duplicada.
A tarefa: criar 100 relatórios diferentes para um aplicativo, cada relatório parecendo muito semelhante, algumas diferenças de requisitos entre os relatórios, alguma lógica diferente, mas, no geral, poucas diferenças.
O desenvolvedor que obtém essa tarefa cria a primeira (digamos que leva três dias). Após algumas alterações ou pequenas correções de erros devido ao controle de qualidade e à inspeção do cliente, parece que está funcionando bem. Então ele começou a criar o próximo relatório copiando e colando a coisa toda, depois o próximo, e para cada novo relatório ele precisa de aproximadamente 1 dia em média. Muito previsível, à primeira vista ...
Agora, depois que os 100 relatórios estiverem "prontos", o programa será produzido de maneira real e ocorrerão alguns problemas que foram ignorados durante o controle de qualidade. Talvez haja problemas de desempenho, talvez os relatórios falhem regularmente, talvez outras coisas não funcionem conforme o esperado. Agora, quando o princípio DRY foi aplicado, 90% desses problemas poderiam ser resolvidos alterando a base de código em um único local. Mas, devido à abordagem de copiar e colar, o problema deve ser resolvido 100 vezes em vez de uma vez. E devido às alterações já aplicadas de um relatório para outro, o desenvolvedor não pode copiar e colar rapidamente a correção do primeiro relatório para o outro 99. Ele deve examinar todos os 100 relatórios, lê-los, traduzir a alteração para o modificado relatório, teste e talvez depure cada um individualmente. Para o PM, isso começa a ficar muito difícil - ele pode, naturalmente, dedicar um tempo para uma correção de erro "regular" (digamos, 3 horas) e multiplicar por 100, mas, na verdade, essa é provavelmente uma estimativa incorreta, algumas das correções podem ser mais fácil de fazer do que outros, outros podem ser mais difíceis. E mesmo que essa estimativa esteja correta, o custo da depuração 100 vezes mais alto do que era necessário custará muito dinheiro à empresa.
O mesmo acontecerá na próxima vez em que o cliente solicitar a alteração da cor do emblema da empresa em todos esses relatórios, para tornar o tamanho da página configurável ou por algum outro novo requisito que afete todos os relatórios de maneira semelhante. Portanto, se isso acontecer, você pode fazer uma estimativa dos custos e cobrar do cliente 100 vezes o preço que ele teria que pagar quando o código estivesse SECO. No entanto, tente isso algumas vezes e, em seguida, o cliente cancelará o projeto porque provavelmente não estará disposto a pagar seus custos exorbitantes de desenvolvimento. E talvez nesse momento alguém faça a pergunta por que isso aconteceu e aponte com o dedo a pessoa que tomou a decisão para esta programação de copiar e colar.
O que quero dizer é: quando você produz software para terceiros, sempre tem pelo menos por um curto período de tempo a responsabilidade de fazer a coisa funcionar, corrigir bugs, adaptar o programa às mudanças de requisitos etc. Mesmo em um projeto de campo verde, essas as peças podem adicionar rapidamente muito mais do que o esforço de desenvolvimento planejado inicialmente. E especialmente quando todo o seu código copiado e colado está dentro de um produto, o período de responsabilidade é o mesmo para todas as partes, o que é bastante diferente da situação em que você copiou um código antigo de um projeto morto que não é mais sob manutenção ativa.