Pergunta

É geralmente aceite que copiar e colar a programação é uma má idéia, mas o que é a melhor maneira de lidar com uma situação onde você tem duas funções ou blocos de código que realmente do necessidade de estar em diferentes apenas algumas maneiras fazer generalizando-os extremamente bagunçado?

E se o código é substancialmente o mesmo, exceto para um menor poucas variações, mas essas poucas variações menores não estão nas coisas que são fáceis de fator de fora, quer através de adição de um parâmetro, métodos de modelo, ou algo parecido?

De modo mais geral, você já encontrou uma situação onde você iria admitir que um pouco de copiar-e-colar de codificação foi verdadeiramente justificada.

Foi útil?

Solução

pessoas

que eu ouvi dizer que o vai copiar e colar (duplicação limitando de código para no máximo dois casos) uma vez, como abstrações não pagar menos que você use o código em três lugares ou mais. () Eu, pessoalmente, tentar torná-lo um bom hábito de refatoração assim que eu vejo a necessidade.

Outras dicas

Esta pergunta sobre suas funções

"se esta pequena exigência muda, vou ter que mudar ambas as funções, a fim de satisfazê-lo?"

É claro que às vezes é aceitável. É por isso que as pessoas mantêm trecho de arquivos. Mas se você está cortando e colando o código, muitas vezes, ou com mais de algumas linhas, você deve pensar sobre o que torna uma sub-rotina. Por quê? porque as probabilidades de que você vai ter que mudar alguma coisa, e desta forma, você só precisa mudá-lo uma vez.

caso Médio é usar uma macro se você tiver tais disponíveis.

Sim, e é exatamente como você diz; menor, mas variações de difícil fator. Não flagelar-se se é realmente o que as chamadas situação para a.

Re é cut-and-passado nunca aceitável:

Sim. Quando o segmento é um pouco diferente e você está fazendo sistemas descartáveis ??(sistemas que estão lá por um curto período de tempo e não necessitam de manutenção). Caso contrário, sua geralmente melhor para extrair os pontos comuns fora.

segmentos Re que sósia, mas não exatamente iguais:

Se a diferença está nos dados, refatoração, extraindo a função e usar a diferença de dados como parâmetros (Se houver muitos dados para passar como um parâmetro, considere agrupá-los em um objeto ou estrutura). Se a diferença for em algum processo na função, refactor usando padrão de comando ou modelo abstrato. Se ainda é difícil refatorar mesmo com esses padrões de projeto, então a sua função pode estar tentando alça para muitas responsabilidades por conta própria.

Por exemplo, se você tem um segmento de código que difere em dois segmentos - diff # 1, e diff # 2. E em diff # 1, você pode ter diff1A, ou diff1B, e por diff # 2 você pode ter diff2A e diff2B.

Se diff1A & diff2A estão sempre juntos, e diff1B & diff2B estão sempre juntos, então diff1A & diff2A pode estar contido em uma classe de comando ou uma implementação abstrata modelo e diff1B & diff2B em outro.

No entanto, se existem vários combinação (ou seja diff1A & diff2A, diff1A & diff2B, diff1B & diff2A, diff1B & diff2B), então você pode querer repensar a sua função, pois pode estar tentando lidar com muitas responsabilidades por conta própria .

declarações Re SQL:

Usando lógicas (if-else, loops de) para construir o seu SQL dinamicamente sacrifícios legibilidade. Mas a criação de todas as variações de SQL seria difícil de manter. Então, se encontram no meio do caminho e usar o SQL segmentos. Extrato de pontos em comum como segmentos SQL e criar todas as variações SQL com esses segmentos SQL como constantes.

Por exemplo:

private static final String EMPLOYEE_COLUMNS = " id, fName, lName, status";

private static final String EMPLOYEE_TABLE = " employee";

private static final String EMPLOYEE_HAS_ACTIVE_STATUS = " employee";

private static final String GET_EMPLOYEE_BY_STATUS =
  " select" + EMPLOYEE_COLUMNS + " from" + EMPLOYEE_TABLE + " where" + EMPLOYEE_HAS_ACTIVE_STATUS;

private static final String GET_EMPLOYEE_BY_SOMETHING_ELSE =
  " select" + EMPLOYEE_COLUMNS + " from" + EMPLOYEE_TABLE + " where" + SOMETHING_ELSE;

Na base de código da minha empresa, temos uma série de cerca de 10 ou declarações tão grandes peludo SQL que têm um alto grau de comunalidade. Todas as afirmações têm um núcleo comum, ou pelo menos um núcleo que difere apenas por uma ou duas palavras. Então, você poderia grupo das 10 declarações em 3 ou 4 grupos que agregam apêndices comuns para o núcleo, novamente com talvez uma ou duas palavras diferentes em cada apêndice. De qualquer forma, acho que das 10 instruções SQL como conjuntos em um diagrama de Venn com sobreposição significativa.

Nós escolhemos código estas declarações de tal forma a evitar qualquer duplicação. Assim, não é uma função (tecnicamente, um método Java) para construir o comunicado. Leva alguns parâmetros que representam a palavra ou dois de diferença no núcleo comum. Então, é preciso um functor para construir os apêndices, o que naturalmente também é parametrizado com mais parâmetros para diferenças menores e mais functors para mais apêndices, e assim por diante.

O código é inteligente em que nenhum dos SQL é sempre repetido. Se você precisar modificar uma cláusula no SQL, modificá-lo em apenas um lugar e todas as instruções SQL 10 são alteradas em conformidade.

Mas o homem é o código difícil de ler. Sobre a única maneira de descobrir o que SQL vai ser executado para um determinado caso é para percorrer com um depurador e imprimir o SQL depois de ter sido completamente montado. E descobrir como uma função específica que gera um fits cláusula no quadro maior é desagradável.

Desde escrevendo isso, eu sempre quis saber se teria sido melhor apenas cortar-e-colar a consulta SQL 10 vezes. Claro que, se fizéssemos isso, qualquer alteração ao SQL pode ter que ocorrer em 10 lugares, mas os comentários podem ajudar a apontar-nos para os 10 lugares para atualização.

O benefício de ter o SQL compreensível e tudo em um lugar provavelmente superam as desvantagens de corte-e-colar o SQL.

Como Martin Fowler sugere,

fazer isso uma vez, tudo bem.

fazê-lo duas vezes, começa a cheirar.

fazê-lo três vezes, tempo para refactor .


EDIT: em resposta ao comentário, a origem do conselho é Don Roberts:

três strikes e você refatorar .

Martin Fowler descreve que em Refactoring capítulo 2, seção a regra de três (página 58).

ABSOLUTAMENTE NEEEVER ..

:)

Você pode postar o código em questão e ver que ele é mais fácil do que o que parece

Se for a única maneira de fazê-lo, em seguida, ir para ele. Muitas vezes (dependendo do idioma), você pode satisfazer pequenas alterações para a mesma função com um argumento opcional.

Recentemente, tive uma função add () e uma função de edição () em um script PHP. Ambos fizeram praticamente a mesma coisa, mas a função de edição () realizaram uma consulta UPDATE em vez de uma consulta INSERT. Eu apenas fiz algo como

function add($title, $content, $edit = false)
{
    # ...
    $sql = edit ? "UPDATE ..." : "INSERT ...";
    mysql_unbuffered_query($sql);
}

Trabalhou grandes - mas há outros momentos em que copy / paste é necessário. Não use algum caminho estranho, complicado para impedi-lo.

  1. Boa código é código reutilizável.
  2. Não reinventar a roda.
  3. Existem exemplos por uma razão: para ajudar você a aprender e, idealmente código melhor
  4. .

Você deve copiar e colar? Quem se importa! O que é importante é por você está copiar e colar. Eu não estou tentando obter filosófica sobre alguém aqui, mas vamos pensar sobre isso praticamente:

É por preguiça? "Blah blah, eu fiz isso antes ... Eu só estou mudando alguns nomes de variáveis ??.. feito."

Não é um problema se ele já estava bom código antes que você copiou e colou-lo. Caso contrário, você está perpetuando código de baixa qualidade por preguiça que vai morder a sua bunda no caminho.

Será que é porque você não entende? "Droga .. Eu não entendo como isso funciona de função, mas eu me pergunto se ele vai trabalhar no meu código .." Pode! Isto pode poupar tempo no momento imediato quando você está estressado que você tem um prazo de nove horas e você está olhando fixamente eyed vermelho para um relógio em torno 04:00

Você vai entender este código quando você retornar a ela? Mesmo se você comentar isso? Não realmente - depois de milhares de linhas de código, se você não entender o que o código está fazendo como você escrevê-lo como você vai entender a voltar para ele semanas, meses mais tarde? Tentar aprendê-la, apesar de toda tentação de outra forma. Digitá-lo para fora, isso vai ajudar a cometê-lo para a memória. Cada linha que você digita, pergunte a si mesmo o que essa linha está fazendo e como ele contribui para o objectivo geral dessa função. Mesmo se você não aprender isso dentro para fora, que você pode ter uma chance de reconhecê-lo, no mínimo, quando você retornar a ele mais tarde.

Assim - copiando e colando código? Bem se você está consciente das implicações do que você está fazendo. De outra forma? Não fazê-lo. Além disso, verifique se você tem uma cópia da licença de qualquer código do 3o partido você copiar e colar. Parece senso comum, mas você ficaria surpreso quantas pessoas não.

Eu evito cortar e colar como a peste. É ainda pior do que o seu clone primo e modificar. Se confrontado com uma situação como sua Estou sempre pronto para usar um processador de macro ou outro script para gerar as diferentes variações. Na minha experiência de um ponto único de verdade é extremamente importante.

Infelizmente o processador macro C não é muito bom para este fim por causa das exigências citando irritantes para newlines, expressões, declarações e argumentos. Eu odeio escrever

#define RETPOS(E) do { if ((E) > 0) then return; } while(0)

mas que citar é uma necessidade. Eu, muitas vezes, usar o pré-processador C, apesar de suas deficiências, porque não adicionar outro item para o conjunto de ferramentas e que por isso não necessitam de mudar o processo de construção ou Makefiles.

Eu estou contente este é marcado como subjetiva, porque é certamente! Este é um excessivamente vago exemplo, mas eu imagino que, se você tiver o código suficiente para que é duplicado que você poderia resumo dessas seções e manter as diferentes partes diferente. A ponto de não copiar-colar é para que você não acabam por ter código que é difícil de manter e frágil.

A melhor maneira (além de converter em funções comuns ou utilizar macros) é colocar comentários. Se você comentar, onde o código é copiado e, eo que a semelhança é, e as diferenças, ea razão para fazê-lo ... então você estará ok.

Se você achar que você tem funções que são basicamente o mesmo, mas em diferentes cenários exigem pequenos ajustes, é o seu design que é o problema. Use polimorfismo e composição em vez de bandeiras ou copiar-colar.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top