Arguments nommés (paramètres) comme aide à la lisibilité

11

Il y a longtemps, j'avais beaucoup programmé dans ADA, et il était normal de nommer des arguments lors de l'appel d'une fonction - SomeObject.DoSomething (SomeParameterName => someValue);

Maintenant que C # prend en charge les arguments nommés, je pense à revenir à cette habitude dans des situations où il n'est pas évident de savoir ce que signifie un argument.

Vous pourriez faire valoir que la signification d'un argument devrait toujours être évidente, mais si vous avez un argument booléen et que les appelants passent "vrai" ou "faux", la qualification de la valeur avec le nom rend le site d'appel plus lisible.

contentFetcher.DownloadNote (remarque, manuel: vrai);

Je suppose que je pourrais créer des énumérations au lieu d'utiliser vrai ou faux (manuel, automatique dans ce cas).

Que pensez-vous de l'utilisation occasionnelle d'arguments nommés pour faciliter la lecture du code?

Damian
la source
Le commentaire des paramètres au-dessus des méthodes aide également.
Amir Rezaei
1
@ amir-rezaei: Les commentaires de paramètres au-dessus des méthodes ne sont utiles que si vous pouvez faire confiance aux commentaires. À moins d'avoir de bons développeurs et de bons processus de révision de code, je ne ferais pas confiance aux commentaires.
btilly
En tant qu'utilisateur unique d'Ada, je suis pour une utilisation occasionnelle comme vous le décrivez. C'est comme ça que je me souviens qu'ils étaient utilisés dans Ada, BTW - je n'appellerais pas cela "anormal", mais le mot "normal" semble impliquer que la plupart des appels spécifieraient des noms de paramètres, ce qui n'est pas comme ça que je me souviens des choses. Bien sûr, les conventions varient, mais l'encombrement inutile est une mauvaise convention dans n'importe quelle langue IMO.
Steve314
Je suis d'accord sur votre utilisation à Ada - ce n'était pas quelque chose que nous faisions tout le temps, mais où cela a aidé.
Damian

Réponses:

7

Cela a été suggéré dans le développement de C ++, et Stroustrup en discute dans son "Design and Evolution of C ++", pages 153 et suivantes. La proposition était bien formulée et s'appuyait sur une expérience antérieure avec Ada. Il n'a pas été adopté.

La principale raison était que personne ne voulait encourager les fonctions avec un grand nombre de paramètres. Chaque fonctionnalité supplémentaire dans une langue coûte quelque chose, et il n'y avait aucun désir d'ajouter une fonctionnalité pour faciliter l'écriture de mauvais programmes.

Cela a également soulevé des questions sur les noms des paramètres canoniques, en particulier dans la convention habituelle des en-têtes et des fichiers de code. Certaines organisations avaient des noms de paramètres plus longs et plus descriptifs dans le fichier .h, et des noms plus courts et plus faciles à taper dans le fichier .cpp (substituez les suffixes de fichier selon vos besoins). Exiger qu'ils soient les mêmes serait un coût supplémentaire pour la compilation, et le fait de mélanger les noms entre les fichiers source pourrait provoquer des bogues subtils.

Il peut également être géré en utilisant des objets plutôt que des appels de fonction. Au lieu d'un appel GetWindow avec une douzaine de paramètres, créez une classe Window avec une douzaine de variables privées et ajoutez des setters si nécessaire. En enchaînant les setters, il est possible d'écrire quelque chose comme my_window.SetColor(green).SetBorder(true).SetBorderSize(3);. Il est également possible d'avoir différentes fonctions avec différentes valeurs par défaut qui appellent la fonction qui fait le travail.

Si vous êtes simplement inquiet de l'effet de la documentation contentFetcher.DownloadNote(note, manual : true);, vous pouvez toujours écrire quelque chose comme ça contentFetcher.DownloadNote(note, /* manual */ true);, donc ce n'est même pas très utile dans la documentation.

David Thornley
la source
Curieusement, lorsque je suis passé d'Ada à C, j'ai commencé à utiliser la convention que vous décrivez - les critiques de code la détestaient cependant. Acceptez de ne pas l'utiliser pour un grand nombre de paramètres.
Damian
7

Je pense qu'il s'agit de rendre le mauvais code plus lisible, plutôt que la «meilleure pratique».

Avoir une méthode (ou un entrepreneur) qui prend 20 paramètres est une «mauvaise odeur» et est probablement due à un problème dans votre conception. Cependant, si je suis obligé de travailler sur du code lorsque les méthodes prennent beaucoup de paramètres, le paramètre nommé rend le code moins difficile à comprendre.

Lorsque les méthodes n'ont que 1 ou 2 paramètres et que le nom de la méthode indique clairement le paramètre, le paramètre nommé n'ajoute rien. C'est le cas idéal pour être.

Si tout le code sur lequel vous travaillez est écrit selon le livre « code propre », vous n'aurez que très peu recours aux paramètres nommés, mais nous vivons dans le monde réel.

Ian
la source
1
Une fonction avec deux paramètres peut prêter à confusion si les deux paramètres sont du même type et sans aucun indice sur lequel. Bien sûr, vous pouvez nommer la fonction d'une manière qui fournit cet indice, mais vous faites vraiment ce que les noms de paramètres font de toute façon - sauf que vous obligez à inclure cette verbosité même lorsque le contexte (par exemple les expressions qui fournissent le paramètres) rendent évident quel paramètre est lequel.
Steve314
1
@ Steve314 Exemple:void TrackDataChange(Data oldData, Data newData)
Alexander
3

Je suis d'accord que l'ajout du nom du paramètre le rend plus lisible. Cependant, la plupart des livres que j'ai lus semblent considérer les commutateurs booléens comme une mauvaise pratique. Je fais parfois ceci:

public Content DownloadNote(Note note)
{
    return downloadNote(note, manual: false);
}

public Content DownloadNoteManually(Note note)
{
    return downloadNote(note, manual: true);
}

Cela vous donne plus de flexibilité lors de la mise en œuvre de votre API. Il vous permet également de contrôler le cas où vous avez plusieurs commutateurs booléens, mais tous ne peuvent pas être actifs en même temps.

Scott Whitlock
la source
3
Si vous avez x choix, allez-vous faire 2 ^ x frontends?
apoorv020
@ apoorv020 - si j'avais suffisamment de paramètres pour un appel de méthode que 2 ^ x est devenu significatif, je créerais une nouvelle classe pour contenir les valeurs des paramètres et je passerais juste un paramètre.
Scott Whitlock
@ scott-whitlock: Option 1 - créer un objet, définir les propriétés x, appeler une méthode une fois avec votre objet. Option 2 - appelez une méthode avec x paramètres nommés. Ce qui est mieux dépend de votre langue. Dans un langage typé dynamiquement, l'option 1 nécessite beaucoup plus de plaques chauffantes sans gain, et c'est donc pire. Dans un langage de type statique, vous ajoutez toujours le passe-partout, mais les tests pour les clés incorrectement nommées doivent être effectués au moment de la compilation plutôt qu'au moment de l'exécution. Par conséquent, l'option 1 est meilleure en C #, mais l'option 2 est une nette victoire en Python.
btilly
@btilly - comme l'a souligné Ian, Clean Code vous dit clairement de ne pas avoir de fonctions avec plus de 2 ou 3 paramètres. Pour être honnête, il s'agissait de Java, qui est typé statiquement. L'OP pose également des questions sur C #, qui est typé statiquement. Je préférerais toujours utiliser des surcharges de fonctions et / ou des noms de fonctions nommés avec précision plutôt qu'une longue liste de paramètres.
Scott Whitlock
@ scott-whitlock: Sommes-nous réellement en désaccord? Nous sommes d'accord sur ce qu'il y a de mieux en C #. Nous savons tous les deux ce que dit Clean Code. Mon point de vue était qu'il est important de comprendre pourquoi il est bon, afin que vous sachiez quand le conseil correspond ou ne correspond pas à un environnement différent.
btilly
3

Je suis un grand partisan des paramètres nommés dans des situations où les types et la sémantique ne sont pas clairs d'après le nom de la méthode. D'après mon expérience, peu de gens lisent la documentation.

Cela étant dit, les paramètres nommés ne devraient pas être une alternative à la création de listes d'arguments sensées, à l'utilisation d'objets auxiliaires (pour «lier» des arguments sémantiquement liés) et à l'utilisation d'énumérations, le cas échéant.

Uri
la source
0

Je pense que cela est plus utile dans les langages non-OO, où vous pouvez avoir une fonction qui doit faire quelque chose de plusieurs manières légèrement différentes, et la façon dont elle détermine quoi faire est basée sur les valeurs des paramètres. Dans le monde OOP, nous surchargerions simplement la fonction, mais quand ce n'est pas possible, vous finirez par passer un tas de drapeaux (ou un tas de valeurs, et si elles sont passées ou non est le drapeau).

Je pense que c'est plus lisible, dans une certaine mesure; mais comme d'autres l'ont mentionné, avoir de nombreux paramètres est une odeur de code, donc je ne vois pas beaucoup d'utilisation pour cela dans un langage orienté objet comme C #.

TMN
la source