web-dev-qa-db-fra.com

Qu'est-ce que cela signifie pour une méthode ou une fonction de faire une chose?

Qu'est-ce que cela signifie lorsque vous dites qu'une méthode ou une fonction ne devrait faire qu'une seule chose?

Peut-il faire quelques choses tant qu'il a un nom cohérent?

Faut-il éviter les routines avec le mot "et" en eux?

Veuillez fournir des exemples concrets.

Remarque: veuillez ne pas confondre cette question avec le principe de responsabilité unique qui concerne les classes et ne signifie PAS "les classes ne doivent faire qu'une seule chose".

5
Piovezan

Si je vous dis de "sortir les poubelles", je vous ai demandé de faire une chose. C'est une idée cohérente. Cela signifie-t-il qu'il ne peut pas être décomposé en plus de choses? Non.

Tout peut être décomposé en plus de choses. Si je vous dis que cette fonction devrait faire une chose, je ne vous dis pas qu'elle ne devrait manipuler qu'un seul sac poubelle ou un seul quark quantique. Je vous dis que si une fonction nommée "sortir la corbeille" implémente également "apporter le courrier" ça va me surprendre et m'ennuyer.

Vous pouvez maintenant affirmer qu'il est logique d'apporter le courrier lorsque vous sortez la poubelle. C'est très bien. Où vous vous êtes trompé, c'était le nom.

"Faites vos corvées" convient, mais c'est choquant. C'est un sac à main qui ne vous dit pas exactement ce qu'il y a à l'intérieur. Mais cela vous dit ce qui devrait ou ne devrait pas être à l'intérieur de la fonction. C'est différent qu'auparavant car c'est un niveau d'abstraction plus élevé. C'est pourquoi c'est encore une chose.

On pourrait dire que cela fait deux choses. Mais je pourrais affirmer que sortir les poubelles implique de marcher, de lier les sacs et d'ouvrir les portes. Il n'y a rien qui soit une chose. Mais il y a des choses. Des choses claires. Les choses qui disent ces choses n'appartiennent pas à cette chose. Ces choses ont des noms cohérents. Les noms sont exactement le facteur limitant ici.

"Traiter les ordures et le courrier" est mauvais surtout parce qu'il vous dit exactement ce qu'il y a à l'intérieur. Il vous indique les détails de mise en œuvre. Il n'a pris aucune responsabilité pour communiquer la seule chose pour laquelle il existe. Il vous dit simplement ce qu'il contient.

Compte tenu de cela, que devriez-vous trouver lorsque vous regardez à l'intérieur "faites vos tâches"?

S'il s'agit d'une liste de conteneurs à ouvrir, d'éléments à supprimer et d'emplacements où les transporter, vous avez perdu deux bons noms et un niveau d'abstraction utile. S'il vous plaît, ne jetez pas "sortez la poubelle" et "apportez le courrier" simplement parce que "faites vos corvées" existe.

Si vous voulez suivre "Faire une chose", prenez du recul par rapport à ce que fait la fonction et demandez à quoi elle sert. Qu'est-ce que quelqu'un qui l'appelle doit vraiment savoir? Quels détails n'ont-ils pas besoin de connaître? Pouvez-vous lui donner un nom qui signifiera quelque chose pour eux?

Voilà la seule chose. Bien sûr, vous pouvez entasser chaque détail dans le nom, mais il vaut mieux que le nom soit centré sur une seule idée de la fonction. Pas chaque petite chose qu'il fait.

18
candied_orange

En effet, le principe de responsabilité unique fait référence à chaque "classe" (une unité de code cohérente, si vous le souhaitez, un objet ) d'avoir une seule raison de changer , de ne pas faire une seule chose.

Le problème clé (le suspect habituel) est productivité. C'est la même raison pour laquelle nous préférons:

  • Ne pas avoir de définitions mixtes dans un dictionnaire (par exemple une définition de "lion et oiseau").
  • Ne pas organiser les dossiers par plusieurs types de documents (par exemple, un dossier "documents de facturation et de taxes téléphoniques").
  • Ne pas mélanger Beatles et Everly Brothers dans le même CD audio (.. .ok, pas le meilleur exemple, mais cela n'aide pas d'avoir à vérifier tout le contenu d'un CD audio pour voir s'il contient la bande que vous aimez, une seule bande fait gagner du temps).

Parce que cela nous rend moins productifs. Nous devons regarder plus profondément pour trouver ce que nous voulons, et nous sommes des êtres impatients parce que le temps c'est de l'argent!

Nous aimons organiser les choses et une fonction qui fait plusieurs choses va à l'encontre de la productivité. Peu importe si cela réduit la productivité de 0,1% maintenant. Perte de productivité s'accumule et nous sommes souvent de parfaites victimes de l'erreur il me semble clair pour le moment erreur. Les quelques secondes qu'il vous faut aujourd'hui pour comprendre ce qui se passe deviennent facilement minutes en quelques mois. Et les minutes deviennent facilement heures lorsque vous avez plusieurs méthodes de ce type "multimodales" à gérer. Et ça peut empirer ... Ce ne sont pas toujours des méthodes vous ont écrit. Et vous n'avez peut-être pas toujours à portée de main les compositeurs de la méthode originale pour vous donner des explications.

Quelles que soient vos compétences, vous êtes plus productif dans la manipulation et le maintien de fonctions simples. Même le nom le meilleur et le plus cohérent du monde vous laisserait encore de lire le nom complet de la fonction, puis de parcourir la fonction pour trouver la partie que vous souhaitez conserver (vérification, révision, débogage, etc.).

En bref, une méthode peut faire autant de choses que vous le souhaitez et personne ne vous empêche d'utiliser "et" dans le nom, de manière appropriée, bien sûr. Mais après avoir fait cela plusieurs fois dans une base de code relativement grande, ce ne sera qu'une question de temps avant que vous ne souhaitiez pas!

2
Vector Zita

Qu'est-ce que cela signifie lorsque vous dites qu'une méthode ou une fonction ne devrait faire qu'une seule chose?

Cela signifie qu'une méthode ou une fonction ne devrait faire qu'une seule chose ...

Une fois qu'il fait deux choses, il devient plus difficile à tester (puisque vous ne pouvez pas tester ces deux choses isolément). Une fois qu'il fait deux choses, votre code est souvent plus fragile (car les gens supposent souvent que les deux choses se produisent toujours, plutôt qu'un échec ne se produit entre eux). Une fois qu'il fait deux choses, votre code est moins flexible (car vous aurez très souvent besoin de réutiliser l'une des choses sans l'autre). Et cela ignore les dommages causés par la débogabilité, la dénomination, la maintenabilité, l'évolutivité et tous les autres aspects qualitatifs des logiciels et du code en général.

"ne faire qu'une seule chose" est une ligne directrice pour aider toutes ces choses qui nous tiennent à cœur. Ce n'est pas une règle que vous devez suivre.

Parce que pédantiquement, l'écrasante majorité des fonctions font plus d'une chose. "Ajoutez ces chiffres et renvoyez-les" est deux choses. "Vérifier cette entrée et l'enregistrer dans la base de données" est deux choses. Ce qui nous importe vraiment, c'est couplage.

Si votre fonction prend deux composants plus petits et les combine pour faire quelque chose d'un peu plus compliqué, c'est bien. Les bits plus petits peuvent être testés/réutilisés/compris isolément car ils sont découplés en dehors de cette fonction. La "seule chose" qu'il fait ici est de combiner les deux composants les plus petits. Mais l'essentiel est que nous ne nous soucions pas vraiment si c'est "ne faire qu'une seule chose" - nous nous soucions si le code est lisible, testable, évolutif, etc.

Peut-il faire quelques choses tant qu'il a un nom cohérent?

Un nom cohérent est un indice qu'il pourrait s'agir d'une abstraction raisonnable, mais ce n'est pas une garantie.

Faut-il éviter les routines avec le mot "et" en eux?

De même, une fonction FooAndBar est une odeur que votre abstraction n'est pas assez granulaire, mais ce n'est pas une garantie.

1
Telastyn