Quelle est une bonne pratique de code pour savoir quand créer une fonction / méthode pour de petits segments de code répétitifs?

12

Plusieurs fois au cours de l'écriture de programmes plus importants, je me suis demandé après combien de copies et de colles est-il sensé de mettre le code dans une fonction ou une méthode et quelle est la bonne règle de base? J'ai utilisé une règle empirique de quatre lignes ou plus et apparaissant plus de deux fois, puis j'ai créé une fonction / méthode simple contenant ce code. Pouvez-vous penser à une meilleure pratique ou offrir des conseils? Il s'agit plus d'une question générale sur le modèle de conception que d'une question spécifique à la langue.


la source

Réponses:

29

J'utilise des fonctions en partie pour documenter le code. L'appel d'une fonction avec un nom significatif facilite la compréhension du code. Dans certains cas, même une fonction avec une seule ligne est logique.

Par exemple, dans "Clean Code", Robert C. Martin donne l'exemple suivant: Lequel préférez-vous voir? Cette:

// Check to see if the employee is eligible for full benefits
if ((employee.flags & HOURLY_FLAG) &&
    (employee.age > 65))

Ou ca?

if (employee.isEligibleForFullBenefits())

Je ne suis pas toujours d'accord avec lui, mais dans ce cas, je le fais. Le code doit être lisible, non seulement lorsque vous l'écrivez et que vous connaissez tous les détails, mais également à 21 heures lorsque vous devez corriger des bogues dans le code de quelqu'un d'autre. Il n'est pas recommandé de regarder longtemps et d'essayer de comprendre tous les doubles négatifs. Si vous pouvez simplement mettre un nom dessus (non seulement des conditions, mais chaque morceau de code que vous écrivez), cela devient beaucoup plus simple.

Je n'ai jamais regretté de mettre quelque chose dans une fonction, et si vous êtes inquiet pour les performances, alors profilez d'abord.

omrib
la source
2
Suivre cette pratique simple vous permettra éventuellement d'écrire le code d'application à un niveau relativement élevé. Les petites fonctions sont regroupées en petites classes et bientôt vous convertissez les spécifications fonctionnelles en code presque mot pour mot.
kevin cline
11
J'ai adoré cet exemple. Soudain, vous n'avez plus besoin de ce commentaire. C'est une règle d'or : si votre commentaire peut être converti en nom de variable ou de fonction, faites-le!
Karoly Horvath
Je suis d'accord avec omrib ici, il s'agit souvent de nettoyer le code - ce qui le rend plus lisible que toute autre règle empirique. Si je finis par réutiliser quelque chose, je l'extraireai vers une méthode. Cependant, mon IDE et mes outils aident souvent à cela, c'est donc facile et rapide à faire.
Travis
+1 Ce type de code pourrait même être plus rapide, du moins s'il doit être édité en JIT - vous ne payez que pour ce que vous utilisez.
Job
1
également connu sous le nom d' intention révélant des noms .
rwong
13

Il existe un malentendu répandu selon lequel les appels de fonction ne doivent être effectués que pour éviter les segments de code répétitifs. Ma règle d'or est que toute unité logique de travail doit être transformée en fonction, même lorsqu'elle n'est utilisée qu'en un seul endroit. Cela conduit généralement à une meilleure lisibilité et vous permet d'écrire du code auto-documenté, où les noms de fonction remplacent les commentaires et vous n'avez pas besoin d'écrire des commentaires supplémentaires expliquant ce que vous faites.

Lie Ryan
la source
1
Voir à quelles longueurs les programmeurs iront afin d'éviter d'écrire un commentaire?
Alger
1
@Alger as they should
MatrixFrog
6

S'il est utilisé dans plus d' un endroit, et

  • il est susceptible de changer, ou
  • il est difficile de bien faire les choses

en faire ensuite une fonction ou une méthode. D'après mon expérience, de longs morceaux de code répétés tomberont naturellement dans l'une de ces catégories (généralement la première, mais les catégories se chevauchent beaucoup;). Bien sûr, tout ce qui doit être dans l'interface est également une fonction / méthode à part entière.

Fred Foo
la source
3
La question est: pourquoi n'écririez-vous pas une fonction pour un morceau de code fréquemment répété même s'il n'était pas difficile à obtenir correctement ou susceptible de changer? (Ma règle d'or: si c'est répété et plus long que d'appeler une fonction, faites-en une fonction)
Winston Ewert
J'irais encore plus loin. En tant que programmeur, vous devez éliminer toutes sortes de répétitions . Que ce soit dans la base de données (normaliser), certains tests manuels (le remplacer par des tests unitaires) ou le déploiement (l'automatiser).
Karoly Horvath
@Winston: cela dépend de la langue utilisée. Toutes les constructions ne peuvent pas être naturellement capturées en tant que fonction, la fonction peut prendre plus d'espace que le code d'origine (pensez à C et retournez par pointeur), les appels de fonction peuvent entraîner des frais généraux.
Fred Foo
@larsman, je suis curieux de savoir à quoi vous faites référence par "(pensez à C et revenez par pointeur)". Mais ce que vous dites, c'est ce que j'essayais de comprendre avec ma règle d'or. L'appel de la fonction doit être plus facile (c'est-à-dire capturer naturellement et prendre moins d'espace) que la mise en œuvre du contenu de la fonction.
Winston Ewert
Si un morceau de code calcule plusieurs valeurs, disons float x, int yet double density, puis mise en place de ces calculs en fonction C peut être plus compliqué que simplement répéter le code, car vous devez trouver un moyen d'obtenir les trois valeurs hors. Si les calculs répétés eux-mêmes sont triviaux, il est parfois préférable de simplement les laisser en ligne.
Fred Foo
4

Presque toujours, surtout si chaque doublon représente la même opération d'un point de vue conceptuel. Si elle est effectuée de la même manière, mais sur des types différents, effectuez une implémentation générique.

La seule raison pour laquelle je ne pense pas à cela est la maintenance: parfois, il pourrait être plus pratique d'éviter de créer une dépendance entre des choses distinctes, même au prix d'une certaine duplication.

Nicola Musatti
la source
Méfiez-vous du typage canard, si pour l'instant l'implémentation est similaire, mais la fonctionnalité est effectivement différente, alors la fusion des deux rend ennuyeux de se séparer. Surtout dans les langues avec un mauvais support IDE (hé, je travaille en C ++ ...)
Matthieu M.
D'un autre côté, en les séparant, vous avez deux fonctions qui font la même chose à tester, la moitié des chances que votre code soit exercé, deux endroits dans lesquels le même bogue peut apparaître et vous devez vous rappeler de corriger celui dans lequel le bogue n'a pas encore été détecté. J'aimerais continuer à travailler en C ++, malgré un mauvais support IDE ;-)
Nicola Musatti
1

Une recherche de « refactoring » vous mènera à de nombreuses ressources pour les «meilleures pratiques» de l'industrie pour ce processus très courant. L'article un peu célèbre, Once and Only Once est une excellente référence historique expliquant ce que certains considèrent comme des "meilleures pratiques" pour les préoccupations soulevées par votre question. En outre, le concept encore plus général est connu sous le nom de Don't Repeat Yourself (DRY) . Pour un ensemble de réponses vraiment approfondies à votre question, lisez le grand classique de Martin Fowler , Refactoring: Improving the Design of Existing Code , qui couvre certains des conseils les plus connus en matière de refactoring , ce que vous essayez intuitivement d'accomplir. !

John Tobler
la source
0

Si le code est répété exactement à plusieurs reprises et que la section répétée ne changera pas dans un avenir proche, je le décompose en fonction.

Steven D.
la source
1
si ça va changer, encore plus de raisons de le refactoriser. Ensuite, vous n'aurez qu'à le changer une fois
SHug
0

Cela dépend de la nature de la cohésion du code répété. Si la section répétée du code exécute une fonction spécifique, alors c'est un excellent candidat pour être transformé en une méthode, en partie à cause du principe DRY , en partie parce que si la fonction doit être optimisée ou corrigée, alors il n'y a qu'une seule section de code à traiter.

Si l'association est une coïncidence, il est préférable de répéter le code plutôt que d'en faire une méthode. Si vous devez ajouter quelque chose au milieu de l'une des séquences de code pour satisfaire l'une des utilisations de cet extrait, s'il se trouve dans une méthode, la modification que vous apportez peut affecter d'autres utilisations de cette méthode.

Voir l'article Wikipedia sur le concept de cohésion de code .

Jay Elston
la source
si l'association semble coïncidence, il est probable que les deux processus partagent une idée commune, et vous devriez probablement explorer si les deux processus sont en effet deux facettes de la même chose. Le plus souvent, c'est le cas.
Lie Ryan
0

Vous devez faire la distinction entre les fonctions au sens de programmation structurée et les méthodes d'une classe.

Dans votre exemple, ce que vous avez montré est une méthode en tant que telle ne doit pas être codée en ligne.

vous devrez peut-être valider une chaîne pour voir s'il s'agit d'un nombre ou non, dans ce cas, vous utilisez une fonction et la plupart des réponses précédentes s'appliquent.

Cette distinction est particulièrement importante dans les grands projets.

Dans la mesure du possible, essayez de séparer les règles métier (qui sont des méthodes) des algorithmes de calcul (qui sont de simples fonctions de programmation).

Aucune chance
la source