O instinto usual é remover qualquer duplicação de código que você vê no código. No entanto, eu me encontrei em uma situação em que a duplicação é ilusória .
Para descrever a situação com mais detalhes: Estou desenvolvendo um aplicativo Web e a maioria das visualizações é basicamente a mesma - elas exibem uma lista de itens pelos quais o usuário pode rolar e escolher, uma segunda lista que contém itens selecionados e um "Salvar "para salvar a nova lista.
Pareceu-me que o problema é fácil. No entanto, todas as visualizações têm suas próprias peculiaridades - às vezes você precisa recalcular algo, às vezes é necessário armazenar alguns dados adicionais etc. Isso eu resolvi inserindo ganchos de retorno de chamada no código lógico principal.
Existem tantas diferenças minuciosas entre as visualizações que estão se tornando cada vez menos sustentáveis, porque eu preciso fornecer retornos de chamada para basicamente todas as funcionalidades, e a lógica principal começa a parecer uma enorme sequência de chamadas de retorno de chamada. No final, não estou economizando tempo ou código, porque cada exibição tem seu próprio código que é executado - tudo em retornos de chamada.
Os problemas são:
- as diferenças são tão pequenas que o código se parece quase exatamente em todas as visualizações,
- existem tantas diferenças que, quando você olha para os detalhes, codificar não é nem um pouco parecido
Como devo lidar com essa situação?
Ter uma lógica principal composta inteiramente de chamadas de retorno de chamada é uma boa solução?
Ou devo duplicar o código e diminuir a complexidade do código baseado em retorno de chamada?
fonte
Respostas:
Em última análise, você deve fazer um julgamento sobre se deve combinar código semelhante para eliminar a duplicação.
Parece haver uma tendência infeliz de adotar princípios como "Não se repita" como regras que devem ser seguidas rotineiramente. De fato, essas não são regras universais, mas diretrizes que devem ajudá-lo a pensar e desenvolver um bom design.
Como tudo na vida, você deve considerar os benefícios versus os custos. Quanto código duplicado será removido? Quantas vezes o código é repetido? Quanto esforço será necessário para escrever um design mais genérico? Quanto você provavelmente desenvolverá o código no futuro? E assim por diante.
Sem conhecer seu código específico, isso não está claro. Talvez haja uma maneira mais elegante de remover a duplicação (como a sugerida por LindaJeanne). Ou, talvez simplesmente não haja repetição verdadeira o suficiente para justificar a abstração.
A atenção insuficiente ao design é uma armadilha, mas também tenha cuidado com o excesso de design.
fonte
Lembre-se que DRY é sobre conhecimento . Não importa se dois pedaços de código parecem semelhantes, idênticos ou totalmente diferentes, o que importa é se o mesmo conhecimento sobre seu sistema pode ser encontrado nos dois.
Um conhecimento pode ser um fato ("o desvio máximo permitido do valor pretendido é de 0,1%") ou pode ser algum aspecto do seu processo ("essa fila nunca contém mais de três itens"). É essencialmente qualquer informação codificada no seu código-fonte.
Portanto, ao decidir se algo é duplicação que deve ser removida, pergunte se é duplicação de conhecimento. Caso contrário, é provavelmente uma duplicação acidental, e a extração para algum lugar comum causará problemas quando mais tarde você desejar criar um componente semelhante em que a parte aparentemente duplicada seja diferente.
fonte
Você já pensou em usar um padrão de estratégia ? Você teria uma classe View que contém o código e as rotinas comuns chamados por várias visualizações. Filhos da classe View conteriam o código específico para essas instâncias. Todos eles usariam a interface comum que você criou para o View e, portanto, as diferenças seriam encapsuladas e coerentes.
fonte
Qual é o potencial de mudança? Por exemplo, nosso aplicativo possui 8 áreas de negócios diferentes, com um potencial de 4 ou mais tipos de usuários para cada área. As visualizações são personalizadas com base no tipo de usuário e na área.
Inicialmente, isso foi feito usando a mesma exibição com algumas verificações aqui e ali para determinar se coisas diferentes devem aparecer. Com o tempo, algumas áreas de negócios decidiram fazer coisas drasticamente diferentes. No final, basicamente migramos para uma visualização (visualizações parciais, no caso do ASP.NET MVC) por parte da funcionalidade por área de negócios. Nem todas as áreas de negócios têm a mesma funcionalidade, mas se alguém deseja a funcionalidade de outra, essa área terá sua própria visão. É muito menos complicado para a compreensão do código, bem como para a testabilidade. Por exemplo, fazer uma alteração em uma área não causará uma alteração indesejada em outra área.
Como o @ dan1111 mencionou, pode ser uma decisão judicial. Com o tempo, você pode descobrir se funciona ou não.
fonte
Um problema pode ser o fato de você estar fornecendo uma interface (interface teórica, não recurso de idioma) para apenas um único nível da funcionalidade:
Em vez de vários níveis, dependendo de quanto controle é necessário:
Até onde eu entendi, você apenas expõe a interface de alto nível (A), ocultando os detalhes da implementação (as outras coisas lá).
Ocultar os detalhes da implementação tem vantagens e você acabou de encontrar uma desvantagem - o controle é limitado, a menos que você inclua explicitamente recursos para cada coisa que seria possível ao usar diretamente as interfaces de baixo nível.
Então, você tem duas opções. Você usa apenas a interface de baixo nível, usa a interface de baixo nível porque a interface de alto nível foi muito trabalhosa para manter ou expõe as interfaces de alto e baixo nível. A única opção sensata é oferecer interfaces de alto e baixo nível (e tudo o que há entre elas), supondo que você queira evitar código redundante.
Então, ao escrever outra coisa, você analisa todas as funcionalidades disponíveis até agora (inúmeras possibilidades, você decide quais podem ser reutilizadas) e as reúne.
Use um único objeto onde você precise de pouco controle.
Use a funcionalidade de nível mais baixo quando alguma estranheza precisar acontecer.
Também não é muito preto e branco. Talvez sua grande classe de alto nível possa razoavelmente cobrir todos os casos de uso possíveis. Talvez os casos de uso sejam tão variados que apenas a funcionalidade primitiva de nível mais baixo seja suficiente. Cabe a você encontrar o equilíbrio.
fonte
Já existem outras respostas úteis. Vou adicionar o meu.
Duplicação é ruim porque
Portanto, o ponto é: você não está eliminando a duplicação por causa disso ou porque alguém disse que é importante. Você está fazendo isso porque deseja reduzir bugs / problemas. No seu caso, parece que se você alterar algo em uma exibição, provavelmente não precisará alterar a mesma linha exata em todas as outras exibições. Então você tem duplicação aparente , não duplicação real.
Outro ponto importante é nunca reescrever do zero algo que está funcionando agora apenas com base em uma questão de princípio, como Joel disse (você já deve ter ouvido falar dele ....). Portanto, se suas opiniões estiverem funcionando, continue melhorando passo a passo e não seja vítima do "pior erro estratégico que qualquer empresa de software pode cometer".
fonte