Violação do princípio DRY

10

Tenho certeza de que há um nome para esse anti-padrão em algum lugar; no entanto, não estou familiarizado o suficiente com a literatura antipadrão para conhecê-lo.

Considere o seguinte cenário:

or0é uma função de membro em uma classe. Para o melhor ou para o pior, depende muito das variáveis ​​dos membros da classe. O Programador A aparece e precisa de funcionalidades como, em or0vez de chamar or0, o Programador A copia e renomeia a classe inteira. Suponho que ela não ligue or0porque, como eu digo, depende muito das variáveis ​​de membro para sua funcionalidade. Ou talvez ela seja uma programadora júnior e não saiba como chamá-la de outro código. Então agora temos or0e c0(c para cópia). Não posso culpar completamente o programador A por essa abordagem - todos temos prazos apertados e hackeamos o código para concluir o trabalho.

Vários programadores mantêm or0a versão agora orN. c0agora é a versão cN. Infelizmente, a maioria dos programadores que mantinham a classe contendo or0parecia desconhecer completamente - qual c0é um dos argumentos mais fortes que posso pensar pela sabedoria do princípio DRY. E também pode ter havido manutenção independente do código em c. De qualquer forma, parece que or0e c0foram mantidas independentes um do outro. E, alegria e felicidade, um erro está ocorrendo no cNque não ocorre orN.

Então, eu tenho algumas perguntas:

1.) Existe um nome para esse anti-padrão? Eu já vi isso acontecer com tanta frequência que acho difícil acreditar que esse não seja um anti-padrão nomeado.

2.) Eu posso ver algumas alternativas:

a.) Corrija orNpara obter um parâmetro que especifique os valores de todas as variáveis ​​de membro necessárias. Em seguida, modifique cNpara chamar orNcom todos os parâmetros necessários passados.

b.) Tente portar manualmente as correções de orNpara cN. (Lembre-se de que não quero fazer isso, mas é uma possibilidade realista.)

c.) Recopie orNpara - cNnovamente, eca, mas eu listo por uma questão de completude.

d.) Tente descobrir onde cNestá quebrado e, em seguida, repare-o independentemente orN.

A alternativa a parece ser a melhor correção a longo prazo, mas duvido que o cliente me permita implementá-la. Nunca tempo ou dinheiro para consertar as coisas direito, mas sempre tempo e dinheiro para consertar o mesmo problema 40 ou 50 vezes, certo?

Alguém pode sugerir outras abordagens que eu talvez não tenha considerado?

Onorio Catenacci
fonte
"Existe um nome para esse anti-padrão?" O anti-padrão 'violador-seco'? :) IMHO você praticamente respondeu você mesmo.
Steven Jeuris
Talvez chame de "O Violador Seco"?
FrustratedWithFormsDesigner
2
Eu chamo: colisão a seco.
AJC 12/09
5
Copiar e colar codificação?
tylermac
É chamado de "muitos cozinheiros estragam o caldo".
Doc Brown)

Respostas:

18
  1. é apenas chamado de código duplicado - não conheço mais nomes sofisticados para isso. As consequências a longo prazo são as que você descreveu e são piores.

  2. Obviamente, eliminar a duplicação é a opção ideal, se possível. Pode levar muito tempo (em um caso recente em nosso projeto legado, eu tive vários métodos duplicados em mais de 20 subclasses em uma hierarquia de classes, muitos dos quais evoluíram evolutivamente suas pequenas diferenças / extensões ao longo dos anos. cerca de 1,5 anos através de sucessivas redações e refatoração de testes unitários para eliminar todas as duplicações.

    Nesse caso, você ainda pode precisar de uma ou mais das outras opções como correções temporárias, mesmo se decidir começar a eliminar a duplicação. No entanto, qual deles é melhor depende de muitos fatores e, sem mais contexto, estamos apenas tentando adivinhar.

    Muitas pequenas melhorias podem fazer uma grande diferença a longo prazo. Você também não precisa necessariamente da aprovação explícita do cliente - uma pequena refatoração toda vez que você toca na classe para corrigir um bug ou implementar um recurso pode percorrer um longo caminho ao longo do tempo. Apenas inclua algum tempo extra para refatoração nas estimativas de tarefas. É como a manutenção padrão para manter o software saudável a longo prazo.

Péter Török
fonte
3
+1, se não apenas pela menção de código duplicado, mas pelo simples esforço envolvido em sua história de refatoração de código. : D
Andreas Johansson
9

Há uma referência ao padrão WET (We Enjoy Typing), mas não sei se é um nome padrão.

... O licenciamento de software é uma exceção notável à prática DRY (não se repita) - o código de licenciamento de software deve ser o mais úmido possível (gostamos de digitar - o oposto de DRY).

Se você isolar sua lógica de licenciamento em um local, separado de outras preocupações, facilitará muito a modificação do software para desativar completamente o licenciamento. É muito melhor repetir a lógica de licenciamento muitas vezes em todo o aplicativo, de preferência para que seja executada várias vezes em uma única execução do software.

Por exemplo, sugerimos que você execute uma verificação de licenciamento durante a instalação, durante a inicialização do aplicativo e sempre que recursos importantes forem acessados. Não verifique a licença uma vez durante a inicialização e repasse esse valor; em vez disso, replique a verificação de licenciamento em cada área. É inconveniente, mas muito melhor do que lançar um produto fácil de quebrar ...

jeremy-george
fonte
3
WET pode significar: Escreva tudo duas vezes
StuperUser
11
@StuperUser Eu descobri isso no dailywtf ontem ... #
jeremy-george
3

Se eu entendi direito, há muita coisa acontecendo na classe. Isso cria métodos que não seguem o princípio da responsabilidade única . Levando ao código que precisa ser movido, pedaços retirados enquanto outros são deixados de fora. Isso também pode criar muitos membros.

Você também deve revisar os modificadores de acessibilidade. Garanta que as coisas públicas sejam de fato públicas. O consumidor não precisa saber sobre cada pequeno membro ... use o encapsulamento.

Isso exige um refator. Parece também que o código está sendo escrito sem design inicial. Veja o desenvolvimento orientado a testes. Escreva o código como deve ser chamado, em vez de chamar o código, no entanto, ele é implementado. Veja no TDD algumas dicas de como realizar a tarefa.

P.Brian.Mackey
fonte
3

Se você estiver copiando código, apresentará uma dívida técnica de manutenção dupla ou mais especificamente: duplicação de código .

Geralmente isso é corrigido através da refatoração. Mais especificamente, você redireciona todas as chamadas para uma nova função (ou um novo método em uma nova classe) que possui o código comum. A maneira mais fácil de começar é remover todo o código copiado e ver quais quebras, nas quais você corrige, redirecionando as chamadas para o código comum.

Conseguir que seu cliente concorde em refatorar o código pode ser difícil, pois é difícil convencer uma pessoa não técnica a consertar uma dívida técnica. Portanto, na próxima vez que você fornecer estimativas de tempo, inclua apenas o tempo necessário para refatorar suas estimativas . Na maioria das vezes, os clientes assumem que você está limpando o código durante o tempo em que faz a correção.

Spoike
fonte
1

Parece código de espaguete para mim. A melhor solução é refatorar / reescrever.

um termo pejorativo para código fonte que possui uma estrutura de controle complexa e emaranhada, especialmente uma que usa muitos GOTOs, exceções, threads ou outras construções de ramificação "não estruturadas". É chamado assim porque o fluxo do programa é conceitualmente como uma tigela de espaguete, ou seja, torcido e emaranhado ...

http://upload.wikimedia.org/wikipedia/commons/thumb/9/93/Spaghetti.jpg/175px-Spaghetti.jpg

Tom Squires
fonte
-1 Refatorar e reescrever são duas opções muito diferentes. Total de reescritas, jogando o software fora, nunca é uma boa ideia. joelonsoftware.com/articles/fog0000000069.html
P.Brian.Mackey (
11
O código espaguete é IMO um termo muito mais geral - e mais flexível. Embora esse código geralmente contenha duplicações, você pode ter um código de espaguete sem duplicação e também um código de espaguete altamente duplicado, mas não o duplicado.
Péter Török
@ P.Brian.Mackey Eu nunca disse que Refatorar e reescrever eram a mesma coisa. O OP deve decidir qual usar.
Tom Squires
2
Eu nunca fui fã desse artigo. Concordo que a reescrita foi uma má idéia no exemplo citado, mas apenas porque era uma má idéia nesse caso, não significa que é sempre uma má idéia. Para iniciantes, a reescrita bloqueará algum outro progresso? Se sim, isso é ruim; se não, bem, então não é tão ruim assim.
Jhocking
@jhocking - Eu acredito que o objetivo da política de não reescrever não é o de bloquear o progresso em outros programas, mas a perda de correções reais ao longo do tempo. Esse mágico "se (goldenNugget> 22)", embora mal nomeado, ainda resolve um problema específico que pode ser impossível de identificar sem horas ou dias de pesquisa. Agora, pegar esses mesmos dados e melhorá-los é o que deve ser feito. Isso é um refator. Jogar fora e dizer "vamos fazer certo da próxima vez" é uma perda de tempo. A mesma razão para resolver problemas já resolvidos é uma perda de tempo. Adicionar código bom em cima de inadimplência aumenta dívida
P.Brian.Mackey
0

Você diz que não pode culpar completamente A - mas copiar uma classe dessa maneira é realmente imperdoável. É uma falha enorme no seu processo de revisão de código. É possivelmente a falha mais maciça, sem nenhuma revisão de código.

Se você pensa que precisa produzir um código terrível para cumprir um prazo, a solicitação de prioridade mais alta absoluta para a liberação depois disso deve ser a de corrigir o código terrível AGORA. Então seu problema se foi.

O princípio DRY é para situações que não são perfeitas e podem ser melhoradas. Duplicar uma classe é um calibre totalmente novo. Eu o chamaria primeiro de "código duplicado" e, com o tempo, ele mudará para o pior de todos os desperdiçadores de tempo, "código duplicado divergente": várias cópias do mesmo código que são quase, mas não totalmente idênticas, e ninguém sabe se as diferenças são intencionais, coincidência ou bugs.

gnasher729
fonte
-3

Quase uma década atrasada para essa parte, mas o nome desse antipadrão é Mudança divergente , onde várias classes incluem cópias do mesmo comportamento, mas à medida que o tempo e a manutenção progridem e algumas classes são esquecidas, esses comportamentos divergem.

Dependendo de qual é o comportamento compartilhado e como ele é compartilhado, ele pode ser chamado de Cirurgia com Espingarda , a diferença é que aqui um único recurso lógico é fornecido por muitas classes, e não por uma única.

doOOooonkeyKoooOOOooong
fonte
11
Isso não parece a mesma coisa. Mudança divergente é quando muitas mudanças são feitas na mesma classe. O OP descreve a duplicação de código. A cirurgia de espingarda também não é a mesma coisa. A cirurgia Shotgun descreve a mesma alteração feita em várias classes diferentes.
Robert Harvey