ti-enxame.com

As funções longas são aceitáveis ​​se tiverem estrutura interna?

Ao lidar com algoritmos complicados em linguagens com suporte para funções aninhadas (como Python e D), muitas vezes escrevo funções enormes (porque o algoritmo é complicado), mas mitigo isso usando funções aninhadas para estruturar o código complicado. As funções enormes (mais de 100 linhas) ainda são consideradas más, mesmo que sejam bem estruturadas internamente por meio do uso de funções aninhadas?

Edit: Para aqueles que não estão familiarizados com Python ou D, as funções aninhadas nessas linguagens também permitem acesso ao escopo da função externa. Em D, esse acesso permite a mutação de variáveis ​​no escopo externo. Python ele só permite a leitura. Em D você pode desabilitar explicitamente o acesso ao escopo externo em uma função aninhada, declarando-o static.

24
dsimcha

Lembre-se sempre da regra, as funções fazem uma coisa e a fazem bem! Se você puder fazer isso, evite funções aninhadas.

Isso dificulta a legibilidade e os testes.

21
Bryan Harrington

Alguns argumentaram que funções curtas podem ser mais sujeitas a erros do que funções longas .

Card e Glass (1990) apontam que a complexidade do projeto envolve realmente dois aspectos: a complexidade dentro de cada componente e a complexidade das relações entre os componentes.

Pessoalmente, descobri que um código de linha reta bem comentado é mais fácil de seguir (especialmente quando não foi você quem o escreveu originalmente) do que quando ele é dividido em várias funções que nunca são usadas em outro lugar. Mas realmente depende da situação.

Acho que a principal conclusão é que, quando você divide um bloco de código, está trocando um tipo de complexidade por outro. Provavelmente existe um ponto ideal em algum lugar no meio.

12
Jonathan Tran

O ideal é que toda a função possa ser visualizada sem a necessidade de rolar. Às vezes, isso não é possível. Mas se você puder dividi-lo em partes, isso tornará a leitura do código muito mais fácil.

Eu sei que assim que pressiono Page Up/Down ou movo para uma seção diferente do código, só consigo me lembrar de 7 +/- 2 coisas da página anterior. E, infelizmente, alguns desses locais serão usados ​​ao ler o novo código.

Sempre gosto de pensar na minha memória de curto prazo como os registros de um computador (CISC, não RISC). Se você tiver toda a função na mesma página, poderá acessar o cache para obter as informações necessárias de outra seção do programa. Se a função inteira não couber em uma página, isso seria o equivalente a sempre enviar qualquer memória para o disco após cada operação.

9
jsternberg

Por que usar funções aninhadas em vez de funções externas normais?

Mesmo que as funções externas sejam usadas apenas em sua função anteriormente grande, isso ainda torna toda a bagunça mais fácil de ler:

DoThing(int x){
    x += ;1
    int y = FirstThing(x);
    x = SecondThing(x, y);
    while(spoo > fleem){
        x = ThirdThing(x+y);
    }
}

FirstThing(int x){...}
SecondThing(int x, int y){...}
ThirdThing(int z){...}
4
Fishtoaster

Eu não tenho o livro na minha frente neste momento (para citar), mas de acordo com o Code Complete o "sweetspot" para o comprimento da função estava em torno de 25-50 linhas de código de acordo com sua pesquisa.

Há momentos em que é normal ter funções longas:

  • Quando a complexidade ciclomática da função é baixa. Seus colegas desenvolvedores podem ficar um pouco frustrados se tiverem que olhar para uma função que contém uma instrução if gigante e a instrução else desse if não está na tela ao mesmo tempo.

Os momentos em que não está ok ter funções longas:

  • Você tem uma função com condicionais profundamente aninhados. Faça um favor aos seus colegas leitores de código, melhore a legibilidade dividindo a função. Uma função fornece uma indicação ao leitor de que "Este é um bloco de código que faz uma coisa". Também pergunte a si mesmo se o comprimento da função indica que ela está fazendo muito e precisa ser fatorada para outra classe.

O resultado final é que a manutenção deve ser uma das maiores prioridades da sua lista. Se outro desenvolvedor não pode olhar para o seu código e obter uma "essência" do que o código está fazendo em menos de 5 segundos, seu código não fornece "metadados" suficientes para dizer o que está fazendo. Outros desenvolvedores devem ser capazes de dizer o que sua classe está fazendo apenas olhando para o navegador de objetos no IDE em vez de ler mais de 100 linhas de código).

Funções menores têm as seguintes vantagens:

  • Portabilidade: é muito mais fácil mover a funcionalidade (seja dentro da classe de refatoração para uma diferente)
  • Depuração: quando você olha para o rastreamento de pilha, é muito mais rápido apontar um erro se você estiver olhando para uma função com 25 linhas de código em vez de 100.
  • Legibilidade - o nome da função informa o que um bloco inteiro de código está fazendo. Um desenvolvedor de sua equipe pode não querer ler esse bloco se não estiver trabalhando com ele. Além disso, na maioria dos IDEs modernos, outro desenvolvedor pode compreender melhor o que sua classe está fazendo lendo os nomes das funções em um navegador de objetos.
  • Navegação - a maioria dos IDE permite que você pesquise o nome das funções. Além disso, a maioria dos IDEs modernos tem a capacidade de visualizar o código-fonte de uma função em outra janela, isso permite que outros desenvolvedores vejam sua função longa em 2 telas (no caso de monitores múltiplos) em vez de fazê-los rolar.

A lista continua.....

3
Korbin

Não gosto da maioria das funções aninhadas. Lambdas se enquadram nessa categoria, mas geralmente não me sinalizam, a menos que tenham mais de 30-40 caracteres.

A razão básica é que ela se torna uma função localmente densa com recursão semântica interna, significando que é difícil para mim envolver meu cérebro, e é apenas mais fácil enviar algumas coisas para uma função auxiliar que não confunde o espaço do código.

Eu considero que uma função deve fazer sua coisa. Fazer Outras Coisas é o que outras funções fazem. Portanto, se você tem uma função de 200 linhas Doing Its Thing, e tudo flui, está tudo bem.

2
Paul Nathan

Não, funções de várias páginas não são desejáveis ​​e não devem passar na revisão de código. Eu costumava escrever funções longas também, mas depois de ler Martin Fowler Refatorando , parei. Funções longas são difíceis de escrever corretamente, difíceis de entender e difíceis de testar. Nunca vi uma função com 50 linhas que não fosse mais facilmente compreendida e testada se fosse dividida em um conjunto de funções menores. Em uma função de várias páginas, quase certamente há classes inteiras que devem ser fatoradas. É difícil ser mais específico. Talvez você deva postar uma de suas funções longas para Revisão de código e alguém (talvez eu) possa mostrar a você como melhorá-la.

1
kevin cline

Isso é aceitável? Essa é realmente uma pergunta que só você pode responder. A função alcança o que precisa? É sustentável? É 'aceitável' para os outros membros da sua equipe? Nesse caso, é isso que realmente importa.

Edit: Eu não vi nada sobre as funções aninhadas. Pessoalmente, eu não os usaria. Eu usaria funções regulares em vez disso.

1
GrandmasterB

Quando estou programando em python, gosto de voltar atrás depois de escrever uma função e me perguntar se ela segue o "Zen do Python" (digite 'import this' em seu python = intérprete):

Belo é melhor do que feio.
Explícito é melhor do que implícito.
Simples é melhor que complexo.
Complexo é melhor do que complicado.
Plano é melhor do que aninhado.
Esparso é melhor do que denso.
Contagens de legibilidade.
Casos especiais não são especiais o suficiente para quebrar as regras.
Embora a praticidade supere a pureza.
Os erros nunca devem passar silenciosamente.
A menos que explicitamente silenciado.
Diante da ambigüidade, recuse a tentação de adivinhar.
Deve haver uma - e de preferência apenas uma - maneira óbvia de fazer isso.
Embora esse caminho possa não ser óbvio no início, a menos que você seja holandês.
Agora é melhor do que nunca.
Embora nunca seja frequentemente melhor do que certo agora.
Se a implementação é difícil de explicar, é uma má ideia.
Se a implementação for fácil de explicar, pode ser uma boa ideia.
Os namespaces são uma ótima ideia - vamos fazer mais desses!

0
user17721

Coloque-os em um módulo separado.

Assumindo que sua solução não é mais inchada do que precisar que você não tem muitas opções. Você já dividiu as funções em diferentes subfunções, então a questão é onde colocá-las:

  1. Coloque-os em um módulo com apenas uma função "pública".
  2. Coloque-os em uma classe com apenas uma função "pública" (estática).
  3. Aninhe-os em uma função (como você descreveu).

Agora, tanto a segunda quanto a terceira alternativas são, em certo sentido, aninhadas, mas a segunda alternativa, para alguns programadores, não parece tão ruim. Se você não descarta a segunda alternativa, não vejo muitos motivos para descartar a terceira.

0
skyking