L'utilisation de noms de paramètres qui diffèrent des noms de types uniquement par la casse est-elle considérée comme une mauvaise pratique en C #?

43

Je vois des questions similaires à celles-ci en ce qui concerne les noms de paramètres qui correspondent aux propriétés de la classe, mais je ne trouve rien concernant l'utilisation d'un nom de paramètre identique à celui du type de paramètre, à l'exception de la casse en C #. Cela ne semble pas être une violation que je puisse trouver, mais est-ce considéré comme une mauvaise pratique? Par exemple, j'ai la méthode suivante

public Range PadRange(Range range) {}

Cette méthode prend une plage et renvoie une nouvelle plage à laquelle un remplissage a été appliqué. Donc, étant donné le contexte générique, je ne peux pas penser à un nom plus descriptif pour le paramètre. Cependant, cela me rappelle un conseil que j'ai lu en lisant Code Complete à propos de "distance psychologique". Ça dit

La distance psychologique peut être définie comme la facilité avec laquelle deux éléments peuvent être différenciés ... Pendant que vous déboguez, soyez prêt à résoudre les problèmes causés par une distance psychologique insuffisante entre des noms de variable similaires et entre des noms de routine similaires. Lorsque vous construisez du code, choisissez des noms avec de grandes différences afin d’éviter le problème.

La signature de ma méthode a beaucoup de "Portée", donc il semble que cela puisse être un problème en ce qui concerne cette distance psychologique. Maintenant, je vois beaucoup de développeurs faire ce qui suit

public Range PadRange(Range myRange) {}

J'ai personnellement beaucoup de dégoût pour cette convention. L'ajout d'un préfixe "mon" aux noms de variables ne fournit aucun contexte supplémentaire.

Je vois aussi ce qui suit

public Range PadRange(Range rangeToPad) {}

J'aime mieux cela que le préfixe "mon", mais je ne m'en soucie toujours pas. Cela me semble trop verbeux et se lit maladroitement comme un nom de variable. Pour moi, il est entendu que la plage sera complétée en raison du nom de la méthode.

Donc, avec tout cela, mon instinct doit aller avec la première signature. Pour moi, c'est propre. Pas besoin de forcer le contexte quand ce n'est pas nécessaire. Mais est-ce que je fais moi-même ou les futurs développeurs un mauvais service avec cette convention? Suis-je en train de violer une pratique exemplaire?

Jason Tyler
la source
35
Si vous ne pouvez pas proposer un paramètre plus descriptif, Range rangec'est bien.
Robert Harvey
21
Dans cette situation, l'EDI colorera 'Range' et 'Range' différemment. Il est donc très facile de voir que l'un est le type et l'autre le nom de la variable.
17 du 26
10
Oui, je m'en souviens. C'est dans leurs directives de conception en tant que considération. "CONSIDERER en donnant à une propriété le même nom que son type." docs.microsoft.com/en-us/dotnet/standard/design-guidelines/…
Jason Tyler
11
Aussi bien: Range r(au moins pour un corps de méthode courte) et Range toPad.
Bergi
19
J'ai toujours considéré le préfixe "mon" comme quelque chose qui est fait dans l'exemple de code, utilisé pour indiquer au lecteur qu'un nom doit être changé en quelque chose d'autre en fonction du contexte. Ce n'est pas quelque chose qui devrait se retrouver dans un code réel.
Kapex

Réponses:

100

Ne pensez pas trop, Range rangec'est bien. J'utilise ce type de nommage depuis plus de 15 ans en C #, et probablement beaucoup plus longtemps en C ++, et je n'ai jamais rencontré de véritables inconvénients, bien au contraire.

Bien sûr, lorsque vous avez différentes variables locales dans le même périmètre, toutes du même type, il sera probablement utile d'investir un effort mental pour les distinguer correctement.

Doc Brown
la source
6
Une autre exception que j’ajouterais concerne le cas où une action particulière est effectuée sur l’instance. Il y a un peu de place pour être plus descriptif sur la raison pour laquelle le paramètre est nécessaire, par exemple. Wack (BozoToBeWacked) Encore plus si le paramètre est optionnel et décrit ce que l'objet dans ce scénario signifie / ce qu'il va avoir un impact. Ma règle de base si ce n'est pas évident sans regarder le code ce que le paramètre fait alors il a besoin d'un meilleur nom et / ou de commentaires.
Mike
17
Je considérerais Wack(Bozo bozoToBeWacked)comme un exemple de redondance dans le nom de variable qui est amplement exprimée par la méthode elle-même (et donc indésirable selon la question initiale). Wack(Person bozo)est cependant plus précieux sur le plan sémantique, car cela implique que seuls les bozos soient fustigés.
Miral
2
Dans le cas que vous mentionnez dans le deuxième paragraphe, je renommerai souvent le paramètre comme suit initialRange. Il est encore très générique mais n’a presque pas le même dégoût que myRange.
Jaquez
@Miral: Cela devient plus pertinent dans des cas tels que Punch(Bozo punchingBozo, Bozo bozoToBePunched). La dénomination détaillée est plus pertinente lorsque vous devez faire la distinction entre plusieurs choses (décrites sémantiquement avec à peu près les mêmes mots). La suggestion de OP Range rangeToPadn'est pas nécessaire dans son exemple de méthode à un paramètre, mais pourrait être extrêmement nécessaire pour une méthode qui prend plusieurs Rangeobjets.
Flater
7
@Flater Punch(Bozo source, Bozo target)ferait le travail
Thomas Ayoub
17

Je fais ça tout le temps, ça me donne un grand esprit. S'il s'agit d'un argument passé à un constructeur qui doit être affecté à un membre, mon membre sera également nommé range et l'affectation sera

this.range = range;

Et j'aurais typiquement une propriété appelée Range.

Ils sont tous la même chose, ne différant que par leur contexte, il est donc logique de conserver un seul nom et vous ne devez vous souvenir que d’un seul nom. C'est une chose, les différences sont purement techniques.

Vous devriez être strict avec des membres pleinement qualifiés avec "ceci". Cependant, c’est à quoi sert StyleCop.

Note de côté StyleCop

Controverse garantie!

Pour ceux qui défendent l'utilisation de "ceci": j'ai vu _, m, m_ et rien du tout. Le langage lui-même nous offre un moyen parfaitement clair et sans ambiguïté, universellement reconnaissable, d'indiquer que nous traitons avec un membre du groupe. Pourquoi voudriez-vous inventer votre propre chemin qui mutile des noms déjà parfaits?

La seule raison pour laquelle je peux penser que c’est une habitude héritée de l’ère C, alors que c’était logique de le faire parce qu’il n’y avait pas d’autre moyen.

"Ce sont plus de personnages!" Sérieusement? "Le temps de compilation va monter en flèche!" Sérieusement? "Je vais devoir lever mon petit doigt quand je le tape!". Comme si le temps de frappe avait une signification dans le temps de développement total.

Je reconnais que tout style différent de celui auquel vous êtes habitué suscitera une certaine opposition. Mais il est difficile de discuter avec cela systématiquement. Voici comment cela fonctionne pour moi: Avant d'exécuter un nouveau fichier de code, j'exécute StyleCop et il trouvera un certain nombre de membres dépourvus du qualificatif "this". Je mets "ceci". dans le presse-papiers, géré par les membres et inséré. Aucun effort du tout.

StyleCop fait beaucoup plus que cela (haha). Il existe de nombreuses façons pour un développeur (uniquement en ce qui concerne le formatage du code) de frustrer le travail de maintenance de son successeur. StyleCop empêche la plupart d'entre eux. C'est inestimable.

Si vous êtes novice: cela vous fait généralement râler pendant une semaine ou deux et ensuite vous allez l'adorer.

Martin Maat
la source
19
" Vous devriez être strict avec les membres pleinement qualifiés avec" ceci. "Bien que, " -1. Ne pas utiliser thissauf si nécessaire. C'est juste du bruit autrement. Utiliser _rangepour le champ et thisn'est jamais nécessaire sauf dans les méthodes d'extension.
David Arno
12
Je suis d'accord avec @DavidArno. 'this' est juste du bruit pur. "Plage" est une propriété, "_range" est un champ et "plage" est un paramètre.
17 du 26
8
@David Si la variable est un membre de la classe, il est essentiel et bat tout préfixe arbitraire pour signaler que vous regardez un membre de la classe plutôt qu'un argument ou une variable locale.
Martin Maat
6
Mon IDE tirait des boules de feu à la seconde où je lui assignerais une variable.
Koekje
21
@DavidArno Attention à expliquer pourquoi le "bruit" de _est préférable au bruit de this.? Je dirais que l’une a une signification imposée par le langage (et a généralement une coloration syntaxique) tandis que l’autre n’a pas.
Clint
9

Mon auto-guidage sur les méthodes de nommage, les paramètres et les variables est assez simple:

  1. Si le nom contient le type qui est transmis ou renvoyé, vous le faites mal.
  2. Nommez les choses en fonction de ce à quoi elles sont destinées et non de ce qu'elles sont.
  3. Rappelez-vous toujours que le code est lu plus qu'il n'est écrit.

Ainsi, la signature de la méthode optimale, à mon avis, serait:

Range Pad(Range toPad)

Raccourcir le nom de la méthode est explicite.

Le nom du paramètre toPadindique immédiatement au lecteur que ce paramètre sera probablement modifié sur place en étant rempli, puis renvoyé. En revanche, aucune hypothèse ne peut être faite sur une variable nommée range.

En outre, dans le corps même de la méthode, toutes les autres Rangevariables introduites devraient (devraient) être nommées en fonction de leur intention. Vous pouvez donc vous conformer paddedet unpadded... vous toPadconformer à ces conventions de nommage, mais vous rangedémarquez et ne gélifie pas.

Ian Kemp
la source
3
padded/ unpaddedsonne bien pour les variables immuables locales. Mais s'il existe un toPadparamètre mutable , le nom toPadne tient plus après le remplissage (à moins que le résultat ne soit renvoyé immédiatement). Je préférerais m'en tenir à Range rangeces cas.
Kapex
@Kapep Je l'appellerais juste result. Il est modifié et renvoyé . Le dernier ressort clairement du nom et le premier suit, car renvoyer un argument non modifié n’a aucun sens.
Maaartinus
A partir de la signature, la Padméthode retourne a Range. Pour moi, cela implique que celui que j'ai transmis sera préservé, non modifié sur place, et qu'un nouveau, capitonné, Rangesera renvoyé. .
Aaron M. Eshbach
1
Je ne sais pas quoi penser de vos conseils. Pad(toPad)se sent un peu mal à mon humble avis. Vous faites un bon point de défendre votre point de vue si. Vous obtenez un +0 de moi! :)
Eric Duminil
Dans la question, il est indiqué qu'il "renvoie une nouvelle plage dans laquelle un remplissage a été appliqué". Je suis d'accord avec votre nom pour ce que vous pensez que le scénario est, mais pour la question réelle, j'irais pour quelque chose comme Range CreateRangeWithPadding (Source source)
Richard Willis
3

Pour nommer les éléments de code (types, variables, fonctions, etc.), la question clé à se poser est:

Si je fais une faute de frappe, le compilateur va-t-il me la trouver?

Le pire type de bogue typo est celui où le code est compilé et exécuté, mais donne un comportement différent de celui auquel vous vous attendez, pour des raisons subtiles. Et comme cela est dû à une faute de frappe, il est généralement très difficile de voir quand vous inspectez le code. Si une faute de frappe arrête la compilation du code, le compilateur marque la ligne à l'origine du problème et vous pouvez facilement le trouver et le résoudre.

Pour votre situation où le type et la variable ne diffèrent que par la capitalisation, ce sera toujours le cas. (Ou presque toujours - avec un effort suffisant, je suis sûr que vous pourriez le faire fonctionner, mais vous devriez vraiment essayer.) Donc je pense que vous êtes OK ici.

Si vous aviez deux variables, méthodes, fonctions ou propriétés dans la portée actuelle, appelez rangeet Range. Dans ce cas, le compilateur le laissera probablement passer et vous obtiendrez un comportement inattendu au moment de l'exécution. Notez que c'est deux tout de ces types d'éléments de code, non seulement « deux variables » ou « deux fonctions » - tous ceux -ci peuvent être implicitement à l'autre, ce qui entraîne un carnage lors de son exécution. Vous pourriez recevoir des avertissements, mais vous ne pouvez rien garantir de plus. Vous avez des problèmes similaires si vous aviez deux types déclarés appelés rangeet Range.

Notez également qu'il en va de même pour le style de notation hongrois , où les noms sont précédés d'un ou de plusieurs caractères pour en dire plus sur ce qu'il est. Si vous avez une variable appelée Rangeet un pointeur appelé PRange, il est facile de rater accidentellement le P, par exemple. C # devrait comprendre cela, mais C et C ++ ne vous donneront tout au plus qu'un avertissement. Ou plus inquiétant, supposons que vous ayez une version double appelée DRangeet que vous sous-échantillonniez celle-ci à une version flottante appelée FRange. Utilisez le flottant par accident (ce qui est facile puisque les touches sont adjacentes sur un clavier) et votre code fonctionnera plutôt bien , mais il tombera de manière étrange et imprévisible lorsque le processus sera à court de résolution et de débordement.

Nous ne sommes plus dans les temps où nous avions des limites de nommage de 8 caractères, ou 16 caractères, ou quelle que soit la limite arbitraire. J'ai parfois entendu des novices se plaindre de noms de variables plus longs, ce qui rend le codage plus long. Ce ne sont que des novices qui s'en plaignent. Les développeurs sérieux savent que ce qui prend vraiment du temps, c'est de trouver des bugs obscurs - et le mauvais choix du nom est un moyen classique de vous laisser tomber dans ce trou particulier.

Graham
la source
Juste une note pour les lecteurs - pour C #, les gens devraient vraiment éviter la notation hongroise. Bien que cela ait été utile dans les temps anciens, lorsque la mise en évidence de la syntaxe n'était pas une chose ou était limitée, de nos jours cela n'aide vraiment pas.
T. Sar - Réintégrer Monica
@ T.Sar Même à l'époque, je le détestais avec passion! Comme vous le dites, de meilleurs IDE ont résolu les problèmes auxquels il était destiné, mais cela apparaît toujours de temps en temps. Vous le verrez quand même si vous devez parler à l'API Windows, par exemple, pour des raisons historiques. Je ne voulais pas frapper totalement les styles préférés des gens s'ils l'appréciaient vraiment, mais je voulais aussi l'utiliser comme crochet pour montrer que les majuscules / minuscules ne sont pas le seul moyen de gâcher l'attribution de nom.
Graham
Je suis conscient que vous ne proposez pas l’utilisation de la notation hongroise, mais je suis également conscient que les jeunes développeurs ont une énorme faiblesse pour les choses aux noms sympas. Être capable de dire "Mon code est écrit dans ce style de codage ninja super secret - la notation hongroise!" peut sembler irrésistiblement cool aux jeunes esprits. J'ai vu trop de développeurs en proie au battage médiatique… La notation hongroise est pénible, donnez la forme du code source xX
T. Sar - Reinstate Monica
@ T.Sar Assez vrai. "Ceux qui ne se souviennent pas du passé sont condamnés à le répéter" et tout ça. : /
Graham
1
Parlons-nous de la notation hongroise originale ou de la façon dont elle a été grossièrement mal interprétée par Microsoft (près de "les rédacteurs de la documentation de l'équipe Windows ont inventé par inadvertance ce qui allait devenir le système hongrois" et aussi dans l'interview de Joel Spolsky par Leo Laporte sur l'épisode Triangulation 277, 2016-12-12, 04 minutes 00 secondes - 06 minutes 35 secondes )?
Peter Mortensen
1

Une anecdote que je voudrais ajouter: bien que Range rangece soit syntaxiquement légal, cela pourrait rendre les choses plus difficiles à déboguer ou à refactoriser. Vous recherchez cette variable nommée "range" dans un fichier contenant beaucoup de variables de type Range? Vous devrez peut-être faire plus de travail plus tard à la suite de ce choix de nom.

Ceci dépend en grande partie du contexte. S'il s'agit d'un fichier de 30 lignes, mes déclarations n'interviennent pas vraiment.

Jacob M.
la source
7
La plupart des gens utilisent des outils qui distinguent les types et les paramètres ou les variables pour le développement Windows. Ce que vous décrivez me rappelle les bons vieux jours de grep sous Unix.
Frank Hileman
1
@FrankHileman Cela peut vous surprendre, mais Unix est toujours en vie et grep est toujours utilisé (: D). Comme grep est par défaut sensible à la casse, le problème mentionné n’existe tout simplement pas. Cependant, même nous, les hordeurs de fenêtres accrochés au terminal, utilisons rarement grep pour le code source, car l'IDE est bien meilleur que les recherches courantes.
Maaartinus
Je pense que nous convenons que la plate-forme n'est pas la question. grepest un excellent outil, mais ce n'est pas un outil de refactoring. Et des outils de refactoring existent sur toutes les plateformes de développement que j'ai utilisées. (OS X, Ubuntu, Windows).
Eric Wilson
@EricWilson À une certaine époque, grep et sed étaient les seuls outils de refactoring sur Unix.
Frank Hileman
@FrankHileman Ce n'est pas parce qu'un élément est utilisé comme outil de refactoring qu'il en est un. Je peux refactoriser le bloc-notes, mais cela n'en fait pas plus qu'un éditeur de texte.
Eric Wilson
1

Je pense que vous pouvez utiliser aujourd'hui Range rangepour une raison: la coloration syntaxique. Les IDE modernes mettent généralement en évidence les noms de types et les noms de paramètres dans des couleurs différentes . De plus, un type et une variable ont une "distance logique" considérable à ne pas confondre facilement.

Si ce n'était pas le cas, je considérerais un nom différent ou essayerais d'activer un plugin / une extension capable de faire cette coloration syntaxique.

Akaltar
la source
0

Quand une fonction est générique, il va de soi que les paramètres seront génériques et devraient donc avoir des noms génériques.

Ce n’est pas ce que vous dites, mais j’ai vu des fonctions qui exécutent une fonction générique dont les noms de paramètres sont trompeurs. Comme

public String removeNonDigits(String phoneNumber)

Le nom de la fonction semble très générique, comme cela pourrait être appliqué à de nombreuses chaînes dans de nombreuses situations. Mais le nom du paramètre est étrangement spécifique, ce qui me fait me demander si le nom de la fonction est trompeur ou ... quoi?

Donc, bien sûr, au lieu de dire Range, vous pouvez dire Range rangeToPad. Mais quelles informations cela ajoute-t-il? Bien sûr, c'est la gamme à pad. Quoi d'autre serait-il?

Ajouter un préfixe arbitraire, "mon" ou "m_" ou autre, ne donne aucune information supplémentaire au lecteur. Lorsque j'ai utilisé des langages dans lesquels le compilateur ne permet pas à un nom de variable d'être identique à un nom de type - avec ou sans sensibilité à la casse - j'ai parfois mis un préfixe ou un suffixe, juste pour le faire compiler . Mais c'est juste pour satisfaire le compilateur. On pourrait faire valoir que même si le compilateur peut distinguer, cela facilite la tâche du lecteur humain. Mais wow, en Java, j'ai écrit des déclarations du type "client client = nouveau client ();" un milliard de fois et je ne l'ai jamais trouvé déroutant. (Je l'ai toujours trouvé un peu redondant et j'aime assez cela en VB, vous pouvez simplement dire "client faible en tant que nouveau client" et vous n'avez pas à donner le nom de la classe deux fois.)

Je m'oppose fortement aux noms génériques lorsqu'il y a deux instances ou plus du même type dans la même fonction. EN PARTICULIER paramètres. Comme:

public Range pad(Range range1, Range range2)

Quelle est la différence entre range1 et range2? Comment suis-je censé savoir? Si c'est quelque chose où ils sont vraiment deux valeurs génériques et interchangeables, d'accord, comme

public boolean overlap(Range range1, Range range2)

Je m'attendrais à ce que cela retourne true si les plages se chevauchent et false si elles ne le font pas, elles sont donc génériques et interchangeables.

Mais s'ils sont différents, donnez-moi un indice en quoi ils sont différents! Je travaillais récemment sur un programme qui avait récemment une classe "Lieu" pour stocker des données sur des lieux géographiques, et avec des variables de ce type nommées "p", "lieu", "lieu2", "monPlace", etc. Les noms m'aident vraiment à déterminer lequel est lequel.

Geai
la source