web-dev-qa-db-fra.com

Devrais-je utiliser et dans un nom de la fonction?

Je suis en difficulté. Je travaille dans un référentiel qui apporte beaucoup de changements de base de données dans ses fonctions.

La fonction que je traite avec les retours de réponse (mais à partir d'une transformation, et non d'une action de base de données). Cependant, comme effet secondaire, il ajoute un objet contenant ces réactions à la base de données.

Alors devrais-je l'appeler:

  • getResponseIds: cela met en évidence les valeurs de retour. C'est une façon très fonctionnelle de penser, mais évidemment si j'ai la fonction postToDB cela n'a aucun sens d'utiliser getStatusOfPost
  • addResponseIdToDB: Cela met en évidence l'effet secondaire, bien que je pense vraiment que bon nombre de mes fonctions fonctionnent simplement sur la base de données (et ont tendance à ne rien renvoyer)
  • getAndAddResponseIdsToDB: très informatif, mais très long.

Quels sont les avantages et les inconvénients des suggestions ci-dessus? Ou pouvez-vous faire une meilleure suggestion vous-même?

42
tintinthong

Un nom de la fonction contenant and est au niveau Niveau incorrect de l'abstraction .

Je me penche vers addResponseIdToDB() car sinon l'effet secondaire est une surprise complète. Toutefois:

responseIds = addResponseIdToDB();

ne laisse personne surprise.

Le principe de ségrégation de la responsabilité de la requête de commande Contrevoi que cela ne devrait pas être le seul moyen d'obtenir l'objet de réponse. Il devrait également y avoir une requête qui ne change pas la DB qui peut obtenir cet objet.

Contrairement à Bertrand Meyer , je ne crois pas que cela signifie que l'ajout doit retourner vide. Signifie juste une requête pure équivalente devrait exister et être facile à trouver afin que la DB ne soit pas inutilement abusive en utilisant des requêtes changeantes d'état.

Étant donné que getResponseIds() devrait exister et ne pas parler à la base de données, le meilleur nom d'une méthode qui fait la fois addToDB(getResponseId()). Mais c'est juste si vous voulez obtenir toute la composition fonctionnelle à ce sujet.

56
candied_orange

Je dirais que c'est bien en général, mais n'est pas acceptable dans tous les cas.

Par exemple, on pourrait discuter contre and dans un nom de la fonction basé sur le principe de responsabilité unique Aka le S In SOLID - parce que le and pourrait impliquer de multiples responsabilités. Si le and signifie vraiment que la fonction fait deux choses, alors vous voulez probablement penser avec précaution sur ce qui se passe.

Un exemple de bibliothèque qui utilise and dans les noms de fonction peut être trouvé dans Java Concurrency et ici and est en fait une partie très importante de ce qui se passe et de près Correspond à ce que vous décrivez dans votre message où l'état est modifié et est renvoyé. Donc, clairement, il y a des gens (et des cas d'utilisation) où il est jugé acceptable.

9
Shaz

En effet, c'est une question difficile à répondre à mesure que de nombreux commentaires peuvent attester. Les gens semblent avoir des opinions contradictoires et des conseils sur ce qui est un bon nom.

J'aimerais ajouter mes 2 cents à ce fil de 2 mois parce que je pense que je peux ajouter plus de couleurs à ce qui a déjà été suggéré.

Nommage est un processus

Tout cela me rappelle l'excellent guide 6 étapes: nommer comme processus .

Un mauvais nom de la fonction est celui qui est surprenant et vous réalisez que vous ne pouvez pas faire confiance. Une bonne nommée est difficile à obtenir au premier coup. Cela devient plus facile avec l'expérience.

6 étapes itératives pour construire un bon nom

  1. Remplacez le nom surprenant avec une non-sens évidente comme appleSauce(). Cela semble stupide, mais il est temporaire et il est évident que le nom ne peut pas faire confiance.
  2. Accédez à un nom honnête , en fonction de ce que vous comprenez de ce que la fonction fait. Dites que vous n'avez pas encore compris l'insertion dans la partie DB, getResponseIdsAndProbablyUseDb serait une option.
  3. Obtenez complètement honnête , le nom de la fonction indique donc tout ce que la fonction est (getAndAddResponseIdsToDB ou getResponsesButAlsoAddCacheOfTheResponsesToTheDb de @Fattie sont Super exemples)
  4. arriver à "fait la bonne chose" qui est fondamentalement la partie où vous divisez votre fonction le long du "et". Donc, vous avez réellement getResponseIds et addResponseIdsToDb.
  5. Accéder à un nom "Intention révélateur" qui résout le point de "Je veux toujours obtenir l'ID de réponse que j'ai inséré dans dB après que je faites-le ". Arrêtez de penser aux détails de la mise en œuvre et de construire une abstraction qui utilise les 2 dernières fonctions pour construire autre chose. C'est le niveau d'abstraction plus élevé mentionné par @CandiedD_Orange. Par exemple, createResponseIds pourrait le faire et sera la composition de getResponseIds et addResponseIdsToDb.
  6. Accédez à l'abstraction de votre domaine . C'est difficile, cela dépend de votre entreprise. Cela prend du temps à l'écoute de votre langue d'entreprise pour avoir raison. Finalement, vous risquez de vous retrouver avec le concept d'un Response et Response.createIds() _ aurait un sens. Ou peut-être ResponseId est quelque chose de précieux et vous auriez une usine pour créer beaucoup. L'insertion dans la DB serait un détail de mise en œuvre d'un référentiel, etc. Oui, la conception serait plus abstraite. Ce serait plus riche et vous laisser exprimer plus. Personne à l'extérieur de votre équipe ne peut vous dire quelle est la bonne abstraction de domaine dans votre situation. Cela dépend.

Dans votre cas, vous avez déjà compris 1 et 2, vous devez probablement au moins aller au moins à 3 (utiliser "et") ou plus loin. Mais aller plus loin n'est pas seulement une question de nommage, vous avez réellement divisé les responsabilités.

Ainsi, les différentes suggestions ici sont valides

Essentiellement:

  • Oui, les noms de fonction surprenants sont terribles et personne ne veut faire face à cela
  • Oui, "et" est acceptable dans un nom de la fonction car c'est mieux qu'un nom trompeur
  • Oui, le niveau d'abstraction est un concept associé et compte

Vous n'êtes pas obligé d'aller pour la scène 6 tout de suite, c'est bien de rester à l'étape 2, 3 ou 4 jusqu'à ce que vous sachiez mieux!


J'espère que cela serait utile de donner une perspective différente sur ce qui ressemble à des conseils contradictoires. Je crois que tout le monde vise le même objectif (noms non surprenants) mais s'arrête à différentes étapes, en fonction de leur propre expérience.

Heureux de répondre si vous avez des questions :)

3
nicoespeon

Avoir un nom de fonction composite est acceptable, de sorte que le schéma de dénomination que vous utilisez dépend de votre contexte. Il y a des puristes qui vous diront de le casser, mais je vais discuter autrement.

Il y a deux raisons d'essayer d'éviter de telles choses:

  • Pureté - une fonction qui fait deux choses doit être convertie en deux fonctions qui font une chose chacune.
  • Taille lexicale - A bigUglyCompositeFunctionName devient difficile à lire.

L'argument de la pureté est typiquement celui qui est axé sur. En tant que vague généraliste généraliste, les fonctions de rupture sont une bonne chose. Cela aide à compartimenter ce qui se passe, ce qui facilite la compréhension. Vous êtes moins susceptible de faire des astuces "intelligentes" avec le partage de variables qui conduisent à coupler entre les deux comportements.

Donc, la chose à poser est "Devrais-je le faire de toute façon?" Je dis briser des choses est une vague heuristique, alors vous n'avez donc besoin que d'un argument décent pour y aller.

Une raison majeure est que son bénéfique de penser aux deux opérations comme une. L'exemple final-tout ultime de ceci se trouve dans les opérations atomiques: compare_and_set. compare_and_set Est une pierre angulaire fondamentale d'atomes (qui constituent un moyen de faire multithreading sans serrures) suffisamment réussi que beaucoup sont disposés à y penser comme le Corrèvre. Il y a un "et" dans ce nom. Il y a une très bonne raison pour cela. L'ensemble de cette opération est qu'il fait la comparaison et le paramètre comme une opération indivisible. Si vous le cédez dans compare() et set(), vous vaincuez la raison entière de la fonction existante en premier lieu, car deux compares() pouvait se produire vers Retour avant la fonction set() s.

Nous le voyons également dans la performance. Mon exemple préféré est FASTIVSQRT . Ceci est un algorithme célèbre de Quake qui calcule 1/sqrt (x). Nous combinons les opérations "inverse" et "racine carrée", car cela nous donne une augmentation massive de performances. Ils font une approximation de Newton qui fonctionne à la fois en une seule étape (et arrive à le faire en integer mathématiques plutôt que sur un point flottant, qui importait à l'ère). Si vous deviez faire inverse(sqrt(x)), ce serait beaucoup plus lent!

Il y a quelques fois où le résultat est plus clair. J'ai écrit plusieurs API impliquant un threading où l'on doit être terriblement prudent des choses comme des blocages. Je ne voulais pas que mon utilisateur soit au courant des détails de la mise en œuvre internes (surtout que je pourrais les modifier), j'ai donc écrit l'API avec quelques fonctions "et" qui empêchent l'utilisateur de toujours avoir une serrure pour plus de un appel de fonction. Cela signifie qu'ils n'ont jamais eu besoin de savoir comment je manipuliez la synchronisation multithreadée sous la hotte. En fait, la plupart de mes utilisateurs n'étaient même pas conscients qu'ils étaient dans un environnement multithreadé!

Ainsi, tandis que la règle générale est de briser les choses, il peut toujours y avoir une raison de les coupler ensemble. Par exemple, votre utilisateur peut-il casser votre architecture en ajoutant à une base de données plusieurs fois sans le "Gets" entre -between? Si chacune des réponses connectées à la DB doit avoir un identifiant unique, vous pouvez avoir des problèmes si l'utilisateur doit les faire willy nilly. De même, voudriez-vous jamais laisser un utilisateur "obtenir" sans enregistrer les résultats dans la DB? Si la réponse est "oui", brisez-les de sorte que l'utilisateur puisse accéder à la fonction "Obtenir". Toutefois, si la sécurité de votre application est cassée si l'utilisateur peut "obtenir" sans que le résultat soit connecté dans la DB, vous devez vraiment conserver les fonctions ensemble.

Maintenant que pour les problèmes lexicaux, votre nom de fonction doit décrire ce que l'utilisateur doit savoir à ce sujet. Commençons par la partie "Obtenir". C'est assez facile à supprimer le "get" à partir d'un nom de fonction, car tous vos exemples afficheront une affectation: int id = addResponseIdToDB() ". Dans tous les endroits où la fonction est utilisée, vous finirez par documenter le fait que la fonction est utilisée. La fonction a renvoyé une valeur.

De même "Ajouter" peut être facultatif. Nous utilisons le terme "effet secondaire" comme un terme tout englobant, mais il y a des nuances différentes. Si les entrées de DB sont simplement un journal, il ne peut y avoir aucune raison de le souligner. Nous ne voyons jamais de fonctions comme playMusicAndSendPersonalInformationToOurCorporateServers. C'est juste playMusic, et si vous avez de la chance, la documentation peut mentionner quelque chose sur une connexion de socket sur Internet. D'autre part, si les utilisateurs devraient appeler cette fonction dans le but d'ajouter des éléments à la base de données, alors "ajouter" est essentiel. Ne le prenez pas.

Maintenant, j'ai écrit beaucoup de raisons de faire toute combinaison possible de ce que vous demandez. Je n'ai intentionnellement pas répondu à la question car il y a un choix à faire. Ce n'est pas une règle de suivre. Vous êtes en train de créer une API.

Cela étant dit, mon instinct est que AddesponseidtoDB est probablement la meilleure réponse. Dans la plupart des cas, la partie "GET" est un effet secondaire assez évident qu'il ne gagne pas le bruit supplémentaire causé en la saisissant partout. Cependant, il y a quelques endroits où je pourrais considérer cela important:

  • Si le "get" est coûteux - si vous devez faire un "get" qui implique de chercher quelque chose sur Internet, puis de l'ajouter à un cache de cache locale, par tous les moyens, le "get" est important. C'est la chose que l'utilisateur essaie de faire.
  • Si vous devez préciser que l'utilisateur a besoin Pour faire attention à la valeur. Si l'utilisateur souhaite utiliser la variable, ils se rendront compte que l'API le renvoie, et ils l'utiliseront. Cependant, vous voulez surveiller l'utilisateur qui ne sait pas qu'elles en ont besoin. Par exemple, si vous devez "fermer" cette opération par ID plus tard pour libérer la mémoire, vous pouvez attirer l'attention sur le fait que vous faites quelque chose. Dans ces cas, vous voudrez peut-être regarder un verbe autre que "obtenir". "Get" implique souvent des fonctions idempotentes (l'appelant à nouveau ne fait rien). S'il renvoie des ressources, d'autres verbes comme "Créer" ou "Acquérir" sont gentils. Ce mécanisme d'échec particulier est un problème majeur en C lors de la manipulation des exceptions. C manque le mécanisme de prise/jet de C++, il dépend donc des codes de retour. Les développeurs sont célèbre Pour simplement avoir échoué à vérifier ces codes de retour et à entrer dans des situations vraiment mauvaises comme les débordements de tampon à cause de cela.
  • Symétrie - Parfois, vous concevez une API pour y avoir une symétrie lexicale. Vous configurez les mots de manière à ce qu'ils viennent en paires ou à d'autres modèles et embrochent les commandes de manière à pouvoir identifier visuellement si le motif a été suivi ou non. Je dirais que cela est rare, mais ce n'est pas inouï. Il y a une raison pour la fermeture des balises XML répétez le nom de la balise (telle que <FOO> et </ FOO>).
1
Cort Ammon

Quel est le ultime Intention de cette méthode ? Pourquoi ajouter ces identifiants transformés à la DB, est-ce dans le but de mettre en cache? Je vais travailler sous cette hypothèse.

On dirait que l'intention de la méthode est vraiment juste d'obtenir les identifiants de réponse transformés (faire la transformation ou les obtenir d'un cache), et il y a donc le nom de votre méthode:

getTransformedResponseIds ou moins verbauly getResponseIds()

Une méthode avec ce nom pourrait mettre en cache ou peut-être pas, et cela peut être documenté, mais votre nom de méthode ne doit pas vous attacher à une implémentation spécifique; Et si vous décidez d'arrêter d'utiliser un dB et de les mettre en cache ailleurs, comme juste temporairement en mémoire?

Les effets secondaires doivent être exacts que, des effets secondaires, ils devraient probablement être documentés, mais ils ne devraient pas vraiment avoir une incidence sur l'intention centrale (ou le succès) ou le nom de la fonction. Si vous obtenez la valeur du cache échoue (ou si vous configurez la mise en cache de saut) qui ne devrait pas être un problème critique, la méthode ne doit que ré-calculer de manière transparente, cache (ou non) et renvoyer la nouvelle valeur.

Parfois, utiliser un "et" est utile pour transmettre l'intention telle que avec le Java méthodes getAndIncrement et incrementAndGet donc ce n'est certainement pas hors de la table.

0
xtratic