Qual é uma boa prática de código de quando criar uma função / método para pequenos segmentos de código repetitivo?

12

Muitas vezes, ao escrever programas maiores, questionei depois de quantas cópias e pastas faz sentido colocar o código em uma função ou método e qual é uma boa regra geral? Eu tenho usado uma regra de ouro de quatro linhas ou mais e aparecendo mais de duas vezes, então eu faço uma função / método simples contendo esse código. Você pode pensar em uma prática melhor ou oferecer alguma indicação? Essa é mais uma questão geral de padrão de design, e não uma questão específica de idioma.


fonte

Respostas:

29

Eu uso funções parcialmente como uma maneira de documentar o código. Chamar uma função com um nome significativo facilita a compreensão do código. Em alguns casos, mesmo uma função com uma única linha faz sentido.

Por exemplo, em "Código Limpo", Robert C. Martin dá o seguinte exemplo: Qual deles você prefere ver? Este:

// Check to see if the employee is eligible for full benefits
if ((employee.flags & HOURLY_FLAG) &&
    (employee.age > 65))

Ou isto?

if (employee.isEligibleForFullBenefits())

Nem sempre eu concordo com ele, mas neste caso eu concordo. O código deve ser legível, não apenas quando você o escreve e conhece todos os detalhes, mas também às 21:00 quando você precisa corrigir erros no código de outra pessoa. Olhar para uma condição longa e tentar descobrir todos os negativos duplos não é recomendado. Se você pode simplesmente colocar um nome nele (não apenas as condições, mas todos os trechos de código que você escreve), isso se torna muito mais simples.

Nunca me arrependi de colocar algo em uma função e, se você estiver preocupado com o desempenho, faça um perfil primeiro.

omrib
fonte
2
Seguir essa prática simples permitirá que você escreva o código do aplicativo em um nível relativamente alto. As pequenas funções são coletadas em pequenas classes e logo você converte as especificações funcionais em código quase palavra por palavra.
Kevin cline
11
Adorei esse exemplo. De repente, você não precisa mais desse comentário. Esta é uma regra prática : se o seu comentário puder ser convertido em um nome de variável ou função, faça-o!
Karoly Horvath
Concordo com o omrib aqui, geralmente trata-se de limpar o código - o que o torna mais legível do que qualquer outra regra prática. Se eu acabar reutilizando algo, extrairei para um método. No entanto, meu IDE e ferramentas geralmente ajudam com isso, por isso é fácil e rápido de fazer.
Travis
+1 Esse tipo de código pode ser ainda mais rápido, pelo menos se precisar ser editado por JIT - você paga apenas pelo que usa.
Job
1
também conhecido como Nomes Reveladores de Intenção .
Rwong 5/09
13

Há um mal-entendido generalizado de que chamadas de função devem ser feitas apenas para evitar segmentos de código repetitivos. Minha regra geral é que qualquer unidade lógica de trabalho seja transformada em uma função, mesmo quando usada apenas em um único local. Isso geralmente leva a uma melhor legibilidade e permite que você escreva um código de auto-documentação, onde os nomes das funções substituem os comentários e você não precisa escrever comentários adicionais explicando o que está fazendo.

Lie Ryan
fonte
1
Veja a que duração os programadores irão para evitar escrever um comentário?
Alger
1
@Alger como deveriam
MatrixFrog
6

Se for usado em mais de um lugar, e

  • é provável que mude, ou
  • é complicado acertar

então faça uma função ou método. Pedaços longos de código repetido, na minha experiência, naturalmente se enquadram em uma dessas categorias (geralmente a primeira, mas as categorias se sobrepõem muito;). Obviamente, qualquer coisa que precise estar na interface também é uma função / método por si só.

Fred Foo
fonte
3
A questão é: por que você não escreveria uma função para um pedaço de código comumente repetido, mesmo que não fosse difícil acertar ou mudar? (Minha regra de ouro: se a sua repetida e mais, em seguida, chamar uma função, torná-lo uma função)
Winston Ewert
Eu iria ainda mais longe. Como programador, você deve eliminar todos os tipos de repetição . Seja no banco de dados (normalize), em alguns testes manuais (substitua-os por testes de unidade) ou na implantação (automatize-os).
Karoly Horvath
@ Winston: isso depende do idioma que está sendo usado. Nem toda construção pode ser capturada naturalmente como uma função; a função pode ocupar mais espaço do que o código original (pense em C e retorne pelo ponteiro); as chamadas de função podem gerar sobrecarga.
Fred Foo
@ Larsman, estou curioso sobre o que você está se referindo por "(pense C e retorne pelo ponteiro)". Mas o que você está dizendo é o que eu estava tentando entender com minha regra de ouro. Chamar a função deve ser mais fácil (ou seja, capturar naturalmente e ocupar menos espaço) do que implementar o conteúdo da função.
Winston Ewert
Se um pedaço de código calcula vários valores, digamos float x, int ye double density, então, configurá-los como uma função C pode ser mais complicado do que apenas repetir o código, já que você precisa criar uma maneira de obter todos os três valores. Se os cálculos repetidos são triviais, às vezes é melhor deixá-los alinhados.
Fred Foo
4

Quase sempre, especialmente se cada duplicata representa a mesma operação do ponto de vista conceitual. Se for executado da mesma maneira, mas em tipos diferentes, faça uma implementação genérica.

O único motivo para não fazer isso é o de manutenção: às vezes pode ser mais conveniente evitar criar uma dependência entre coisas separadas, mesmo ao custo de alguma duplicação.

Nicola Musatti
fonte
Cuidado com a digitação de patos, se por enquanto a implementação é semelhante, mas a funcionalidade é efetivamente diferente, então a fusão dos dois torna irritante como o inferno se dividir. Especialmente em idiomas com suporte IDE pobres (hey, eu trabalho em C ++ ...)
Matthieu M.
Por outro lado, mantendo-os separados, você tem duas funções que fazem a mesma coisa para testar, metade da chance de seu código ser exercido, dois lugares em que o mesmo bug pode surgir e você deve se lembrar de corrigir aquele em que o bug ainda não foi detectado. Eu gostaria de ainda estar trabalhando em C ++, fraco suporte IDE não obstante ;-)
Nicola Musatti
1

Uma pesquisa por " refatoração " levará você a muitos recursos para as "melhores práticas" do setor para esse processo muito comum. O artigo um pouco famoso, Once and Only Once, é uma ótima referência histórica, explicando o que alguns consideram "melhores práticas" para as preocupações levantadas por sua pergunta. Além disso, o conceito ainda mais geral é conhecido como Não se repita (DRY) . Para obter um conjunto realmente profundo de respostas à sua pergunta, leia o grande clássico de Martin Fowler , Refatoração: aprimorando o design do código existente , que aborda alguns dos conselhos mais conhecidos sobre refatoração , que é o que você está tentando intuitivamente realizar !

John Tobler
fonte
0

Se o código for exatamente repetido em mais de uma vez e a seção repetida não for alterada no futuro próximo, eu o divido em uma função.

Steven D.
fonte
1
se vai mudar, ainda há mais motivos para refatorá-lo. Então você só vai ter que mudá-lo uma vez
shug
0

Isso depende da natureza da coesão do código repetido. Se a seção repetida do código estiver executando uma função específica, é um excelente candidato para ser transformado em um método, em parte por causa do princípio DRY , em parte porque se a função precisar ser otimizada ou corrigida, haverá apenas uma seção de código para lidar.

Se a associação for coincidente, é melhor repetir o código do que transformá-lo em um método. Se você precisar adicionar algo no meio de uma das seqüências de código para satisfazer um dos usos desse snippet, se estiver em um método, a alteração que você fizer poderá afetar outros usos desse método.

Veja o artigo da Wikipedia sobre o conceito de coesão do código .

Jay Elston
fonte
se a associação parecer coincidente, é provável que os dois processos compartilhem uma ideia comum, e você provavelmente deve explorar se os dois processos são de fato duas facetas da mesma coisa. Mais frequentemente do que não, é.
Lie Ryan
0

Você precisa distinguir entre funções no sentido de programação estruturada e métodos de uma classe.

No seu exemplo, o que você mostrou é um método e, como tal, não deve ser codificado em linha.

pode ser necessário validar uma sequência para ver se é um número ou não; nesse caso, você usa uma função e a maioria das respostas anteriores se aplica.

Essa distinção é importante principalmente em grandes projetos.

Na medida do possível, lute para separar as regras de negócios (que são métodos) dos algoritmos de computação (que são funções de programação puras).

NoChance
fonte