Por que DRY é importante?

81

Muito simples, por que eu gostaria de escrever código que funcione para todos os casos e dados escalonáveis ​​quando tudo o que preciso fazer é repetir o mesmo processo algumas vezes com alguns pequenos ajustes?

É improvável que precise editá-lo novamente em breve.

Parece muito menos trabalho para apenas ir ...

function doStuff1(){/*.a.*/}
function doStuff2(){/*.b.*/}
function doStuff3(){/*.c.*/}

E se eu precisar adicionar algo ...

function doStuff4(){/*.d.*/}

E se eu precisar removê-lo, eu o removo.

É mais difícil descobrir como transformar tudo isso em um padrão direto, no qual eu possa apenas alimentar dados e lidar com todos os casos, e fazer um monte de mudanças que eu não sinto que vou ter. façam.

Por que ficar SECO quando parece que um corte + colar rápido será muito menos trabalhoso?

Incógnito
fonte
11
porque seco ainda é mais rápido quando você faz o que é certo, e também se você cometer um erro em um. que afeta todos os outros
Daniel Pequenas
97
"É improvável que precise editar isso novamente tão cedo" - você pode esperar, mas provavelmente está cometendo um erro aqui. E se você for trabalhar nesse código novamente, mas não tão cedo, isso só piorará as coisas; você esquecerá onde estão as duplicatas, e as duplicatas crescerão discrepâncias sutis, porém traiçoeiras. "Escreva como se a pessoa que manter seu código fosse um maníaco perigoso que sabe onde você mora", para citar os clássicos.
9000
14
Acho que você pode resumir: Um único ponto de mudança é mais fácil de manter.
Falcon
17
Se você mesmo não conseguir responder, precisará obter mais experiência no mundo real de desenvolvimento e manutenção.
David Heffernan
15
@Wayne, senti uma grande perturbação na fonte, como se milhões de programadores de repente gritassem aterrorizados.
Incognito

Respostas:

121

Se você se repetir, poderá criar problemas de manutenção. Se todos os doStuff1-3 tiverem código estruturado da mesma forma e você resolver um problema em um, você poderá facilmente esquecer de corrigi-lo em outros lugares. Além disso, se você precisar adicionar um novo caso para lidar, basta passar parâmetros diferentes para uma função em vez de copiar e colar em todo o lugar.

No entanto, o DRY é frequentemente levado ao extremo por programadores inteligentes. Às vezes, para não se repetir, é necessário criar abstrações tão obtusas que seus colegas de equipe não possam segui-las. Às vezes, a estrutura de duas coisas é apenas vagamente semelhante, mas diferente o suficiente. Se doStuff1-4 for diferente o suficiente, de modo que refatorá-los para não se repetir faz com que você precise escrever um código não natural ou sofrer backflips de codificação inteligentes que farão com que sua equipe olhe para você, então pode ser bom repetir-se. Eu me inclinei para trás para não me repetir algumas vezes de maneiras não naturais e me arrependi do produto final.

Eu sempre erro do lado do DRY, no raro caso de me repetir quando penso que os benefícios na legibilidade valem os riscos de alguém esquecer de corrigir um bug em vários lugares.

Levando em consideração esse conselho, parece que no seu caso

repita o mesmo processo algumas vezes com alguns pequenos ajustes

Eu definitivamente trabalharia duro para não me repetir no seu caso. Assumindo "ajustes" mínimos - eles podem ser manipulados com parâmetros diferentes que afetam o comportamento ou talvez injetados na dependência para executar subtarefas diferentes.

Por que ficar SECO quando parece que um corte + colar rápido será muito menos trabalhoso?

Últimas palavras famosas. Você vai se arrepender de pensar que, quando um engenheiro júnior ajusta / corrige / refatora, um faz coisas e nem percebe que os outros existem. Hilaridade segue. Não ocorre principalmente azia. Cada linha de código custa mais. Quantos caminhos de código você deve testar com tantas funções repetidas? Se uma função, você apenas precisa testar um caminho principal com algumas modificações comportamentais. Se você copiar e colar, deverá testar todos os doStuff separadamente. As probabilidades são de que você perderá uma e um cliente poderá ter um bug indesejável e alguns emails indesejados em sua caixa de entrada.

Doug T.
fonte
2
Er, só para deixar claro, eu não estou propondo que seco é ruim, essa questão é mais do que diabos advogam. Estou realmente procurando por uma resposta lógica que possa vincular a pessoas que acham que o código recortar, colar e ajustar é bom.
Incognito
2
Dito isto, eu gosto mais da sua resposta, pois abrange as duas falhas no DRY: não incomodar e exagerar, além de explicar os impactos. - Em um ponto sobre sacrificar a legibilidade por bugs, eu argumentaria que o código repetitivo é menos legível pelo mesmo motivo que você aponta, onde é fácil perder o controle das coisas.
Incognito
16
Gostaria de sublinhar uma armadilha fácil do DRY: código semelhante mesclado. Se você tiver dois casos de uso que não estão funcionalmente relacionados, mas que possuem código muito semelhante, é fácil mesclar os dois porque DRY é bom . Infelizmente, quando é necessário evoluir, você geralmente se vê com a desagradável tarefa de dividir a função novamente e depois percorre todos os sites de chamada e considera cuidadosamente qual deve ser chamado aqui ... Exemplo: digitação estrutural do LLVM (todos os tipos semelhantes são mesclados em um) torna quase impossível mapear o IR de volta ao código original.
Matthieu M.
1
Bingo. Se dois ou mais trechos de código forem alterados e as alterações sempre forem as mesmas para todos os trechos, eles deverão ser mesclados. Qualquer peça que precise mudar de uma maneira diferente das outras não deve ser mesclada. Se o código nunca será alterado, não importa muito se ele é mesclado ou não. A questão de saber se as alterações devem ser bloqueadas ou desanexadas é muito mais importante que o tamanho do código em questão.
supercat 28/09
1
@ MatthieuM é um exemplo um pouco injusto. O LLVM está aplicando a tipagem estrutural como uma otimização ; isto é, o pessoal da LLVM decidiu pagar o preço da RI difícil de entender pelos benefícios de desempenho. O DRY geralmente é um problema de manutenção, mas nesse caso foi claramente uma decisão deliberada para reduzir a manutenção.
Benjamin Hodgson
47

Porque DRY será menos trabalhos depois.


SECA: (Não se repita)

Uma função recebendo um argumento.

def log(arg):
    print(arg)

C&P: (copiar e colar)

26 gazilhões de funções fazem essencialmente a mesma coisa, mas com uma diferença de 2 caracteres.

def logA():
    print('a')

def logB():
    print('b')

...ad infinitum...

Que tal atualizar nossa impressão para especificar exatamente o que é impressão?

SECO:

def log(arg):
    print(arg + "Printed from process foo")

Feito.

C&P:

Você precisa voltar e alterar todas as funções .


Qual você acha que seria mais fácil depurar?

John
fonte
10
Além disso, você precisa escrever tantos conjuntos de testes semelhantes quanto funções duplicadas.
9000
Você ilustrou o conceito adequadamente, mas, na prática, ninguém faria o que você descreveu com as funções de gazilhões, e não dessa maneira.
Robert Harvey
@ Robert Eu espero que não! Escolhi uma tarefa muito simples para tentar ilustrar melhor o conceito e por que ele pode ser uma coisa boa.
John
11
@ Robert - você já leu algum dos artigos em thedailywtf.com ;) - há alguns por aí que iria fazer exatamente isso
HorusKol
1
@ 9000 Não se você não tem nenhum conjuntos de testes: p (que na verdade muitas vezes pode ser o caso em alguns projetos ... infelizmente ...)
Svish
16

Porque , aplicado ao seu exemplo:

  • + legibilidade

    Menos código geralmente se traduz em menos ruído . (nem sempre...)

  • + flexibilidade

    Se você já teve que mudar o comportamento do doStuffX, você vai querer se matar ou quem o escreveu,

  • + extensibilidade

    Se você extraiu as partes distintas para uma estrutura de dados de sua escolha e depois iterou sobre ela chamando um genérico doStuff, você também pode adicionar uma linha em sua estrutura de dados na qual deseja uma nova entrada ou remover uma e mudar o comportamento significa apenas edição doStuff. Mais fácil de manter .

  • + eficiência de custos

    menos código aqui significa:

    • => menos desenvolvimento => custo reduzido
    • => menor probabilidade de erros => menor tempo de suporte => custo reduzido
  • + (possível) otimização gerenciada

    Dependendo do idioma, o compilador / intérprete pode ter uma chance maior de determinar que o genérico doStuffsempre faz as coisas quase idênticas, muitas vezes uma chamada após a outra, e pode incorporá- lo ou tentar otimizá- lo. Provavelmente não faria X variações de doStuffX.

  • + teste e qualidade

    O teste é mais fácil: doStuffprecisa de teste, e é isso. Bem, não exatamente, mas isso já cobre mais . Somente suas expectativas de IO variam e precisam ser testadas sob condições diferentes, mas ainda é muito mais fácil de testar e mais sustentável do que todas as variações de doStuffX.

No geral, isso representa um código mais sustentável e uma eficiência de desenvolvimento aprimorada para sua equipe, e é uma das muitas boas práticas para ajudá-lo a produzir software mais robusto e confiável.

haylem
fonte
13

Como todo mundo fez um ótimo trabalho ao explicar os problemas de manutenção com código duplicado, vou dizer o seguinte:

Grande parte da programação exige que você pense no futuro, não apenas no presente imediato. Você está certo de que copiar e colar é mais fácil agora, mas é improvável que a declaração precise editá-la novamente em breve " mostra que você não está pensando corretamente. Sim, você pode comprar um pouco de tempo com um copiar / colar rápido e sujo, mas, ao fazer isso, você mostra que não pode olhar além do seu problema imediato e pensar no amanhã.Tem certeza de que nunca precisará revisitar esse código? Você pode 100% garantir que não precisará revisitá-lo quando seu próximo conjunto de recursos precisar ser implementado? Esses são problemas para amanhã e precisam ser considerados ao projetar hoje.

Obviamente, há momentos em que copiar / colar será necessário. Como desenvolvedor de interface do usuário, descobri que há momentos em que tenho que violar o princípio DRY. É péssimo, estremeço toda vez que acontece e, felizmente, é raro. Mas não acontecer.

A diferença é que, ao violar o DRY, você deve ter um motivo muito convincente para fazê-lo, e a afirmação: É mais difícil descobrir como transformar todos esses elementos em um padrão direto não é realmente um deles. A menos que você esteja sofrendo muito tempo e faça seu chefe gritar para conseguir algo nas próximas horas ou perder seu emprego, não acho que essa seja uma lógica válida.

Não tome isso da maneira errada: não estou tentando castigá-lo ou castigá-lo, mas tente fazê-lo ver onde sua mentalidade está errada. Programadores investem em preguiça futura; DRY é uma maneira de conseguir isso. O trabalho que você faz hoje para resolver um problema de projeto difícil será recompensado amanhã.

bedwyr
fonte
Não tenho certeza se concordo com um chefe dizendo que "faça o trabalho ou está demitido" é um ótimo motivo para violar o DRY. Dívida técnica, quando você tem tempo para fazer o que é certo, economiza muito tempo, etc?
Incognito
1
@Incognito, eu estava tentando ser um pouco irônico :)
Bedwyr
7

É improvável que precise editá-lo novamente em breve.

Se esse for realmente o caso, você poderá se safar, mas com mais freqüência estará trabalhando no código que precisa ser mantido. Isso significa estender a funcionalidade, corrigir bugs e outras melhorias. Se você tiver pequenas variações do mesmo código em 10 locais diferentes, e um dia você voltar ao código e precisar fazer uma alteração, agora você tem a tarefa propensa a erros de fazer a mesma alteração em 10 locais diferentes (desculpe, não eram 11 lugares, você esqueceu um e agora tem um bug).

Se você puder generalizar o problema que está tentando resolver, poderá tornar seu código mais fácil de estender e corrigir, se surgirem erros.

Alex
fonte
Resposta legal, mas, mesmo que eu consiga escapar, o que dizer da pobre seiva que consegue mantê-la depois de mim? ;).
Incognito
Veja: "mais frequentemente do que não você vai estar trabalhando no código que precisa ser mantida" :)
Alex
Mesmo assim, é o caso se o que você está copiando e colando é 100% perfeição sem erros. E não é, e pare de pensar que pode ser.
Dan Ray
Admito que copiei e colei coisas no passado, mas nunca por algo que eu iria manter por mais de um dia. Às vezes, você só precisa de um script de descarte rápido e sujo.
Alex
6

Como afirmei na resposta a outra pergunta, minha abordagem é a seguinte:

  1. A primeira vez que resolvo um determinado problema, apenas o resolvo.
  2. Na segunda vez (ou seja, quando eu resolvo um problema semelhante), penso: hm, talvez eu esteja me repetindo, mas vou copiar e colar rapidamente por enquanto.
  3. Na terceira vez que penso: hm, estou me repetindo -> seja geral!

Ou seja, até 2, outro princípio (YAGNI) vence o DRY. Mas a partir de 3 (ou 4, se eu sou realmente preguiçoso!), Parece que vou precisar e, por isso, sigo DRY.

Atualizar

Algumas idéias adicionais da minha experiência recente. Eu tive que adaptar / integrar dois componentes A e B desenvolvidos por outra equipe em nosso produto. Primeiro: os dois componentes A e B são muito semelhantes entre si, então eu já estava perturbado pelo fato de eles terem uma arquitetura um pouco diferente. Segundo: tive que adaptá-los para ter prazer em usar subclasses e apenas substituir o que realmente precisava.

Então comecei a refatorar esses dois componentes (cada um dos quais consiste em cerca de 8 classes C ++): eu queria ter uma arquitetura comum para A e B e, em seguida, adicionar os recursos necessários ao definir subclasses. Dessa maneira, nossos dois novos componentes A 'e B' seriam derivados dos existentes.

Depois de duas semanas tentando obter uma estrutura comum e bem definida do código existente e tendo que explicar durante nossas reuniões diárias que eu estava fazendo pouco progresso porque o código original era muito confuso, conversei com meu chefe. Observamos que não precisaríamos de mais do que esses dois novos componentes A 'e B' (não haveria quatro ou seis deles, apenas esses dois).

Ok, seja assim: fiz uma cópia maciça e renomeei as classes de A e B e comecei a adaptar a cópia do código. Consegui que funcionasse em mais duas semanas (ainda estou corrigindo alguns erros agora).

Vantagens: Temos a funcionalidade quase concluída agora e, quando corrigimos todos os bugs, terminamos. Economizamos toda a refatoração e teste de A e B.

Desvantagens: Duas semanas atrás, a outra equipe mudou outro componente C, usado por A e B. Eles adaptaram A e B, mas A 'e B' também foram quebrados e tivemos que alterá-los nós mesmos. Isso introduziu um novo bug que tivemos que corrigir. Esse trabalho extra provavelmente seria desnecessário se A 'e B' tivessem compartilhado a maior parte de seu código com A e B.

Portanto: a duplicação de código é sempre perigosa. Penso que é sempre uma questão de encontrar compromissos e, muitas vezes, não é fácil.

Giorgio
fonte
5

Apenas para esclarecer, pois não encontro isso em nenhuma das outras respostas:

DRY é um princípio de desenvolvimento de software que visa reduzir a repetição de informações de todos os tipos .

Todo conhecimento deve ter uma representação única, inequívoca e autoritativa dentro de um sistema.

O princípio DRY mencionado por Andy Hunt e Dave Thomas não se limita a impedir a duplicação de código. Ele também defende a geração de código e qualquer processo de automação. Ironicamente, os resultados da geração de código podem até ser código duplicado ...

A razão pela qual já foi explicada minuciosamente nas outras respostas, mas o comentário de Falcon resume bem o suficiente IMHO:

Um único ponto de mudança é mais fácil de manter.

Steven Jeuris
fonte
Oh uau, eu pensei que a tag tinha alguns dados nela. Vou colocar algumas informações lá.
Incognito
3

Existe algo como muito seco. Quando isso acontece, dois conceitos que parecem em algum momento semelhantes o suficiente para garantir o código de fatoração (1) podem vir a ser diferentes o suficiente para merecer implementações separadas.

Em outras palavras, o acoplamento SECO e solto às vezes entra em conflito. Se você espera que o doStuff1 e seus amigos diverjam a cada nova versão do software, não há problema em duplicar o código.

Na minha experiência, pode ser difícil julgar para onde o seu software está indo no futuro e, por esse motivo, o DRY geralmente é uma escolha segura.

Código que foi excessivamente "seco" geralmente possui fluxo de controle complexo e muitos parâmetros. O que inicialmente era uma função simples foi posteriormente estendido para suportar uma nova funcionalidade controlada por um parâmetro extra. Após duas ou três iterações, a função não é mais mantida. Corrija um erro que ocorre em uma configuração e você introduz novos erros em outras configurações.

É compreensível que a qualidade do código geralmente diminua à medida que o código evolui, mas vi casos em que uma função multiparâmetros com espaguete if-then-else no corpo era o resultado de um esforço de refatoração bem-intencionado, mas mal conduzido.

(1) Estou usando a palavra "código", mas isso também se aplica ao design.

Joh
fonte
Seria útil dar um exemplo de "muito seco", pois é o extremo menos visível do espectro.
Incognito
@ Incognito: Eu editei minha resposta. Nenhum exemplo concreto, mas espero que o que eu quis dizer seja suficientemente claro.
Joh
2

Eu tenho que mencionar os problemas com o DRY no mundo do banco de dados relacional. Os bancos de dados são projetados para um desempenho rápido e bom, usando lógica baseada em conjunto e através de consultas sargable. Os princípios DRY geralmente fazem com que o desenvolvedor grave consultas não-suscetíveis de Sargable ou use a lógica Row-by-agonizing-Row para aproveitar o código existente em várias situações. A DRY e a otimização do desempenho geralmente estão em desacordo e, no mundo dos bancos de dados, o desempenho geralmente é muito mais crítico do que a capacidade de manutenção. Isso não significa que você não deva usar os princípios DRY, apenas esteja ciente de como isso afetará a usabilidade geral do banco de dados. Os desenvolvedores de aplicativos consideram DRY primeiro e o desempenho segundo, os desenvolvedores de banco de dados acham a integridade dos dados primeiro, o desempenho segundo, a segurança dos dados em terceiro (desempenho e segurança podem trocar de lugar em alguns sistemas).

Percebi, em geral, que quanto mais camadas de abstração você coloca no banco de dados, mais lenta elas se tornam. Não estou dizendo que não desejo que as pessoas que projetam os programas da base de dados não trabalhem melhor ao permitir que os desenvolvedores usem DRY sem afetar o desempenho do banco de dados, mas não projeto software de banco de dados nesse nível , então talvez o conflito entre abstração e desempenho no banco de dados seja mais difícil de corrigir do que eu suponho. No entanto, temos que trabalhar com os sistemas como eles são construídos atualmente. Podemos pedir uma melhor implementação dos princípios DRY em versões futuras que também não prejudicam o desempenho (e que melhorou ao longo dos anos, mas ainda é problemático), mas, enquanto isso, devemos considerar se DRY é o movimento certo para esse banco de dados. nesse momento.

Mas muitas vezes os mesmos recursos que você deseja usar para garantir o cumprimento do princípio DRY são os que causam enormes problemas ao banco de dados. Não estou dizendo que nunca use DRY, mas não exagere.

Exemplos do que estou falando. Você precisa importar dados de um milhão de registros uma vez por mês. Os registros já podem ser adicionados manualmente através da interface do usuário chamando um processo armazenado. Este processo, por ter sido projetado para importações de registro único, adiciona apenas um registro por vez. Usando DRY para evitar o código de inserção em dois lugares, você escreve um cursor para chamar o proc repetidamente, em vez de gravar as importações baseadas em conjuntos necessárias. O tempo para a importação vai dos 30 minutos necessários para usar a lógica baseada em conjunto a 18 horas. Agora, a maneira correta de aderir ao DRY nesse caso seria corrigir o processo para lidar com várias importações de registros. Infelizmente, muitas vezes é impossível ou muito difícil enviar uma matriz para um proc (dependendo do back end do banco de dados) e, alterando o proc, você acaba quebrando o aplicativo.

Funções escalares e funções com valor de tabela também são usadas para implementar os princípios DRY e, novamente, elas podem afetar seriamente o desempenho, especialmente se você precisar usá-las de maneira a impedir que os índices sejam úteis.

As visualizações também são boas para a implementação de DRY. No entanto, se você implementar o DRY através do uso de visualizações que chamam visualizações que chamam outras visualizações, chegará rapidamente ao ponto em que as consultas atingirão o tempo limite sob carga. Na verdade, você pode precisar gerar conjuntos de dados de milhões de registros quando precisar apenas de três no final. Portanto, uma visão de um nível de um conjunto complexo de junções para implementar DRY pode ser excelente (eu mesmo tenho uma que usamos para garantir que todos os relatórios financeiros usem o mesmo conjunto básico de tabelas e cálculos de certas coisas), mais de dois níveis e você precisa considerar se está criando uma bagunça no desempenho.

HLGEM
fonte
1

Não vejo os pontos principais da minha resposta acima, então aqui vai. Não olhe para DRY tanto como uma regra contrafazendo algo. Pode ser redigido assim, mas pode realmente servir a um propósito bem diferente e positivo. É um sinal para parar, pensar e encontrar uma resposta melhor. Me desafia a procurar oportunidades para projetar uma solução melhor. É o lado bom de um mau cheiro no meu código que me leva a repensar meu design e me faz fazê-lo muito melhor. DRY não se trata apenas de uma violação de sintaxe muito pequena. Isso me desafia a modularizar. Desafia-me a componente. Isso indica repetição que me lembra de pensar em usar modelos e geração de código em vez de força bruta e ignorância. Isso me ajuda a descobrir que devo encontrar algum tempo para automatizar minha automação. Isso leva você a um estilo de vida parcimonioso! Ele ajuda você a gastar mais do seu tempo fazendo coisas novas e mais legais, em vez de detalhes chatos e antigos. E oferece boas maneiras, bom hálito e um estilo de vida saudável! Bem, talvez eu me perca um pouco ...

John Tobler
fonte
O DRY tem efeitos muito diferentes para mim, no entanto, se esses são os efeitos sobre você, eu gosto da filosofia de algo ser "um sinal para parar, pensar e encontrar uma resposta melhor" e o desafio.
N611x007
1

Eu tenho um projeto antigo, em que alguns dos ex-desenvolvedores não se preocupavam com o DRY. Portanto, toda a base de código estava cheia de métodos auxiliares, como GetSystemTimeAsString (), LogToFile () e muitas outras coisas. Alguns métodos foram levemente personalizados para necessidades especiais, mas a maioria era apenas copiar e colar.

Infelizmente, alguns dos métodos tinham bugs sutis, como char array, não suficientemente longos em alguns casos, usando coisas inseguras como strcpy (), etc.

Portanto, foi uma verdadeira PITA encontrar todos os fragmentos de código, harmonizá-los e corrigir os erros. E ainda estamos harmonizando e consertando coisas.

Você nunca sabe, se cometeu um erro no seu primeiro método e depois precisa corrigi-lo várias vezes, porque acabou de copiá-lo. E se você quiser usar alguns dos métodos posteriormente, como você sabe, qual dos 5 métodos na base de código é o mais adequado para o seu caso agora? Então você apenas copia um, personaliza e aqui começa de novo ...

Simon
fonte
1

Sim, não se preocupe com DRY se você estiver escrevendo o Throwaway Code .

Mas o DRY é importante, é claro, se você planeja manter o código.

Pacerier
fonte
1

A fraseologia "não se repita" é um pouco simplista demais. O importante é "evitar ter uma informação potencialmente mutável encapsulada em dois locais independentes ".

Se um programa deve processar widgets, cada um com três woozles e muitos loops do formulário

for (i=0; i<3; i++)
  thisWidget.processWoozle(i);

então, a expectativa de que os widgets devam conter três woozles seria encapsulada em cada um desses loops, e seria difícil atualizar o código para acomodar qualquer outro número de woozles por widget. Por outro lado, se alguém dissesse

#define WOOZLES_PER_WIDGET 3

e cada loop foi reescrito

for (i=0; i<WOOZLES_PER_WIDGET; i++) ...

esse design pode facilitar a alteração do número de woozles por widget.

É importante observar, no entanto, que, embora seja desejável consolidar informações como o número de woozles por widget em um único ponto, nem sempre é prático. Às vezes, pode ser necessário codificar a lógica, que só funcionará se as coisas tiverem um tamanho específico. Por exemplo, se cada woozle tem um valor e se deseja encontrar a mediana associada a um widget específico, pode ser possível classificar os valores e usar o do meio, e essa abordagem funcionaria com qualquer número de woozles, mas com lógica escrito à mão especificamente para encontrar a mediana de três itens, pode ser significativamente mais rápido.

Embora ter uma constante WOOZLES_PER_WIDGET possa tornar o código mais legível, deve-se comentar para deixar claro que seu valor não pode ser alterado sem outros ajustes na lógica do programa. Nesse caso, a lógica codificada para três itens e a constante WOOZLES_PER_WIDGET duplicariam as informações "cada widget possui três woozles", mas os benefícios dessa duplicação (maior velocidade de execução) poderiam compensar o custo.

supercat
fonte
0

Embora eu realmente concorde com os outros pôsteres, os comentários sobre a manutenção etc. são válidos.

Gostaria de acrescentar uma pequena voz dissidente ao debate.

  • É importante apenas para programadores. As pessoas que pagam seu salário não se importam menos, desde que o software seja aprovado no UAT.
  • Em termos de importância, está bem abaixo de itens como obter os requisitos corretos, ouvir os patrocinadores do projeto e entregar a tempo.
James Anderson
fonte
como este site é para "Programadores", acho seguro dizer que a pergunta é direcionada ao "ponto de vista dos programadores". Suas declarações sobre os ordenados, UAT e nível de importância são válidas, é claro, mas não são relevantes para esta questão específica.
ozz
1
Eu discordo totalmente. Uma boa gerência entenderá os princípios e por que eles estão sendo realizados, se explicados em detalhes. Isso deve ser uma conversa séria e profunda, e não uma queda de 5 minutos por coisa.
Michael Durrant
2
Seu segundo ponto está inteiramente correto.
Jim G.
1
@ Ozz, o orgulho do seu trabalho é importante, mesmo necessário para um bom programador, mas talvez o "ponto de vista do programador" deva incluir um pouco de preocupação com a "satisfação do cliente".
James Anderson
0

<tl;dr>

Como não consegui ler todas as respostas repetidas, posso ter perdido alguma coisa (e a repetirei eu mesma <= ver o que fiz aqui?).

Aqui está a lista de coisas impressionantes sobre como impedir a duplicação de código!

  1. Mais fácil de testar: você só precisa testar uma 'cópia' do código.
  2. Mais fácil de corrigir: você só precisa encontrar o bug em uma 'cópia' do código e corrigi-lo uma vez.
  3. Mais fácil de atualizar (o mesmo que acima): as alterações necessárias, geralmente podem ser tratadas modificando o código em pouquíssimos lugares, porque você gastou um tempo para reutilizar o código corretamente e não copiou as mesmas linhas para centenas ou milhares de lugares diferentes na fonte.
  4. Mais fácil de reutilizar: quando (não é duplicado em alguns lugares) e é mantido em métodos genéricos apropriadamente nomeados, é fácil encontrá-los e usá-los em vez de escrever seus próprios.
  5. Mais fácil de ler: o código duplicado é difícil de ler porque é desnecessariamente detalhado; ele contém muitas linhas que não fazem parte da lógica e da funcionalidade específica pretendida (por exemplo, comandos genéricos usados ​​para configurar o palco para a ação ocorrer ou tarefas repetidas simples genéricas que são necessárias em muitos lugares). O código limpo faz com que a lógica e a funcionalidade se destacem porque não há repetição no espaço do código.
  6. Mais fácil para depurar devido a (1) e (5).
  7. Economiza tempo e dinheiro e faz mais coisas divertidas no futuro; crie especificamente um código melhor e mais robusto. Este é o resultado final e é um resumo de praticamente todas as opções acima. Se muitas pessoas usam a mesma função doFoo1(a, b), há uma chance maior de que muitas de suas falhas e casos irritantes sejam descobertos e resolvidos. Se todos copiam o código e criam doFoo2(specialA)... doFuu2^n(a, b, c)eles duplicaram os problemas doFoo1e criaram muito mais trabalho.

</tl;dr>

Versão longa:

O problema da duplicação de código é que ela "cresce exponencialmente" (em outras palavras, se expande rapidamente) porque, ao duplicar o código, você concede, sem saber, permissão a outros (por exemplo, você não está mais em condições de julgá-los) e você os encoraja a fazer o mesmo. Você também torna mais difícil não fazê-lo, porque é mais difícil detectar e reutilizar códigos úteis quando há muitas repetições redundantes confusas na fonte. Especialmente se o código ainda não foi extraído para uma função adequadamente nomeada. Portanto, se você enfrentar um problema comum simples de resolver, provavelmente escreverá um pedaço de código para resolvê-lo ... E provavelmente não conseguirá verificar alguns casos extremos, adicionando mais códigos não testados com erros.

Outra coisa é que, para um iniciante, isso pode soar como um problema que afetará apenas grandes empresas, mas eu achei bastante prejudicial para pequenas startups (como em 10.000 linhas de código duplicado do lado do servidor). É um estado de espírito. Você não deve apenas dominar o DRY, mas se esforçar para incentivar outras pessoas a fazer o mesmo; porque, caso contrário, você se comprometerá a duplicar o código. Quando os meios de DRY estão à mão e são aplicados, é muito mais fácil aplicá-los. Quando há muito código duplicado, é muito mais fácil aplicar soluções de copiar e colar.

Coisas que considero prejudiciais na duplicação de código:

  1. Esta função é utilizável? Digamos que você encontre uma função que funcione (ou pareça fazer o que você precisa), como você sabe se ela deve funcionar corretamente ou se é apenas um código duplicado e abandonado.
  2. Código redundante. Às vezes, as pessoas duplicam o código, o usam e esquecem (sempre podem duplicá-lo novamente no futuro). Em algum momento, alguém remove as chamadas para a função duplicada em alguns lugares, em um esforço para refatorar, mas a função não utilizada permanece, mesmo que não esteja sendo usada ativamente.
  3. Difícil de encontrar o que você está procurando. O código duplicado ocupa espaço e torna a tarefa de encontrar coisas úteis e necessárias (usando ferramentas como grep) uma tarefa mais difícil do que tem que ser quando você obtém dezenas ou milhares de resultados nos quais deveria ter conseguido apenas um punhado.
  4. (Foi mencionado anteriormente): Difícil de manter, mas também difícil de usar para fins de manutenção e regressão. Se o código de teste for duplicado e não extraído adequadamente nas funções, outros o duplicarão. Alguém se preocupará em escrever uma API fácil de usar e de ler para melhorar a QV? Na minha experiência, não, muitas vezes há algo que as pessoas consideram mais urgente até que ela fique fora de controle.
  5. A duplicação de código é mais difícil de ler porque torna o código detalhado onde não precisa estar, em locais onde a verbosidade não adiciona informações sobre a funcionalidade pretendida: por exemplo, chamadas genéricas de método usadas [repetidas vezes] para definir o terreno para vários tipos de funcionalidade pretendida, dificulta o surgimento dessa funcionalidade real.
  6. Isso foi mencionado muito. Se o código estiver incorreto, um cara ou uma garota pobre precisará pesquisar e alterar cada uso desse código. Por exemplo, se alguém usou uma chamada insegura de injeção SQL para mysql_query em pouquíssimos lugares em uma classe organizada onde é necessário, seria fácil corrigi-la e usar o PHP PDO em vez disso, mas se eles a usassem em mais de mil lugares copiando a chamada além disso, a correção praticamente precisará ser terceirizada ou, às vezes, mais perigosa; o código precisará ser reescrito do zero.
  7. Duplicar código é um mau hábito. Se você pratica algo, lentamente se torna uma segunda natureza e afeta as pessoas ao seu redor. Os desenvolvedores júnior veem você fazendo e também. Você deve praticar o que prega e criar o hábito de fazer a coisa certa. Você aprende mais. Escrever código não duplicado é mais difícil e mais desafiador. É um hábito gratificante.

Últimas notas sobre prevenção de duplicação de código excessivamente zeloso e resumo:

Isso já foi dito antes, mas às vezes evitar a duplicação faz com que você "se incline para trás" e faça coisas que são muito sofisticadas (ou sem importância) para que outras pessoas possam entender. Escrever código ilegível (ou, como chamamos de brincadeira, código de "preservação de trabalho") é um problema em si mesmo, mesmo quando a prevenção de duplicação de código não está envolvida. No entanto, acho que, se a infra-estrutura e as melhores práticas corretas são instaladas desde o início, é muito mais fácil evitar a duplicação de código e as pessoas geralmente evitam fazer coisas não-intuitivas para evitar futuros montes desnecessários e ilegíveis de trabalho feitos para a prevenção de duplicação de código, se você faz as coisas desde o início.

O que está fazendo as coisas certas? Bem, essa é uma pergunta difícil de responder, mas uma coisa é definir quais métodos são necessários para o projeto e ver o que já foi implementado por outras pessoas (fora e) dentro da empresa e reutilizá-lo quando possível; documentando tudo o que você adiciona à base de código e tentando torná-lo um nível mais genérico do que deveria ser, mas é isso. Não exagere nos padrões de design apenas para tornar o código flexível onde ele não precisa estar.

wolfdawn
fonte