8
votes

Pourquoi certaines fonctions sont-elles extrêmement longues? (Idées nécessaires pour une recherche académique!)

J'écris un petit projet de recherche académique sur des fonctions extrêmement longues. Évidemment, je ne cherche pas Exemples pour une mauvaise programmation , mais pour des exemples de fonctions de longue durée de 100, 200 et 600 lignes qui a du sens.

Je vais enquêter sur la source du noyau Linux à l'aide d'un script écrit pour un Master écrit dans l'Université hébraïque , qui mesure différents paramètres comme le nombre de lignes de code, Complexité des fonctions (mesurée par MCC) et d'autres friandises. Au fait, c'est une étude soignée sur l'analyse de code et un matériau de lecture recommandé.

Je suis intéressé si vous êtes peut penser à une bonne raison pour laquelle une fonction devrait être exceptionnellement longue? Je vais regarder dans C, mais des exemples et des arguments de n'importe quelle langue seraient d'une grande utilisation.


0 commentaires

15 Réponses :


14
votes

beaucoup de valeurs dans un relevé d'interrupteur?


7 commentaires

J'allais dire la même chose - j'ai vu d'énormes fonctions comme des relevés de commutation géants dans une machine à états pour un contrôleur


J'ai vu d'énormes déclarations de commutation dans d'anciens programmes Windows. La question est que ces programmes devaient-ils être écrits de cette façon? La réponse est non.


Quel est le problème avec une énorme déclaration de commutation? C'est simple, même si longtemps.


J'ai vu d'énormes instructions de commutation dans les anciens programmes Linux. Et de nouveaux programmes Linux. Je ne pense pas que ce soit un problème de Windows seulement ;-) Ni pas toujours un problème, comme David l'a souligné.


@David Peut-être que vous n'avez jamais vu de programme Windows "réel" avec tandis que des boucles imbriquées à l'intérieur des commutateurs imbriqués à l'intérieur des commutateurs imbriqués à l'intérieur tandis que des boucles imbriquées à l'intérieur des commutateurs. Tout dans la même fonction, bien sûr. Ce style de programmation a été encouragé par le premier livre de Petzold, à partir duquel une génération de programmeurs Windows a appris de mauvaises habitudes.


J'en ai vu beaucoup d'entre eux en haut de la liste la plus longue du noyau, mais que des déclarations de commutation à long terme sont-elles transformées en tables d'expédition?


Si cela ne convient pas à un seul écran, il est beaucoup plus difficile de saisir. Une fois, j'ai vu une fonction de commutateurs imbriqués de 16 000 lignes. C'était incompréhensible.



3
votes

Lire le chapitre du code de McConnell complet sur les sous-routines, il a des directives et des pointeurs de lorsque vous devriez casser les choses en fonctions. Si vous avez un algorithme où ces règles ne s'appliquent pas, cela peut être une bonne raison pour avoir une fonction longue.


1 commentaires

Pouvez-vous penser à un exemple concret que je peux lier?



1
votes

Parfois, je me trouve en train de écrire un fichier plat (à utiliser par des tiers) qui implique des en-têtes, des remorques et des enregistrements de détail qui sont tous liés. Il est plus facile d'avoir une longue fonction dans le but de calculer des résumés qu'il est de concevoir un système de transmettre des valeurs à travers de nombreuses petites fonctions.


0 commentaires

18
votes

Je peux attraper Flak pour cela, mais la lisibilité. Une exécution hautement série, mais indépendante qui pourrait être divisée en n appels de fonction (de fonctions utilisées nulle part ailleurs) ne bénéficie pas vraiment de la décomposition. Sauf si vous comptez rencontrer un maximum arbitraire sur la longueur de la fonction comme avantage.

Je préfère faire défiler les blocs de code de code de la fonction Naviguez dans l'ordre que de naviguer dans l'ensemble du fichier, frappez n Fonctions.


8 commentaires

Nitpicking - C'est Flak (au sens du feu AA), un "Flack" est une personne PR.


Ah, tu es. Tant que je ne sais pas et que je vais, je vais bien.


La prestation est que si les morceaux sont vraiment indépendants, vous pouvez prouver en les brisant réellement. Ni vous ni aucun maintenance ne peut stocker l'état dans des variables qui durent la durée de la fonction, sont modifiées dans de nombreux endroits différents et n'ont que des invariants très compliqués. Une fois qu'une fonction devient longue, une variable locale de grande portée a de nombreuses caractéristiques méchantes des globaux. En le divisant dans des fonctions, vous ne pouvez rien modifier de ne pas avoir de référence visiblement. Bien sûr, si la décomposition réussit, vous avez principalement prouvé que vous n'avez pas besoin d'avoir dérangé ;-)


... et vous pouvez atteindre 50% des avantages simplement en emballant chaque morceau des accolades et ne déclarant pas trop dans l'étendue la plus externe de la fonction.


Je peux également le voir à ma satisfaction en lisant le code et en plaçant des déclarations variables sensiblement. Une fois que le code est propre et en place, il est beaucoup plus facile de voir quand quelqu'un fait quelque chose de stupide en regardant le diff. J'ai tendance à rejeter comme raisonnement "parce que quelqu'un pourrait faire quelque chose de mal si vous les laissez". Code, comme n'importe quoi, ne devrait pas être un état de nounou. Si vous ne faites pas confiance à quelqu'un pour écrire un bon code, ne les embauchez pas. Les gens font des erreurs bien sûr, mais ce sont les critiques de code et les QA.


Je ne suis pas d'accord avec vous, Patros. J'ai eu une fonction d'environ 1000 lignes de long. Il a géré 3 stades de traitement différentes qui n'étaient faits que dans cette fonction, mais il était impossible de dire où chaque étape a commencé et où elle s'est terminée, ou d'avoir une idée de l'ensemble du flux. Je le divisions dans environ 10 fonctions que la fonction principale appelée, et que je puisse avoir une bonne image du flux, même si ces fonctions n'étaient appelées nulle part ailleurs. Pensez-y comme effondrant les en-têtes dans un document texte.


@Patros: Bien sûr, je ne dis pas que vous trouverez votre code plus facile à gérer si vous suivez une convention spécifique. Je dis que d'autres personnes seront, pour l'avantage décrits, ce qui est qu'ils ne doivent pas avoir à lire plusieurs pages de code pour voir la structure série / indépendante de votre fonction. Personnellement, je suis assez ambivalent sur la question: à moins que le guide de style n'impose autrement, j'écris beaucoup plus de fonctions que certaines personnes aimeraient. Je ne pense pas que la jonglerie 5 ou 6 variables est un problème.


@Nathan aurait été impossible de casser la seule fonction en 10 morceaux en utilisant des espaces et des commentaires? De toute évidence, les deux méthodes ont leurs mérites et leurs inconvénients, et pour moi, le facteur le plus important sera basé sur votre éditeur ou votre IDE. J'ai tendance à ne pas le faire en C, où j'utilise surtout Vim. En C ++ ou Java, je suis plus susceptible de puisque les IDI, j'utilise le soutien à des fonctions et gardez une pile de tout ce que vous avez visité jusqu'à présent.



4
votes

Les fonctions peuvent être plus longues au fil du temps, surtout si elles sont modifiées par de nombreux ensembles de développeurs.

cas au point: je récemment (~ 1yr ou 2 il y a 2 ans) a refacturé un code de traitement d'image hérité à partir de 2001 ou de sorte que contenait quelques fonctions de plusieurs milliers de lignes. Pas quelques-uns plusieurs mille lignes - quelques fonctions de plusieurs milliers de lignes.

Au fil des ans, il y a une telle fonctionnalité qui leur a été ajoutée sans vraiment mettre dans l'effort de les refroidir correctement.


2 commentaires

Donc, c'est une mauvaise programmation en soi, impho - forcé, peut-être, par les circonstances.


À droite, mais la question était "Pourquoi certaines fonctions sont-elles extrêmement longues?" - C'est ma réponse :-)



0
votes

Le code d'analyse XML a souvent des pousses de traitement de caractères d'échappement dans une fonction de configuration.


0 commentaires

11
votes

Quelque chose généré à partir d'autres sources, c'est-à-dire une machine à états finie d'un générateur d'analyseur ou similaire. Si cela n'est pas destiné à la consommation humaine, les préoccupations esthétiques ou de la maintenabilité sont sans importance.


0 commentaires

2
votes

Le code généré peut générer des fonctions très très longues.


0 commentaires

1
votes

Un point que je pense a une roulement est que différentes langues et outils ont une structure lexicale différente associée aux fonctions.

Par exemple, Java vous permet de supprimer des avertissements avec une annotation. Il peut être souhaitable de limiter la portée de l'annotation et de protéger la fonction à cette fin. Dans une autre langue, briser cette section dans sa propre fonction pourrait être complètement arbitraire.

controversé: dans JavaScript, j'ai tendance à créer uniquement des fonctions dans le but de réutiliser le code. Si un extrait n'est exécuté que dans un endroit, je le trouve chargé de sauter autour du ou des fichiers suivant les spaghettis des références de fonction. Je pense que les fermetures facilitent et renforcent donc des fonctions [parent] plus longues. Étant donné que JS est une langue interprétée et que le code réel est envoyé sur le fil, il est bon de conserver la longueur du code, la création de déclarations correspondantes et de références ne permet pas d'aider (cela pourrait être considéré comme une optimisation prématurée). Une fonction doit être assez longue dans JS avant de décider de le couper pour le but exprès de «garder les fonctions courtes».

Encore une fois dans JS, l'ensemble de la «classe» est techniquement une fonction avec de nombreuses sous-fonctions fermées, mais il existe des outils pour vous aider à gérer.

D'autre part dans JS, les variables ont une portée de la longueur de la fonction et c'est donc un facteur pouvant limiter la longueur d'une fonction donnée.


0 commentaires

1
votes

Les très longues fonctions que je rencontre ne sont pas écrites en C. Vous devrez donc décider si cela s'applique à votre recherche ou non. Ce que j'ai à l'esprit, vous trouverez des fonctions de PowerBuilder plusieurs centaines de lignes, étant ainsi pour les raisons suivantes:

  • Ils ont été écrits il y a plus de 10 ans, par des personnes à cette époque n'avaient pas en tête des normes de codage.
  • L'environnement de développement rend un peu plus difficile de créer des fonctions. À peine une bonne excuse, mais c'est une de ces petites choses qui vous décourage parfois de travailler correctement, et je suppose que quelqu'un vient de se faire paresseux.
  • Les fonctions ont évolué au fil du temps, ajoutant à la fois du code et de la complexité.
  • Les fonctions contiennent d'énormes boucles, chaque itération gérant éventuellement différents types de données de manière différente. Utiliser des dizaines (!) De variables locales, de variables de membre et de certains globaux, ils sont devenus extrêmement complexes.
  • Être aussi vieux et moche, personne n'ose les refléter dans des parties plus petites. Avoir autant de cas spéciaux qui leur sont manipulés, les distinguer est de demander des ennuis.

    C'est encore un autre endroit où les mauvaises pratiques de programmation évidentes rencontrent la réalité. Alors que tout étudiant de première année CS pouvait dire que ces bêtes sont mauvaises, personne ne dépenserait d'argent pour les rendre plus jolies (étant donné qu'au moins pour le moment, ils livrent toujours).


0 commentaires

0
votes

Les fonctions que je traite (pas d'écriture) deviennent longues car elles sont élargies et étendues et que personne ne dépense le temps de rétracter les fonctions. Ils continuent de continuer à ajouter de la logique aux fonctions sans pensée à la grande image.

Je traite de beaucoup de développement CUT-N-CLET ...

Donc, pour le papier, un aspect à regarder est un mauvais plan d'entretien / cycle, etc.


0 commentaires

2
votes

Les seuls que j'ai récemment codés sont là où il n'aboutit pas beaucoup pour les rendre plus petits ni rendre le code moins lisible. La notion qu'une fonction sur une certaine longueur est en quelque sorte intrinsèquement mauvaise est simplement un dogme aveugle. Comme tout dogme appliqué aveuglément, OT soulage le suiveur de la nécessité de penser à ce qui s'applique dans une affaire donnée ...

Exemples récents ...

analyse et validation d'un fichier de configuration avec un nom simple = la structure de valeur dans une matrice, convertissant chaque valeur que je le trouve, il s'agit d'une instruction de commutation massive, d'un cas par option de configuration. Pourquoi? Je pourrais m'être divisé en beaucoup d'appels vers des fonctions triviales 5/6. Cela ajouterait environ 20 membres privés à ma classe. Aucun d'entre eux n'est réutilisé ailleurs. L'affacter en plus petits morceaux n'a pas ajouté suffisamment de valeur pour en valoir la peine, il y a donc de même que le prototype. Si je veux une autre option, ajoutez un autre cas.

Un autre cas est le code de communication client et serveur dans la même application et son client. Beaucoup d'appels à lire / écrire qui peut échouer, auquel cas je caution et retourne faux. Cette fonction est donc fondamentalement linéaire et a des points de caution (s'ils ont échoué, renvoient) après presque chaque appel. Encore une fois, rien à gagner en rendant plus petit et aucun moyen de le rendre plus petit.

Je devrais également ajouter que la plupart de mes fonctions sont quelques «dépiscuites» et je m'efforce de rester plus complexes de la conserver à un «scieful», simplement parce que je peux regarder la fonction entière à la fois. Il est correct pour les fonctions qui sont fondamentalement linéaires de nature et n'ont pas beaucoup de bouclures complexes ou de conditions à suivre pour que le flux soit simple. En tant que note finale, je préfère appliquer un raisonnement coûts-avantages lors de la détermination du code au refacteur et de la priorité en conséquence. Aide à éviter le projet perpétuellement semi-fini.


0 commentaires

1
votes

De loin le plus courant que je vois / écriture sont des relevés de commutation longs ou des instructions semi-commutateurs pour les types qui ne peuvent pas être utilisés dans les relevés de commutation de cette langue (déjà mentionnés quelques fois). Le code généré est un cas intéressant, mais je me concentre sur le code humain ici. En regardant mon projet actuel, la seule fonction vraiment longue non incluse ci-dessus (296 LOC / 650 lot) est un code de cow-boy que j'utilise comme une évaluation précoce de la production d'un générateur de code que je prévois d'utiliser à l'avenir. Je vais certainement le refroidir, ce qui l'enlève de cette liste.

Il y a de nombreuses années, je travaillais sur certains logiciels informatiques scientifiques qui avaient une fonction longue. La méthode utilisait un grand nombre de variables locales et refactorise la méthode empêchée d'obtenir une différence mesurable par profilage. Même une amélioration de 1% de cette section du code enregistré des heures de temps de calcul, la fonction est donc restée longue. J'ai beaucoup appris depuis lors, alors je ne peux donc pas parler à la façon dont je gérerais la situation aujourd'hui.


0 commentaires

0
votes

Quelques idées non mentionnées explicitement:

  • Tâches répétitives, par exemple La fonction lit une table de base de données avec des colonnes 190 et doit les envoyer en tant que fichier plat (en supposant que les colonnes doivent être traitées individuellement, une boucle simple sur toutes les colonnes ne fera pas). Bien sûr, vous pouvez créer 19 fonctions, chaque sortie 10 colonnes, mais cela ne rendrait pas mieux le programme.
  • compliqué, API Verbose, comme OCI d'Oracle. Lorsque des actions apparemment simples nécessitent de grandes quantités de code, il est difficile de le casser dans de petites fonctions qui ont un sens.

0 commentaires

1
votes

Vitesse:

  • appeler une fonction signifie pousser à la pile, puis sauter, puis stockez à nouveau sur la pile, puis sautant à nouveau. Si vous utilisez des paramètres sur la fonction, vous avez généralement plusieurs pousses supplémentaires. Li> ul>

    considérer une boucle: p> xxx pré>

    à l'intérieur d'une boucle, toutes ces pousses et saute peut être un facteur. P>

    Ceci était En grande partie résolue avec la présentation de Fonctions en ligne sur C99 et officieusement avant cela, mais un code écrit auparavant, ou a été créé avec la compatibilité à l'esprit, peut avoir été long pour cette raison. P >

    Inline a également des flux, certains sont décrits sur le Lien de fonctions en ligne .

    EDIT: strong> p>

    Comme exemple de la manière dont un appel à une fonction peut rendre un programme plus lent: p>

    jmp .L2
    .L3:
    movl    $.LC0, (%esp)
    call    printf
    addl    $1, -8(%ebp)
    .L2:
    cmpl    $999, -8(%ebp)
    jle .L3
    


1 commentaires

Merci et Toda Raba. Je pense que le problème majeur de la fonction en ligne est leur liste d'arguments huje, dans de nombreux cas (aucun jeu de mots).