Qual deve ser o comprimento máximo de uma função? [fechadas]

38

Qual deve ser o comprimento máximo de uma função?

E há casos que são uma exceção a isso?

    
por Peter Mortensen 11.01.2014 / 05:40
fonte

18 respostas

41

Desde que eu embarquei nessa louca raquete em 1970, vi exatamente um módulo que realmente precisava para ser mais do que uma página impressa (cerca de 60 linhas). Eu vi muitos módulos que eram mais longos.

Por falar nisso, eu escrevi módulos que eram mais longos, mas eles eram geralmente grandes máquinas de estados finitos, escritas como grandes declarações de switch.

Parte do problema parece ser que os programadores atualmente não são ensinados a modularizar as coisas.

Padrões de codificação que maximizam o desperdício de espaço vertical também parecem fazer parte do problema. (Eu tenho ainda para conhecer um gerente de software que leu href="https://en.wikipedia.org/wiki/Gerald_Weinberg#Publications"> Psicologia da Programação de Computadores ". Weinberg aponta que vários estudos têm mostrado que a compreensão do programador é essencialmente limitada ao que o programador pode ver em um determinado momento. Se o programador tiver que rolar ou virar uma página, sua compreensão cai significativamente: eles precisam se lembrar e abstrair.)

Continuo convencido de que muitos dos ganhos de produtividade do programador bem documentados de FORTH foram devidos a o sistema FORTH "block" para o código-fonte: os módulos eram limitados a um máximo absoluto de 16 linhas de 64 caracteres. Você poderia fatorar infinitamente, mas você não poderia, sob nenhuma circunstância, escrever uma rotina de 17 linhas.

    
por 15.12.2018 / 18:38
fonte
27

Qual é o tamanho certo, realmente?

Depende do idioma que você usa, mas em geral (e para meu gosto pessoal):

  • Idealmente , menos de 25 linhas.
  • Aceitavelmente , menos de 35 linhas.

Se é mais, então é algo que preciso voltar mais tarde e retrabalhar.

Mas realisticamente , qualquer tamanho que seja necessário quando você precisar entregar algo e que faça mais sentido no momento de expô-lo dessa forma, torna ainda mais fácil às vezes que alguém analise antes do envio. (mas ainda voltar a isso mais tarde).

(Recentemente, minha equipe executou um programa em nossa base de código: encontramos uma classe com 197 métodos e outra com apenas 3 métodos, mas um deles foi de 600 linhas. Jogo bonito: qual é o pior dos 2 males?)

Agora, para uma resposta mais zen ... Em geral, é considerado uma boa prática (TM) citar um ou dois grandes homens, então aqui vai:

Everything should be made as simple as possible, but not simpler. - A. Einstein

Perfection is finally attained not when there is no longer anything to add, but when there is no longer anything to take away. - A. de Saint Exupéry

Adendo aos estilos de comentários

Como um adendo a isso, suas funções devem ter nomes claros explicando sua intenção. Quanto aos comentários, geralmente não comento dentro de uma função:

  • comentários dizem "por quê?" ,
  • código diz "como?" .

Um bloco de comentários no topo de cada função (que requer explicação) é suficiente. Se a sua função é pequena e os nomes das funções são explícitos o suficiente, você só precisa dizer o que deseja alcançar e por quê. Eu uso comentários inline somente para campos em alguns idiomas ou em block starts para funções que quebram as regras de 25-35 linhas se a intenção não estiver clara. Eu uso um comentário de bloco dentro do código quando ocorre uma situação excepcional (um bloco catch onde você não precisa ou quer fazer nada deve ter um comentário dizendo por que, por exemplo).

Para mais, leia minha resposta em Estilo e recomendações de código de comentário

    
por 12.04.2017 / 09:31
fonte
12

Na minha opinião, todas as funções devem ser tão pequenas quanto possível. Cada função deve fazer apenas uma coisa e fazê-lo bem. Isso realmente não responde a questão do comprimento máximo, mas é mais a minha opinião sobre a duração das funções.

Para usar as palavras do tio Bob, "Extraia até você simplesmente não pode extrair mais. Extraia até cair. "

    
por 15.12.2018 / 18:39
fonte
10

Qual deve ser a altura máxima de um prédio? Depende de onde está a construção ou a altura que você quer que seja.
Você pode obter respostas diferentes de pessoas diferentes que vêm de uma cidade diferente.
Algumas funções de script e manipuladores de interrupção do kernel são muito longos.

    
por 18.12.2010 / 16:54
fonte
9

Um método que funciona para mim é: Posso fazer com que uma parte de uma função mais longa forneça um nome que faça sentido. Eu acho que o comprimento de um método não é tão importante como uma boa nomenclatura. O método deve fazer o que o nome diz, nem mais nem menos. E você deve ser capaz de dar um bom nome. Se você não pode nomear seu método como bom, o código provavelmente não é bom em conjunto.

    
por 18.12.2010 / 17:46
fonte
9

Desde que seja necessário fazer o que precisa fazer, mas não mais.

    
por 18.12.2010 / 18:09
fonte
6

Eu acho que há um trade off. Se você tiver muitos métodos curtos, é mais difícil depurá-los do que um método longo. Se você tiver que pular pelo editor 20 ou 30 vezes diferentes para rastrear uma chamada de método, será difícil manter tudo isso em mente. Enquanto isso, se houver um método claro bem escrito, mesmo que seja 100 linhas, muitas vezes é mais fácil mantê-lo na cabeça.

A verdadeira questão é por que os itens devem estar em métodos diferentes, e a resposta como dada acima é reutilização de código. Se você não está reutilizando o código (ou não sabe), pode fazer sentido deixá-lo em um método fácil de seguir e, quando precisar reutilizá-lo, divida as partes que precisam ser reutilizadas. usando em métodos menores.

Na realidade, parte do bom design de métodos é fazer métodos funcionalmente coesivos (essencialmente eles fazem uma coisa). O comprimento dos métodos não importa. Se uma função faz uma coisa bem definida e é 1.000 linhas do que é um bom método. Se uma função faz 3 ou 4 coisas e é apenas 15 linhas, então é um método ruim ...

    
por 18.12.2010 / 18:21
fonte
5

Acho mais fácil acompanhar o que estou fazendo se consigo ver toda a função de uma só vez. Então, aqui está como eu prefiro escrever funções:

  1. Curto o suficiente para caber no meu monitor com uma fonte razoável.
  2. Se precisar ser maior que # 1, curta o suficiente para imprimir em um pedaço de papel em uma fonte razoável.
  3. Se precisar ser maior que # 2, curta o suficiente para imprimir 2 em um pedaço de papel.

Eu raramente escrevo funções por mais tempo que isso. A maioria delas são declarações gigantes de switch C / C ++.

    
por 18.12.2010 / 19:08
fonte
5

A questão deve ser quantas coisas uma função deve fazer. E geralmente, é raro que você precise de 100 linhas para fazer uma coisa. Novamente, isso depende do nível a partir do qual você está olhando o código: Uma senha é uma senha? Ou é hashing e salvar a senha uma coisa?

Eu diria, comece salvando senha como uma função. Quando você sente que hashing é diferente e refatora o código. Eu não sou nenhum programador especialista por qualquer meio, mas IMHO, toda a idéia de funções começar pequeno é que quanto mais atômica suas funções são, maior a chance de reutilização de código, nunca tendo que fazer a mesma mudança em mais de um lugar , etc.

Eu vi o SQL procedimentos armazenados que executam mais de 1000 linhas. O número de linhas de procedimentos armazenados também é menor que 50? Eu não sei, mas faz a leitura do código, inferno. Não apenas você precisa continuar rolando para cima e para baixo, você precisa dar a algumas linhas de código um nome como "isto faz validação1", "isto atualiza no banco de dados", etc. - um trabalho que o programador deveria ter feito.

    
por 11.01.2014 / 08:57
fonte
5

De Complexidade ciclomática (Wikipedia):

The cyclomatic complexity of a section of source code is the count of the number of linearly independent paths through the source code.

  • Eu recomendo que você mantenha esse número abaixo de 10 em um único método. Se chegar a 10, então é hora de refatorar.

  • Existem ferramentas que podem avaliar seu código e fornecer um número de complexidade ciclomática.

  • Você deve se esforçar para integrar essas ferramentas ao seu canal de criação.

  • Não procure literalmente um tamanho de método, mas tente analisar sua complexidade e responsabilidades. Se tiver mais de uma responsabilidade, provavelmente é uma boa ideia refazer o fator. Se a sua complexidade ciclomática aumenta, então provavelmente é hora de re-fatorar.

  • Tenho quase certeza de que existem outras ferramentas que fornecem um feedback semelhante, mas ainda não tive a oportunidade de analisar isso.

por 11.01.2014 / 09:02
fonte
4

Normalmente, tento manter meus métodos / funções no que cabe na tela de um monitor de 1680x1050. Se não couber, use métodos / funções auxiliares para dividir a tarefa.

Ajuda a leitura na tela e no papel.

    
por 18.12.2010 / 16:35
fonte
4

Curto o suficiente para ser otimizado corretamente

Os métodos devem ser curtos para fazer exatamente uma coisa. A razão para isso é simples: assim, seu código pode ser otimizado adequadamente.

Em uma linguagem JIT-ted como Java ou C #, é importante que seus métodos sejam simples para que o compilador JIT possa produzir código rapidamente. Métodos mais longos e mais complicados exigem naturalmente mais tempo de JIT. Além disso, os compiladores JIT oferecem apenas algumas otimizações e apenas os métodos mais simples se beneficiam disso. Este fato foi até chamado em Effective C # de Bill Wagner.

Em uma linguagem de nível mais baixo, como C ou C ++, ter métodos curtos (talvez uma dúzia de linhas) também é importante porque dessa forma você minimiza a necessidade de armazenar variáveis locais na RAM em vez de em um registro. (Aka 'Register Spilling'.) Note, entretanto, que neste caso não gerenciado, o custo relativo de cada chamada de função pode ser bem alto.

E mesmo em uma linguagem dinâmica, como Ruby ou Python, ter métodos curtos também ajuda nas otimizações do compilador. Em uma linguagem dinâmica, quanto mais "dinâmica" for uma característica, mais difícil será otimizar. Por exemplo, um método longo, que aceita um X e pode retornar um Int, Float ou String, provavelmente será mais lento do que três métodos separados, cada um retornando apenas um único tipo. Isso ocorre porque, se o compilador sabe exatamente qual tipo a função retornará, ele também pode otimizar o site de chamada de função. (Por exemplo, não verificar conversões de tipo.)

    
por 19.12.2010 / 03:31
fonte
4

Para mim, uma função é qualquer tamanho que precisa ser. A maior parte do tempo que eu divido é quando reutilizo o código.

Basicamente, vou me ater ao principal 'alta coesão, baixo acoplamento' e não há restrição de tamanho.

    
por 11.01.2014 / 08:54
fonte
3

Eu não coloco um limite de linha dura em nada, porque algumas funções implementam algoritmos que são inerentemente complexos e qualquer tentativa de torná-los mais curtos tornaria as interações entre as novas funções mais curtas tão complicadas que o resultado líquido não seria reduzido. na simplicidade. Eu também não acredito que a idéia de que uma função deva fazer apenas "uma coisa" seja um bom guia, já que "uma coisa" em um alto nível de abstração pode ser "muitas coisas" em um nível inferior.

Para mim, uma função é definitivamente muito longa se seu tamanho causar violações sutis de DRY agora, e extrair parte da função para uma nova função ou classe poderia resolver isso. Uma função pode ser muito longa, se este não for o caso, mas uma função ou classe poderia ser facilmente extraída, o que tornaria o código mais modular, de uma maneira que provavelmente será útil diante de mudanças previsíveis no futuro. / p>     

por 18.12.2010 / 23:08
fonte
3

Depende muito do que está no código.

Eu tenho visto uma rotina de mil linhas que eu não tive problema. Era uma declaração de switch enorme, nenhuma opção ultrapassava uma dúzia de linhas e a única estrutura de controle em qualquer opção era um único loop. Nos dias de hoje, teria sido escrito com objetos, mas isso não era uma opção naquela época.

Eu também estou olhando para 120 linhas em um switch na minha frente. Nenhum caso excede 3 linhas - um guarda, uma tarefa e o intervalo. Está analisando um arquivo de texto, os objetos não são uma possibilidade. Qualquer alternativa seria mais difícil de ler.

    
por 01.01.2014 / 01:34
fonte
2

A maioria dos compiladores não se importa com o comprimento de uma função. Uma função deve ser funcional, mas deve ser fácil de entender, mudar e reutilizar para os seres humanos. Escolha o tamanho que melhor lhe convier.

    
por 20.12.2010 / 11:16
fonte
1

Minha regra geral é que uma função deve caber na tela. Existem apenas três casos que eu acho que tendem a violar isso:

1) Funções de despacho. Antigamente, eram comuns, mas a maioria deles é substituída pela herança de objetos nos dias de hoje. Objetos funcionam apenas dentro do seu programa, e assim você ainda verá funções de envio ocasionais ao lidar com dados que chegam de outro lugar.

2) Funções que executam um monte de etapas para atingir uma meta e onde as etapas não têm uma boa subdivisão. Você acaba com uma função que simplesmente chama uma longa lista de outras funções em ordem.

3) Como # 2, mas onde as etapas individuais são tão pequenas que são simplesmente embutidas em vez de chamadas separadamente.

    
por 23.12.2010 / 19:40
fonte
1

Talvez o comprimento da função não seja uma boa métrica. Tentamos usar a complexidade ciclomática , em métodos também, e uma das futuras regras de check-in de controle de fonte que a complexidade ciclomática em classes e os métodos devem ser menores que X.

Para os métodos, X é definido como 30 e isso é muito difícil.

    
por 11.01.2014 / 09:00
fonte