Donc, en regardant autour de moi plus tôt, j'ai remarqué des commentaires sur les méthodes longues comme étant une mauvaise pratique.
Je ne suis pas sûr de toujours être d'accord sur le fait que les méthodes longues sont mauvaises (et aimeraient avoir l'avis des autres).
Par exemple, certaines vues Django traitent un peu les objets avant de les envoyer à la vue, une méthode longue consistant en 350 lignes de code. Mon code est écrit de manière à traiter les paramètres - trier / filtrer le jeu de requêtes, puis effectue petit à petit le traitement des objets renvoyés par ma requête.
Donc, le traitement est principalement une agrégation conditionnelle, qui a des règles assez complexes pour que cela ne puisse pas être fait facilement dans la base de données, donc j'ai des variables déclarées en dehors de la boucle principale qui sont ensuite modifiées pendant la boucle.
variable_1 = 0
variable_2 = 0
for object in queryset :
if object.condition_condition_a and variable_2 > 0 :
variable 1+= 1
.....
...
.
more conditions to alter the variables
return queryset, and context
Donc, selon la théorie, je devrais décomposer tout le code en méthodes plus petites, afin que la méthode d'affichage ait une longueur maximale d'une page.
Cependant, ayant déjà travaillé sur différentes bases de code dans le passé, je trouve parfois que cela rend le code moins lisible, alors que vous devez constamment passer d'une méthode à l'autre pour en comprendre toutes les parties, tout en gardant la méthode la plus externe dans votre tête.
Je trouve qu’une méthode longue, bien formatée, permet de voir la logique plus facilement, car elle ne se cache pas dans les méthodes internes.
Je pourrais factoriser le code en méthodes plus petites, mais il existe souvent une boucle interne utilisée pour deux ou trois choses, de sorte que le code soit plus complexe ou que les méthodes ne font qu'une chose, mais deux ou trois (alternativement Je pourrais répéter les boucles internes pour chaque tâche, mais alors il y aura un coup de performance).
Alors, y a-t-il un cas où les méthodes longues ne sont pas toujours mauvaises? Existe-t-il toujours un cas pour les méthodes d'écriture, lorsqu'elles ne seront utilisées qu'à un seul endroit?
MISE À JOUR: On dirait que j'ai posé cette question il y a plus d'un an.
J'ai donc refactoré le code après la réponse (mélangée) ici, en le divisant en méthodes. Il s'agit d'une application Django récupérant des ensembles complexes d'objets liés dans la base de données. L'argument de test est donc sorti (il aurait probablement fallu presque toute l'année pour créer des objets pertinents pour les scénarios de test. J'ai un type "cela doit être fait hier" environnement de travail avant que quiconque ne se plaint). La correction des bogues dans cette partie du code est maintenant un peu plus facile, mais pas de manière massive.
avant :
#comment 1
bit of (uncomplicated) code 1a
bit of code 2a
#comment 2
bit of code 2a
bit of code 2b
bit of code 2c
#comment 3
bit of code 3
maintenant:
method_call_1
method_call_2
method_call_3
def method_1
bit of (uncomplicated) code 1a
bit of code 2a
def method_2
bit of code 2a
bit of code 2b
bit of code 2c
def method_3
bit of code 3
la source
Réponses:
Non, les méthodes longues ne sont pas toujours mauvaises.
Dans le livre Code Complete , il est mesuré que les méthodes longues sont parfois plus rapides et plus faciles à écrire, et ne conduisent pas à des problèmes de maintenance.
En fait, ce qui est vraiment important, c'est de rester SEC et de respecter la séparation des préoccupations. Parfois, le calcul est long à écrire, mais ne posera vraiment pas de problème à l'avenir.
Cependant, d’après mon expérience personnelle, la plupart des méthodes longues tendent à manquer de séparation des préoccupations. En fait, les méthodes longues sont un moyen facile de détecter que quelque chose peut être erroné dans le code et qu'un soin particulier est nécessaire ici lors de la révision du code.
EDIT: Au fur et à mesure des commentaires, j'ajoute un point intéressant à la réponse. En fait, je vérifierais également les métriques de complexité de la fonction (NPATH, complexité cyclomatique ou encore meilleure CRAP).
En fait, je recommande de ne pas vérifier ces métriques sur les fonctions longues, mais d'inclure une alerte sur eux avec des outils automatisés (tels que checkstyle pour java par exemple) ON EVERY FUNCTION.
la source
La plupart de l'accent semble être ici autour du mot toujours . Oui, les absolus sont mauvais, et le génie logiciel est presque autant un art que la science, et tout ça ... mais je vais devoir dire que pour l'exemple que vous avez donné, la méthode serait meilleure si elle était scindée up. Voici les arguments que j'utiliserais généralement pour justifier la division de votre méthode:
Lisibilité: Je ne suis pas sûr des autres, mais je ne peux pas lire 350 lignes de code rapidement. Oui, si c'est mon propre code et que je peux en déduire beaucoup, je pourrais le parcourir très rapidement, mais c'est tout. Considérez combien cette méthode serait plus facile à lire si elle consistait en 10 appels à d’autres méthodes (chacune avec un nom descriptif). Ce faisant, vous avez introduit une couche dans le code et la méthode de haut niveau donne un aperçu succinct au lecteur de ce qui se passe.
Modifier - pour mettre cela sous un jour différent, réfléchissez-y comme ceci: comment expliqueriez-vous cette méthode à un nouveau membre de l’équipe? Il a sûrement une structure que vous pouvez résumer comme suit: "eh bien, on commence par faire A, puis B, puis parfois C, etc.". Avoir une courte méthode "overview" appelant d'autres méthodes rend cette structure évidente. Il est extrêmement rare de trouver 350 lignes de code qui n'en bénéficient pas; le cerveau humain n’est pas censé gérer des listes de centaines d’articles, nous les regroupons.
Réutilisation: les méthodes longues ont généralement une faible cohésion - elles font souvent plus d'une chose. La faible cohésion est l'ennemi de la réutilisation; Si vous combinez plusieurs tâches en une seule méthode, elle sera réutilisée dans moins d’endroits que ce qu’elle aurait dû être.
Testabilité et cohésion: j'ai mentionné la complexité cyclomatique dans un commentaire ci-dessus - c'est une assez bonne mesure de la complexité de votre méthode. Il représente la limite inférieure du nombre de chemins uniques dans votre code, en fonction des entrées (edit: corrigé selon le commentaire de MichaelT). Cela signifie également que pour bien tester votre méthode, vous devez avoir au moins autant de tests que votre nombre de complexité cyclomatic. Malheureusement, lorsque vous mettez en place des morceaux de code qui ne dépendent pas vraiment les uns des autres, vous ne pouvez être sûr de ce manque de dépendance et la complexité a tendance à se multiplier. Vous pouvez considérer cette mesure comme une indication du nombre de choses différentes que vous essayez de faire. Si c'est trop élevé, il est temps de diviser pour conquérir.
Refactoring et structure: Les méthodes longues sont souvent le signe qu'une structure manque dans le code. Souvent, le développeur ne parvenait pas à identifier les points communs entre les différentes parties de cette méthode et à définir une ligne de démarcation entre elles. Se rendre compte qu'une méthode longue est un problème et essayer de la diviser en méthodes plus petites constitue la première étape sur un chemin plus long pour identifier réellement une meilleure structure pour l'ensemble. Peut-être avez-vous besoin de créer une classe ou deux; ce ne sera pas forcément plus complexe à la fin!
Je pense aussi que dans ce cas, l'excuse pour avoir une méthode longue est "... certaines variables déclarées en dehors de la boucle principale sont ensuite modifiées pendant la boucle". Je ne suis pas un expert en Python, mais je suis à peu près certain que ce problème pourrait être résolu de manière triviale par une forme de renvoi par référence.
la source
someVar.toString()
et ressenti vous aviez besoin de voir le code de toString pour savoir ce qu'il fait? Vous venez de lire juste après parce que la méthode de nommage est bonne.Les méthodes longues sont toujours mauvaises, mais sont parfois meilleures que les alternatives.
la source
Les méthodes longues sont une odeur de code . Ils indiquent généralement que quelque chose ne va pas, mais ce n'est pas une règle absolue. Habituellement, les cas où ils sont justifiés impliquent un grand nombre de règles d’état et relativement complexes (comme vous l’avez découvert).
En ce qui concerne votre autre question, il est souvent utile de séparer des blocs de logique en méthodes distinctes, même si elles ne sont appelées qu'une seule fois. Cela facilite la compréhension de la logique de haut niveau et peut rendre la gestion des exceptions un peu plus propre. Tant que vous n'avez pas à entrer vingt paramètres pour représenter l'état de traitement!
la source
Les méthodes longues ne sont pas toujours mauvaises. Ils sont généralement un signe qu'il pourrait y avoir un problème.
Sur le système sur lequel je travaille, nous avons une demi-douzaine de méthodes de plus de 10 000 lignes. L'un a actuellement une longueur de 54 830 lignes. Et c'est bon.
Ces fonctions ridiculement longues sont très simples et sont générées automatiquement. Ce gros monstre d'une longueur de 54 830 lignes contient les données de mouvements polaires quotidiennes du 1er janvier 1962 au 10 janvier 2012 (notre dernier communiqué). Nous publions également une procédure permettant à nos utilisateurs de mettre à jour ce fichier généré automatiquement. Ce fichier source contient les données de mouvement polaire de http://data.iers.org/products/214/14443/orig/eopc04_08_IAU2000.62-now , traduites automatiquement en C ++.
La lecture de ce site Web à la volée n’est pas possible dans une installation sécurisée. Il n'y a pas de lien avec le monde extérieur. Télécharger le site Web en tant que copie locale et analyser en C ++ n'est pas une option non plus; l'analyse syntaxique est lente et doit être rapide. Téléchargement, traduction automatique en C ++ et compilation: vous avez maintenant quelque chose de rapide. (Ne le compilez pas optimisé. Le temps nécessaire à un compilateur d'optimisation pour compiler 50 000 lignes de code extrêmement simple est incroyable. Il faut plus d'une demi-heure sur mon ordinateur pour compiler ce fichier optimisé. Et l'optimisation n'apporte absolument rien. Il n’ya rien à optimiser, c’est un simple code en ligne droite, une déclaration d’affectation après une autre.)
la source
Disons simplement qu'il y a de bonnes et de mauvaises manières de rompre une longue méthode. Avoir à «garder la méthode la plus externe dans votre tête» est un signe que vous ne la divisez pas de la manière la plus optimale ou que vos sous-méthodes sont mal nommées. En théorie, il existe des cas où une méthode longue est préférable. En pratique, c'est extrêmement rare. Si vous ne savez pas comment rendre une méthode plus courte lisible, demandez à quelqu'un de revoir votre code et de lui demander spécifiquement des idées pour raccourcir les méthodes.
En ce qui concerne les boucles multiples provoquant un impact sur les performances, il n’ya aucun moyen de le savoir sans mesurer. Plusieurs petites boucles peuvent être considérablement plus rapides si cela signifie que tout ce dont il a besoin peut rester dans le cache. Même s'il y a un impact négatif sur les performances, il est généralement négligeable en faveur de la lisibilité.
Je dirai que souvent les méthodes longues sont plus faciles à écrire , même si elles sont plus difficiles à lire . C'est pourquoi ils prolifèrent même si personne ne les aime. Il n'y a rien de mal à planifier dès le début de refactoriser avant de l'enregistrer.
la source
Les méthodes longues peuvent être plus efficaces en termes de calcul et d'espace, il peut être plus facile de voir la logique et de les déboguer. Cependant, ces règles ne s'appliquent vraiment que lorsqu'un seul programmeur touche ce code. Le code va être difficile à étendre s’il n’est pas atomique, essentiellement la prochaine personne devra recommencer à zéro, puis déboguer et tester cela prendra pour toujours car il n’utilise aucun bon code connu.
la source
Il existe quelque chose que nous appelons la décomposition fonctionnelle, qui consiste à décomposer vos méthodes les plus longues en méthodes plus petites chaque fois que cela est possible. Comme vous avez mentionné que votre méthode implique le tri / filtrage, il est préférable de disposer de méthodes ou de fonctions distinctes pour ces tâches.
Justement, votre méthode devrait être axée sur l'exécution d'une tâche seulement.
Et si elle a besoin d'appeler une autre méthode pour une raison quelconque, faites-le autrement, continuez avec celle que vous écrivez déjà. Également pour des raisons de lisibilité, vous pouvez ajouter des commentaires. Classiquement, les programmeurs utilisent des commentaires multilignes (/ ** / en C, C ++, C # et Java) pour la description des méthodes et utilisent des commentaires d’une seule ligne (// en C, C ++, C # et Java). Il existe également de bons outils de documentation disponibles pour une meilleure lisibilité du code (par exemple, JavaDoc ). Vous pouvez également consulter les commentaires XML si vous êtes un développeur .Net.
Les boucles ont une incidence sur les performances du programme et peuvent entraîner une surcharge d'application si elles ne sont pas utilisées correctement. L'idée est de concevoir votre algorithme de manière à utiliser le moins possible de boucles imbriquées.
la source
C'est parfaitement correct d'écrire de longues fonctions. Mais cela dépend du contexte, que vous ayez vraiment besoin ou non. Par exemple, certains des meilleurs algorithmes s'expriment mieux lorsqu'il s'agit d'un morceau. D'autre part, un grand pourcentage de routines dans les programmes orientés objet seront des routines d'accès, qui seront très courtes. Certaines des longues routines de traitement qui ont de longues cas de commutation, si les conditions peuvent être optimisées via des méthodes pilotées par des tables.
Code Complete 2 traite très bien de la longueur des routines.
la source
Un autre vote que c'est presque toujours faux. Je trouve deux cas de base où c'est la bonne réponse, cependant:
1) Une méthode qui en gros appelle simplement un tas d’autres méthodes et ne fait pas vraiment de travail. Vous avez un processus qui prend 50 étapes à accomplir, vous obtenez une méthode contenant 50 appels. En général, il n'y a rien à gagner en essayant de rompre cela.
2) les répartiteurs. La conception de la programmation orientée objet s'est débarrassée de la plupart de ces méthodes, mais les sources de données entrantes sont par nature des données et ne peuvent donc pas suivre les principes de la programmation orientée objet. Il n’est pas tout à fait inhabituel d’avoir une sorte de routine de répartition dans le code qui gère les données.
Je dirais aussi que l’on ne devrait même pas considérer la question quand il s’agit de choses générées automatiquement. Personne n'essaie de comprendre ce que le code généré automatiquement fait, peu importe si cela est facile à comprendre pour un humain.
la source
Je voulais aborder l'exemple que vous avez donné:
Dans mon entreprise, notre plus gros projet est construit sur Django et nous avons également des fonctions de vision longue (beaucoup ont plus de 350 lignes). Je dirais que la nôtre n’a pas besoin d’être aussi longue, et ils nous font mal.
Ces fonctions de vue effectuent un grand nombre de travaux liés qui doivent être extraits dans le modèle, les classes auxiliaires ou les fonctions auxiliaires. En outre, nous finissons par réutiliser des vues pour faire différentes choses, qui devraient plutôt être divisées en vues plus cohérentes.
Je soupçonne que vos opinions ont des caractéristiques similaires. Dans mon cas, je sais que cela cause des problèmes et je travaille pour apporter des changements. Si vous n'êtes pas d'accord pour dire que cela cause des problèmes, vous n'avez pas besoin de le réparer.
la source
Je ne sais pas si quelqu'un a déjà mentionné cela, mais l'une des raisons pour lesquelles les longues méthodes sont mauvaises est qu'elles impliquent généralement plusieurs niveaux d'abstraction. Vous avez des variables de boucle et toutes sortes de choses qui se passent. Considérons la fonction fictive:
Si vous faisiez toute l'animation, le calcul, l'accès aux données, etc. dans cette fonction, cela aurait été un désastre. La fonction nextSlide () conserve une couche d'abstraction cohérente (le système d'état des diapositives) et en ignore les autres. Cela rend le code lisible.
Si vous devez constamment utiliser des méthodes plus petites pour voir ce qu'elles font, l'exercice de division de la fonction a échoué. Ce n'est pas parce que le code que vous lisez n'est pas évident dans les méthodes enfants que les méthodes enfants sont une mauvaise idée, mais simplement que cela a été fait de manière incorrecte.
Lorsque je crée des méthodes, je les divise généralement en méthodes plus petites, comme une sorte de stratégie de division et de conquête. Une méthode comme
est certainement plus lisible que
Droite?
Je suis d'accord sur le fait que les énoncés absolus sont mauvais, mais je suis également d'accord pour dire qu'une méthode longue est mauvaise.
la source
Histoire vraie. Une fois, j'ai rencontré une méthode de plus de deux mille lignes. La méthode avait des régions qui décrivaient ce qu’elle faisait dans ces régions. Après avoir parcouru une région, j'ai décidé de faire une méthode d'extraction automatisée, en la nommant d'après le nom de la région. au moment où j’avais terminé, la méthode n’était plus que 40 appels de méthode d’une cinquantaine de lignes chacun et tout fonctionnait de la même manière.
Ce qui est trop grand est subjectif. Parfois, une méthode ne peut pas être décomposée plus loin que ce qu’elle est actuellement. C'est comme écrire un livre. La plupart des gens conviennent que les longs paragraphes doivent généralement être scindés. Mais parfois, il n’ya qu’une idée et sa division est source de plus de confusion que la longueur de ce paragraphe.
la source
Le but d’une méthode est d’aider à réduire la régurgitation du code. Une méthode doit avoir une fonction spécifique dont elle est responsable. Si vous finissez par ressasser du code à de nombreux endroits, vous risquez que le code produise des résultats inattendus si les spécifications que le logiciel est conçu pour répondre sont modifiées.
Pour une méthode de 350 lignes, cela suggérerait qu'une grande partie des tâches qu'elle effectue sont répliquées ailleurs, car il est inhabituel d'exiger une telle quantité de code pour effectuer une tâche spécialisée.
la source
Ce ne sont pas vraiment les longues méthodes qui sont mauvaises, mais plutôt les laisser comme ça, c'est mauvais.
Je veux dire que l'acte réel de refactoriser votre échantillon de:
à
et ensuite
vous êtes maintenant sur la voie d'une méthode beaucoup plus courte mais bien plus utilisable et compréhensible.
la source
Je pense que le fait que la méthode soit très longue est une chose à vérifier, mais certainement pas un anti-modèle instantané. La grande chose à rechercher dans les méthodes énormes est beaucoup de nidification. Si tu as
et le corps de la boucle n'est pas extrêmement localisé (vous pouvez lui envoyer moins de 4 paramètres), il est probablement préférable de le convertir en:
À son tour, cela peut considérablement réduire la longueur d'une fonction. Assurez-vous également de rechercher le code en double dans la fonction et de le déplacer dans une fonction distincte.
Enfin, certaines méthodes sont simplement longues et compliquées et vous ne pouvez rien faire. Certains problèmes nécessitent des solutions qui ne se prêtent pas à une codification facile. Par exemple, une syntaxe grammaticale très complexe peut constituer une méthode très longue pour laquelle vous ne pouvez vraiment rien faire sans aggraver la situation.
la source
La vérité est que cela dépend. Comme mentionné, si le code ne sépare pas les préoccupations et essaie de tout faire d'une seule méthode, c'est un problème. La séparation du code en plusieurs modules facilite la lecture du code, ainsi que l’écriture de code (par plusieurs programmeurs). Adhérer à un module (classe) par fichier source est une bonne idée pour commencer.
Deuxièmement, en ce qui concerne les fonctions / procédures:
est une bonne méthode si elle vérifie la plage de "données" uniquement. C'est une mauvaise méthode lorsque la même plage s'applique à plusieurs fonctions (exemple de code incorrect):
Cela doit être refactorisé pour:
RÉUTILISER le code autant que possible. Et cela est possible lorsque chaque fonction de votre programme est assez simple (pas nécessairement facile).
CITATION: La montagne est composée de minuscules grains de terre. L'océan est constitué de minuscules gouttes d'eau .. (- Sivananda)
la source
Les méthodes longues tendent à être "mauvaises" dans les langages impératifs qui favorisent les déclarations, les effets secondaires et la mutabilité, précisément parce que ces fonctionnalités augmentent la complexité et donc les bugs.
Dans les langages de programmation fonctionnels, qui favorisent les expressions, la pureté et l’immuabilité, les motifs de préoccupation sont moins nombreux.
Dans les langages fonctionnels et impératifs, il est toujours préférable de factoriser les fragments de code réutilisables dans des routines de niveau supérieur communes, mais dans les langages fonctionnels qui prennent en charge l'étendue lexicale avec des fonctions imbriquées, etc., il est en fait préférable d'encapsuler pour masquer les sous-routines dans le haut. -fonction de niveau (méthode) que de les répartir dans d'autres fonctions de niveau supérieur.
la source