Les méthodes longues sont-elles toujours mauvaises? [fermé]


64

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

156
Tous les absolus sont mauvais. Toujours.
Joachim Sauer

30
Je vois les « méthodes d'extraction si vous pouvez les réutiliser » argument assez souvent (dans ce ou formes similaires), mais je n'y crois pas: si la méthode fait plus d'une chose, vous devez extraire les méthodes de celui - ci pour une meilleure lisibilité / maintenabilité même si ces nouvelles méthodes sont appelées à partir d’un seul endroit de votre code.
Joachim Sauer

4
@gnat: wow, une sorte d'insertion manuelle (via un pré-processeur) dans l'étape de compilation ne serait-elle pas une meilleure solution ici?
Joachim Sauer

11
L'un des meilleurs programmeurs que je connaisse a fait remarquer que si vous voulez vraiment une mesure, le nombre de variables locales est supérieur à la longueur réelle. Il travaillait sur un optimiseur de trajectoire complexe où le courage était une méthode de plusieurs centaines de lignes, mais la quantité d'état (variables locales) conservée était très petite.
Chuu

2
Les méthodes longues ne sont pas toujours mauvaises; mais ils sont quelque chose que vous devriez toujours regarder et demandez-vous "est-ce mauvais?"
Carson63000

Réponses:


80

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.


41
+1: "Non, les méthodes longues ne sont pas toujours mauvaises" mais elles sont presque toujours mauvaises
Binary Worrier

67
Les corps de méthode longs sont une odeur de code classique : ce n'est pas un problème en soi, mais c'est une indication qu'il y a probablement un problème.
Joachim Sauer

6
+1, mais je recommanderais quand même de vérifier la complexité cyclomatique de la méthode longue. Les valeurs élevées indiquent des méthodes qui sont effectivement impossibles à effectuer des tests unitaires (et les méthodes longues sont très rarement dépourvues de logique de flux de commande).
Daniel B

11
J'utilise des noms de méthodes pour minimiser les commentaires. Ce qui mène parfois à des choses comme "getSelectedNodeWithChildren", mais mon collègue me répète que mon code est bien lisible. J'essaie aussi d'éviter les abréviations, elles sont agréables à écrire, mais pas très agréables à lire.
K ..

4
@ da_b0uncer C'est aussi une politique que je suis. Il est plus difficile de lire du code que de l'écrire. Un effort supplémentaire lors de l'écriture pour rendre le code plus lisible est rentable.
deadalnix

55

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.


13
+1 pour avoir désavoué la partie toujours de la question et mis l'accent sur la viande: si les méthodes longues sont mauvaises ou non. Je pense que le PO cherche une justification comme si son scénario était un cas marginal, bien que, généralement, lorsque j'entende les gens expliquer leurs mauvaises pratiques comme étant nécessaires pour le scénario inhabituel, c'est simplement parce qu'ils n'ont pas essayé très durement d'utiliser de bonnes pratiques. Les scénarios inhabituels sont vraiment très rares, mais les méthodes longues sont malheureusement assez courantes.
Jimmy Hoffa

2
OK, en regardant la liste ci-dessus: lisibilité Je pense que l'expérience passée est augmentée par une méthode plus longue, contenant beaucoup de commentaires et bien formatée, plutôt que de devoir sauter d'un code à l'autre d'une méthode à l'autre, bien que cela soit probablement assez subjectif. Je ne m'attends pas à ce que les parties du code soient réutilisées. La majeure partie de la réutilisation du code est réalisée à partir de l'héritage pour le moment.
wobbily_col

1
@wobbily_col BTW, si vous recherchez un texte bien écrit qui explique les méthodes plus courtes, lisez les premiers chapitres de Clean Code , qui explique très bien l'explication.
Daniel B

5
@wobbily_col Vous dites que le fait de trop sauter pour comprendre le code avec de nombreuses méthodes est déroutant, je pense que le point manquant ici concerne l'importance de nommer. Si une méthode est bien nommée, vous n’avez pas besoin de la regarder pour savoir ce qu’elle fait, la méthode d’appel doit être parfaitement compréhensible, sans aucune connaissance sous-jacente des méthodes qu’elle appelle, par exemple avez-vous déjà utilisé 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.
Jimmy Hoffa

4
En passant, avoir une méthode qui a besoin de n paramètres est aussi une odeur de code et indique que la méthode peut faire plus d’une chose. Même chose pour avoir une méthode difficile à nommer. Et s'il a vraiment besoin de tous ces paramètres, ils font généralement partie d'un concept plus vaste qui peut et doit être inclus dans une classe à part. Bien sûr, nous pourrions trouver un exemple qui vaut mieux ne pas utiliser cette règle. Ce que je veux dire, c'est que si vous voyez une telle méthode, examinez-la de fond en comble, elle est probablement mauvaise en quelque sorte.
KL

28

Les méthodes longues sont toujours mauvaises, mais sont parfois meilleures que les alternatives.


5
sans explication, cette réponse peut devenir inutile si quelqu'un d'autre affiche une opinion contraire. Par exemple, si quelqu'un publie une réclamation du type "Les méthodes longues ne sont jamais mauvaises, mais sont parfois pires que les alternatives". , comment cette réponse aiderait-elle le lecteur à choisir deux opinions opposées? Envisagez de le modifier pour le rendre plus
beau

9

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!


7

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.)


6
"une déclaration d'affectation après l'autre" ... J'appellerais cela un "fichier de données". Pourquoi est-ce le code?
Joachim Sauer

3
@ JoachimSauer - L'analyse d'un fichier de données volumineux au moment de l'exécution dans une configuration Monte Carlo est une mauvaise idée. Une très, très mauvaise idée.
David Hammen

4
@DavidHammen: faites-le au moment de l'initialisation, comme si vous obligiez votre éditeur de liens / chargeur à le faire. Ou écrivez le fichier de données sous forme de structure C dans un fichier d’en-tête, au lieu de code C. Au moins, le chargeur se chargerait en tant que bloc de données.
Javier

3
@ Javier: Même au moment de l'initialisation, cela peut être une très mauvaise idée, du moins dans une configuration de Monte Carlo. Une simulation qui prend quelques minutes à initialiser, mais ne prend que quelques secondes, va à l’encontre de la réalisation de dizaines de milliers de exécutions dans la nuit. Le fait de modifier les tâches d’initialisation clés pour les compiler élimine ce problème. Nous avons essayé un certain nombre de techniques, y compris l'approche de la structure de données compilée. Cela ne fonctionne tout simplement pas ou serait très difficile à faire fonctionner dans certains cas (par exemple, un modèle de gravité énorme). La méthode du code en ligne droite est facile à générer et à vérifier automatiquement. C'est juste du code moche.
David Hammen

7
+1 histoire intéressante. Le code généré n'est pas vraiment un code source bien sûr, alors on pourrait dire que cela ne "brise" pas la règle. on suppose que le générateur de code lui-même avait de bonnes méthodes courtes
jk.

7

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.


1
"Il n'y a rien de mal à planifier dès le début de refactoriser avant de l'enregistrer." +1 pour cela. De nos jours, la plupart des IDE disposent d’outils de refactoring qui rendent cela extrêmement facile. Mais il existe une méthode inverse qui consiste à déléguer des tâches à des fonctions inexistantes, puis à compléter les méthodes, mais je n’ai jamais pu coder de cette façon, autant que j’ai essayé.
Tjaart

+1 pour "Devoir" [garder] la méthode la plus extérieure dans votre tête "est un signe que vous ne la divisez pas de la meilleure façon possible" "
Michael Shaw

4

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.


34
Il y a toujours au moins deux programmeurs impliqués: "vous" et "vous, dans trois semaines".
Joachim Sauer

3

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.


Aussi connu sous le nom "Une fonction doit faire une chose."
lorddev

3

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.

Les 497 longueurs maximales théoriques optimales sont souvent décrites comme une ou deux pages de liste de programmes, de 66 à 132 lignes. Les programmes modernes ont tendance à avoir des volumes de routines extrêmement courtes mélangés avec quelques routines plus longues.

Des décennies de preuves indiquent que des routines d'une telle longueur ne sont pas plus sujettes aux erreurs que des routines plus courtes. Laissez des problèmes tels que la profondeur d'imbrication, le nombre de variables et d'autres considérations liées à la complexité dicter 535 la longueur de la routine plutôt que d'imposer une longueur

Si vous voulez écrire des routines de plus de 200 lignes, soyez prudent. Aucune des études ayant fait état d'une réduction des coûts, d'une diminution du taux d'erreur ou des deux avec des routines plus volumineuses ne fait la distinction entre des tailles supérieures à 200 lignes et vous êtes forcé d'atteindre une limite supérieure de compréhensibilité lorsque vous transmettez 200 lignes de code. 536 restriction en soi.


2

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.


1
Le processus en 50 étapes peut probablement être résumé dans plusieurs compartiments. Les étapes 1 à 9 sont des vérifications de paramètres. Créez donc une nouvelle méthode appelée vérification de paramètres. (Je suis sûr qu'il y a des exemples où ce n'est pas possible. Je serais intéressé d'en voir un).
Sixtyfootersdude

@stytyfootersdude: Bien sûr, vous pourriez le casser. Je n'ai pas dit que c'était impossible, j'ai dit qu'il n'y avait rien à gagner à le casser. Bien que ce ne soit pas 50 étapes, j'ai frappé quelque chose comme ça: Créer un monde de jeu. Le n ° 1 a créé le monde vide, le n ° 2 a créé le terrain, puis toute une série d'étapes qui l'ont ensuite massé d'une manière ou d'une autre.
Loren Pechtel

& sixtyfootersdude: C’est incroyable de voir comment vous connaissez un code que vous n’avez jamais vu et comment l’améliorer.
gnasher729 le

2

Je voulais aborder l'exemple que vous avez donné:

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, à savoir trier / filtrer le jeu de requêtes, puis effectue petit à petit le traitement des objets renvoyés par ma requête.

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.


2

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:

function nextSlide() {
  var content = getNextSlideContent();
  hideCurrentSlide();
  var newSlide = createSlide(content);
  setNextSlide(newSlide);
  showNextSlide();
}

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

   if (hasMoreRecords()) { ... }

est certainement plus lisible que

if (file.isOpen() && i < recordLimit && currentRecord != null) { ... } 

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.


1

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.


0

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.


Aide à réduire le code quoi ?
Avner Shahar-Kashtan

@ AvnerShahar-Kashtan, il signifie probablement "duplication" :-)
Péter Török

0

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:

varaible_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 

à

Status status = new Status();
status.variable1 = 0;
status.variable2 = 0;
for object in queryset :
     if object.condition_condition_a and status.variable2 > 0 :
     status.variable1 += 1
     .....
     ...    
     . 
      more conditions to alter the variables (status)

return queryset, and context 

et ensuite

class Status {
    variable1 = 0;
    variable2 = 0;

    void update(object) {
        if object.condition_condition_a and variable2 > 0 {
            variable1 += 1
        }
    }
};

Status status = new Status();
for object in queryset :
     status.update(object);
     .....
     ...    
     . 
      more conditions to alter the variables (status)

return queryset, and context 

vous êtes maintenant sur la voie d'une méthode beaucoup plus courte mais bien plus utilisable et compréhensible.


0

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

foreach(var x in y)
{
    //do ALL the things
    //....
}

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:

foreach(var x in y)
{
    DoAllTheThings(x);
}
...
void DoAllTheThings(object x)
{
    //do ALL the things
    //....
}

À 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.


0

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:

void setDataValueAndCheckForRange(Data *data) {/*code*/} 

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):

void setDataValueAndCheckForRange(Data *data){ /*code */}
void addDataValuesAndCheckForRange(Data *result, Data *d1, Data *d2){ /*code*/}
void subDataValuesAndCheckForRange(Data *result, Data *d1, Data *d2){ /*code*/}
void mulDataValuesAndCheckForRange(Data *result, Data *d1, Data *d2){ /*code*/}

Cela doit être refactorisé pour:

bool isWithinRange(Data *d){ /*code*/ }
void setDataValue(Data *d) {/*code*/ if(isWithinRange(d)){/*continue*/}else{/*warn/abort*/} 
void addDataValue(Data *d, Data *d1, Data *d2) {/*code*/ if(isWithinRange(d)){/*continue*/}else{/*warn/abort*/} 
void subDataValue(Data *d, Data *d1, Data *d2) {/*code*/ if(isWithinRange(d)){/*continue*/}else{/*warn/abort*/} 
void mulDataValue(Data *d, Data *d1, Data *d2) {/*code*/ if(isWithinRange(d)){/*continue*/}else{/*warn/abort*/} 

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)


0

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.


Dans les langages fonctionnels, les méthodes longues sont beaucoup moins courantes.
Itsbruce
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.