Parfois (rarement), il semble que la meilleure voie consiste à créer une fonction qui prend une quantité décente de paramètres. Cependant, quand je le fais, j'ai l'impression de choisir souvent l'ordre des paramètres au hasard. Je vais généralement par "ordre d'importance", avec le paramètre le plus important en premier.
Y a-t-il une meilleure manière de faire cela? Existe-t-il une "bonne pratique" pour classer les paramètres qui améliore la clarté?
refactoring
clean-code
functions
parameters
order
Casey Patton
la source
la source
MessageBox.Show
. Regardez dans cela aussi.Réponses:
En général: utilisez-le .
Ecrivez un test pour votre fonction, un test du monde réel.
Quelque chose que vous aimeriez réellement faire avec cette fonction .
Et voyez dans quel ordre vous les avez mis.
Sauf si vous avez déjà (ou connaissez) certaines fonctions qui font quelque chose de similaire.
Dans ce cas: conformez-vous à ce qu'ils font déjà, du moins pour les premiers arguments.
Par exemple, prennent-ils tous un document / objet / pointeur de fichier / série de valeurs / coordonnées comme premier (s) argument (s)? Pour l'amour de Dieu, conformez-vous à ces arguments .
Évitez de confondre vos collègues et votre futur moi .
la source
Je vais généralement avec ces règles, mais pas toujours avec la même priorité. Je suppose que c’est un processus de réflexion automatique à présent, et je n’y réfléchis pas trop, sauf pour la conception d’API publiques .
Entonnoir de sélection
1. La sémantique d'abord
Surtout en POO, choisissez les paramètres en fonction de leur signification sémantique pour l'action ou le message. La signature d'une méthode bien nommée avec un paramètre bien nommé doit:
(Pour ces raisons, utiliser parfois des types personnalisés ou des alias au lieu de primitives peut augmenter l'expressivité de votre signature.)
2. Alors l'importance
Le paramètre le plus "significatif" vient en premier (ou suivant ...)
3. Puis la fréquence
La fréquence est également importante, en particulier dans une langue où vous n'avez pas de paramètres nommés mais pouvez avoir des valeurs par défaut pour les paramètres de position. Cela implique que l'ordre des paramètres ne varie pas et que vous ne pouvez évidemment pas définir les paramètres N + 1 si vous souhaitez forcer la valeur par défaut du paramètre Nth (sauf si votre langue utilise le concept de paramètre d'espace réservé ).
La bonne nouvelle pour vous est que généralement, la fréquence est liée à l’importance, ce qui va donc de pair avec le point précédent. Et puis, c’est probablement à vous de concevoir votre API pour qu’elle ait la sémantique appropriée.
4. N'oublions pas les E / S
si votre méthode / fonction prend une entrée et génère une sortie, et que cette dernière ne doit pas être "retournée" (via une instruction return) ou "jetée" (en utilisant un système d'exception), il vous reste l'option de passer renvoyer les valeurs à l'appelant à l'aide de vos autres paramètres (ou du paramètre d'entrée). Cela concerne la sémantique, et dans la plupart des cas, il sera judicieux que les premiers paramètres définissent la sortie, et les derniers paramètres reçoivent la sortie.
En outre, une autre approche permettant de réduire le nombre de paramètres et d'optimiser la sémantique consiste à utiliser une approche fonctionnelle ou à définir un motif Builder , afin de pouvoir clairement empiler vos entrées, définir vos sorties et les récupérer en cas de besoin.
(Remarquez que je ne mentionne pas les variables globales, car pourquoi en utiliseriez-vous une, n'est-ce pas?)
Quelques points à considérer
Utilisabilité
Si vous suivez les conseils de ZJR, la plupart des éléments ci-dessus apparaîtront naturellement : utilisez-le!
Envisager de refactoriser
Si vous vous inquiétez de l'ordre des paramètres, peut-être que cette inquiétude trouve sa racine dans ce qui précède et dans le fait que votre API est mal conçue. Si vous avez trop de paramètres, il est très probable que quelque chose soit composé / modularisé et refactorisé .
Considérer la performance
Gardez à l'esprit que l'implémentation de certaines langues aura des conséquences très importantes sur la gestion de la mémoire d'exécution lors de l'utilisation de paramètres. D'où la raison pour laquelle les manuels de style de nombreuses langues recommandent de garder la liste des paramètres simple et courte . À 4 paramètres maximum, par exemple. Je vous laisse comme exercice pour comprendre pourquoi.
La réponse de Bevan et la mention des recommandations de Clean Code sont également pertinentes!
la source
Je soumets respectueusement que s'inquiéter de l'ordre des paramètres, c'est se soucier de la mauvaise chose.
Dans son livre " Clean Code ", il préconise de manière convaincante que les méthodes ne devraient jamais avoir plus de deux arguments - et la plupart ne devraient en avoir qu'un, le cas échéant. Dans ce cas, la commande est évidente ou sans importance.
Bien qu'imparfaitement, j'essaie de suivre le conseil de Oncle Bob - et cela améliore mon code.
Dans les rares cas où une méthode semble nécessiter plus d'informations, l'introduction d'un objet paramètre est une bonne idée. En général, je trouve que c'est la première étape vers la découverte d'un nouveau concept (objet) qui est la clé de mon algorithme.
la source
J'essaie de mettre les paramètres IN en premier, les paramètres OUT en second. Il existe également un ordre naturel, par exemple
createPoint(double x, double y)
fortement préférable àcreatePoint(double y, double x)
.la source
addAllTo(target, something1, something2)
.Je n'ai jamais vu de "meilleure pratique" documentée concernant ce sujet particulier, mais ma norme personnelle est de les énumérer dans l'ordre dans lequel elles apparaîtront dans la méthode pour laquelle elles sont utilisées ou si la méthode est plus complexe. passer au travers d’une couche de données Je les énumérerai dans l’ordre dans lequel elles apparaîtront dans les méthodes de schéma de base de données ou de couche de données.
De plus, quand il y a plusieurs surcharges d'une méthode, je remarque que la manière typique est de les lister en commençant par des paramètres communs à toutes les méthodes (ou à la plupart), chaque méthode étant ajoutée à la fin de chaque surcharge, comme :
la source
Ordre: entrée (s), sortie (s), paramètres optionnels.
la source
Je suis souvent la convention C / C ++
const
qui consiste à placer les paramètres en premier (c'est-à-dire les paramètres que vous transmettez par valeur), puis ceux que vous transmettez par référence. Ce n'est peut-être pas forcément la méthode correcte pour appeler des fonctions, mais si la manière dont chaque compilateur traite les paramètres vous intéresse, consultez les liens suivants pour connaître les règles régissant et / ou l'ordre dans lequel les paramètres sont placés dans la pile.http://msdn.microsoft.com/en-us/library/zthk2dkh%28v=vs.80%29.aspx
http://en.wikipedia.org/wiki/Calling_convention
la source
Je vais généralement juste avec l'ordre des paramètres "ce qui semble moins cyprique". Moins il me faudra aller à la définition de méthode / fonction, mieux ce sera. Et c’est agréable d’avoir des paramètres nommés qui décrivent ce à quoi ils sont utilisés, de cette façon lorsque la petite info-bulle apparaît (VS), cela le rend encore plus facile.
Si vous avez des lignes et des lignes de paramètres, vous pouvez envisager une conception différente. Prenez du recul et voyez comment vous pouvez le diviser en davantage de fonctions / méthodes. Juste une idée, mais quand j'ai une douzaine de paramètres dans ma fonction, ce n'est presque toujours pas un problème de paramètre, mais un problème de conception.
la source
L'utilisation de plusieurs paramètres est souvent un indicateur clair que vous violez le SRP avec cette méthode. Une méthode nécessitant de nombreux paramètres a peu de chance de faire une seule chose. L'excétion peut être une fonction mathématique ou une méthode de configuration, où plusieurs paramètres en tant que tels sont nécessaires. J'éviterais plusieurs paramètres comme le diable évite l'eau bénite. Plus vous utilisez de paramètres dans une méthode, plus il y a de chances que la méthode soit (trop) complexe; plus la complexité signifie: plus difficile à maintenir et moins souhaitable.
En principe, vous choisissez au hasard . Bien sûr, vous pourriez penser que le paramètre A est plus pertinent que le paramètre B ; mais cela pourrait ne pas être le cas pour les utilisateurs de votre API, qui pensent que B est le paramètre le plus pertinent. Donc, même si vous avez été attentif dans le choix de la commande, cela pourrait sembler aléatoire pour d'autres .
Il y a plusieurs issues:
a) Le cas trivial: N'utilisez pas plus d'un paramètre.
b) Comme vous n'avez pas précisé la langue que vous avez choisie, il est possible que vous choisissiez une langue avec des paramètres nommés . C'est un bon sucre syntaxique qui vous permet de desserrer la signification de l'ordre des paramètres:
fn(name:"John Doe", age:36)
Toutes les langues ne permettent pas de telles subtilités. Alors quoi alors?
c) Vous pouvez utiliser un dictionnaire / tableau de hachage / tableau associatif en tant que paramètre: par exemple, Javascript autoriserait ce qui suit:
fn({"name":"John Doe", age:36})
ce qui n'est pas loin de (b).d) Bien sûr, si vous travaillez avec un langage typé statiquement , tel que Java. vous pouvez utiliser une table de hachage , mais vous perdriez des informations de type (par exemple lorsque vous travaillez avec
HashMap<String, Object>
) lorsque les paramètres ont des types différents (et doivent être transtypés).La prochaine étape logique serait de passer un
Object
(si vous utilisez Java) avec les propriétés appropriées ou quelque chose de plus léger comme une structure (si vous écrivez par exemple C # ou C / C ++).Règle de base:
1) Meilleur cas - votre méthode n'a besoin d' aucun paramètre
2) Bon cas - votre méthode nécessite un paramètre
3) Cas tolérable - votre méthode nécessite deux paramètres
4) Tous les autres cas devraient être refactorisés
la source
Souvent, un objet complexe en tant que paramètre est préférable: la version des paramètres nommés du pauvre qui fonctionne sur la plupart des plateformes. Et ouvre la porte aux paramètres avec comportement à démarrer.
Pour obtenir un exemple de la plupart des choses que vous ne devriez pas faire, essayez de lire la documentation de la bibliothèque standard de PHP.
la source
Je les commande habituellement avec le choix d’abord, puis selon une mesure combinée de l’importance et de la fréquence d’utilisation en fonction d’un "sentiment" (peut être considéré comme
ORDER BY required DESC, SOME_MAGIC_FEELING(importancy,frequency)
) et non selon une pratique spécifique.Cependant, comme d’autres l’ont noté, j’estime que le problème sous-jacent qui fait que ce problème existe utilise trop de paramètres (IMHO, tout ce qui est> 3 est trop) et c’est le véritable problème que vous devriez résoudre. Il y a un article intéressant à ce sujet sur le blog de rebecca murphey.
Je pense que lorsque vous n'avez que 1 à 3 arguments, l'ordre correct est assez évident et vous ne faites que "sentir" ce qui est juste.
la source
Semblable à la réponse de @Wyatt Barnetts, rien de plus que quelques paramètres ou des paramètres très explicites pour la méthode, je vous recommanderais plutôt de passer un objet. Ceci est généralement plus facile à mettre à jour / maintenir, plus clair à lire et élimine la nécessité de se soucier de la commande . En outre, trop de paramètres pour une méthode constituent une odeur de code et il existe des modèles de refactoring courants que vous pouvez suivre pour vous aider à les corriger.
Exemple explicite:
Puisqu'il s'agit d'un exemple assez clairement défini et que l'addition est commutative (l'ordre n'a pas d'importance), continuez simplement avec.
Toutefois, si vous ajoutez quelque chose de plus complexe:
Deviendrait:
J'espère que cela t'aides...
la source
Commandez-le de la manière dont vous pensez que le curry bénéficiera probablement. Par exemple, les paramètres de fonction en premier.
la source
"Important d'abord" ne veut pas dire grand chose. Il y a des conventions.
Si vous transmettez l'objet appelant (souvent appelé expéditeur), cela commence en premier.
La liste devrait être fluide , ce qui signifie que vous devez savoir ce qu’est un argument au moment où vous le lisez. Exemple:
CopyFolder (chemin de la chaîne, bool récursif);
Si vous deviez mettre récursif en premier, ce serait déroutant car il n'y a pas encore de contexte. Si vous voulez déjà copier (1), un dossier (2), alors l'argument récursif commence à avoir un sens.
Cela permet également aux fonctionnalités de type IntelliSense de bien fonctionner: l'utilisateur apprend au fur et à mesure qu'il complète les arguments, il construit une compréhension de la méthode et de ce qu'elle fait. De même, les surcharges doivent conserver le même ordre pour les parties égales.
Ensuite, vous pouvez toujours trouver des arguments "égaux" à cet égard et vous pourriez être tenté de laisser l'ordre dépendre du type de l'argument. Juste parce que quelques cordes dans une rangée puis deux booléens sont plus jolies. À un certain niveau, cela deviendra un art plutôt qu'une compétence.
Je me moque bien de l’affirmation selon laquelle vous devriez envelopper tous les arguments dans un objet pour n’avoir qu’un seul argument. Cela ne fait que vous leurrer (cela ne rend pas la méthode moins complexe, elle a encore tous ces arguments, vous les avez cachés). Cela peut quand même être pratique si vous passez plusieurs fois d'une série à l'autre, le refactoring deviendra certainement beaucoup plus facile, mais au niveau de la conception, il ne fait que prétendre que vous faites une différence. Ce n'est pas comme si vous allez vous retrouver avec un objet significatif qui représente quelque chose, ce sera juste un tas d'arguments, pas différent de la liste dans la déclaration de la méthode. Cela ne rendra pas l'oncle Bob heureux.
la source