Existe-t-il des directives sur le nombre de paramètres qu'une fonction doit accepter?

114

J'ai remarqué que quelques fonctions avec lesquelles je travaille ont 6 paramètres ou plus, alors que dans la plupart des bibliothèques que j'utilise, il est rare de trouver une fonction qui en prend plus que 3.

Souvent, beaucoup de ces paramètres supplémentaires sont des options binaires pour modifier le comportement de la fonction. Je pense que certaines de ces fonctions à paramètres multiples devraient probablement être refactorisées. Existe-t-il une directive pour déterminer quel nombre est trop?

Darth Egregious
la source
4
@ Ominus: L'idée est que vous souhaitiez que vos cours soient concentrés. Les classes focalisées n'ont généralement pas autant de dépendances / d'attributs, vous auriez donc moins de paramètres pour le constructeur. Certains mots à la mode que les gens ajoutent à ce stade sont le principe de grande cohésion et de responsabilité unique . Si vous estimez que ceux-ci ne sont pas violés et ont encore besoin de nombreux paramètres, envisagez d'utiliser le modèle Builder.
c_maker
2
Ne suivez certainement pas l'exemple de MPI_Sendrecv () , qui prend 12 paramètres!
chrisaycock
6
Le projet sur lequel je travaille actuellement utilise un certain cadre, dans lequel les méthodes à 10 paramètres ou plus sont courantes. J'appelle une méthode particulière avec 27 paramètres dans quelques endroits. Chaque fois que je le vois, je meurs un peu à l'intérieur.
perp
3
N'ajoutez jamais de commutateurs booléens pour modifier le comportement d'une fonction. Diviser la fonction à la place. Décomposez le comportement commun dans de nouvelles fonctions.
Kevin Cline
2
@ Ominus Quoi? Seulement 10 paramètres? Ce n'est rien, il en faut beaucoup plus . : D
maaartinus

Réponses:

106

Je n'ai jamais vu de guide, mais d'après mon expérience, une fonction qui prend plus de trois ou quatre paramètres indique l'un des deux problèmes suivants:

  1. La fonction en fait trop. Il devrait être divisé en plusieurs fonctions plus petites, chacune ayant un jeu de paramètres plus petit.
  2. Il y a un autre objet caché à l'intérieur. Vous devrez peut-être créer un autre objet ou une autre structure de données contenant ces paramètres. Consultez cet article sur le modèle d' objet de paramètre pour plus d'informations.

Il est difficile de dire ce que vous regardez sans plus d'informations. Il est probable que le refactoring que vous devez faire est de scinder la fonction en fonctions plus petites, appelées à partir du parent, en fonction des indicateurs actuellement transmis à la fonction.

En procédant ainsi, il y a des avantages à obtenir:

  • Cela rend votre code plus facile à lire. Je trouve personnellement qu'il est beaucoup plus facile de lire une "liste de règles" composée d'une ifstructure qui appelle beaucoup de méthodes avec des noms descriptifs qu'une structure qui fait tout en une seule méthode.
  • C'est plus testable à l'unité. Vous avez divisé votre problème en plusieurs tâches plus petites individuellement très simples. La collection de tests unitaires serait alors constituée d'une suite de tests comportementaux vérifiant les chemins via la méthode principale et d'une collection de tests plus petits pour chaque procédure.
Michael K
la source
5
L'abstraction de paramètres a été transformée en un motif de conception? Qu'advient-il si vous avez 3 classes de paramètres. Ajoutez-vous 9 surcharges de méthodes supplémentaires pour gérer les différentes combinaisons de paramètres possibles? Cela ressemble à un problème de déclaration de paramètre O (n ^ 2). Oh, attendez, vous ne pouvez hériter que d'une classe en Java / C #, il faudra donc un peu plus de biolerplate (peut-être un peu plus de sous-classes) pour que cela fonctionne dans la pratique. Désolé, je ne suis pas convaincu. Ignorer les approches plus expressives qu'une langue peut offrir en faveur de la complexité semble tout simplement inacceptable.
Evan Plaice
Sauf si vous utilisez le modèle Objet de modèle pour empaqueter les variables dans une instance d'objet et le transmettre en tant que paramètre. Cela fonctionne pour l’emballage, mais il peut être tentant de créer des classes de variables différentes simplement pour simplifier la définition de la méthode.
Evan Plaice
@ EvanPlaice Je ne dis pas que vous devez utiliser ce modèle chaque fois que vous avez plus d'un paramètre - vous avez absolument raison de dire que cela devient encore plus méchant que la première liste. Il peut arriver que vous ayez vraiment besoin d'un grand nombre de paramètres et que cela ne fonctionne tout simplement pas de les envelopper dans un objet. Je n'ai pas encore rencontré de cas de développement d'entreprise qui ne soit pas classé dans l'un des deux compartiments mentionnés dans ma réponse - cela ne veut pas dire qu'un tel système n'existe pas.
Michael K
@MichaelK Si vous ne les avez jamais utilisés, essayez de rechercher des "initialiseurs d'objet" dans Google. C'est une approche assez nouvelle qui réduit considérablement la définition standard. En théorie, vous pouvez éliminer les constructeurs de classes, les paramètres et les surcharges d'un seul coup. En pratique cependant, il est généralement bon de conserver un constructeur commun et de s'appuyer sur la syntaxe 'initialiseur d'objet' pour le reste des propriétés obscure / niche. IMHO, c'est au plus près de l'expressivité des langages à typage dynamique dans un langage à typage statique.
Evan Plaice
@Evain Plaice: Depuis quand les langages à typage dynamique sont-ils expressifs?
ThomasX
41

Selon "Clean Code: Un manuel d'artisanat agile", zéro est l'idéal, un ou deux sont acceptables, trois dans des cas spéciaux et quatre ou plus, jamais!

Les mots de l'auteur:

Le nombre idéal d'arguments pour une fonction est zéro (niladique). Vient ensuite l'un (monadique), suivi de près par deux (dyadique). Trois arguments (triadiques) doivent être évités autant que possible. Plus de trois (polyadiques) nécessitent une justification très spéciale - et ne devraient donc pas être utilisés de toute façon.

Dans ce livre, il y a un chapitre qui ne traite que des fonctions pour lesquelles les paramètres sont largement discutés. Je pense donc que ce livre peut constituer une bonne indication du nombre de paramètres dont vous avez besoin.

À mon avis, un paramètre est préférable à personne car je pense que ce qui se passe est plus clair.

Par exemple, à mon avis, le deuxième choix est préférable car la méthode utilisée est plus claire:

LangDetector detector = new LangDetector(someText);
//lots of lines
String language = detector.detectLanguage();

contre.

LangDetector detector = new LangDetector();
//lots of lines
String language = detector.detectLanguage(someText);

À propos de beaucoup de paramètres, cela peut être un signe que certaines variables peuvent être regroupées dans un seul objet ou, dans ce cas, beaucoup de booléens peuvent indiquer que la fonction / méthode en fait plus qu'une chose, et dans ce cas, est préférable de refactoriser chacun de ces comportements dans une fonction différente.

Renato Dinhani
la source
8
"Trois dans des cas spéciaux et quatre ou plus, jamais!" BS. Que diriez-vous de Matrix.Create (x1, x2, x3, x4, x5, x6, x7, x8, x9); ?
Lukasz Madon
71
Le zéro est idéal? Comment diable les fonctions obtiennent-elles des informations? Global / instance / statique / quelles que soient les variables? YUCK.
Peter C
9
C'est un mauvais exemple. La réponse est évidemment: String language = detectLanguage(someText);. Dans les deux cas où vous avez passé exactement le même nombre d'arguments, il arrive que vous ayez scindé l'exécution de la fonction en deux à cause d'un langage médiocre.
Matthieu M.
8
@lukas, dans les langages prenant en charge des constructions aussi sophistiquées que les tableaux ou les listes (gasp!), que se passe-t-il, par exemple, Matrix.Create(input);où se inputtrouve un .NET IEnumerable<SomeAppropriateType>? De cette façon, vous n'avez pas non plus besoin d'une surcharge séparée lorsque vous voulez créer une matrice contenant 10 éléments au lieu de 9.
CVn
9
Zéro argument en tant qu '"idéal" est un manque à gagner et l'une des raisons pour lesquelles je pense que le Clean Code est largement surestimé.
user949300
24

Si les classes de domaine de l'application sont correctement conçues, le nombre de paramètres que nous transmettons à une fonction sera automatiquement réduit, car les classes savent comment faire leur travail et disposent de suffisamment de données pour effectuer leur travail.

Par exemple, supposons que vous ayez une classe de gestionnaires qui demande à une classe de 3e année de terminer les travaux.

Si vous modélisez correctement,

3rdGradeClass.finishHomework(int lessonId) {
    result = students.assignHomework(lessonId, dueDate);
    teacher.verifyHomeWork(result);
}

C'est simple.

Si vous n'avez pas le bon modèle, la méthode sera la suivante

Manager.finishHomework(grade, students, lessonId, teacher, ...) {
    // This is not good.
}

Le modèle correct réduit toujours les paramètres de fonction entre les appels de méthode car les fonctions correctes sont déléguées à leurs propres classes (responsabilité unique) et disposent de suffisamment de données pour effectuer leur travail.

Chaque fois que le nombre de paramètres augmente, je vérifie mon modèle pour voir si j'ai correctement conçu mon modèle d'application.

Il existe cependant quelques exceptions: lorsque je dois créer un objet de transfert ou des objets de configuration, je vais d'abord utiliser un modèle de générateur pour générer de petits objets construits avant de construire un grand objet de configuration.

java_mouse
la source
16

Un aspect que l’autre réponse ne prend pas est la performance.

Si vous programmez dans un langage de niveau suffisamment bas (C, C ++, assemblage), un grand nombre de paramètres peut être très préjudiciable aux performances de certaines architectures, notamment si la fonction est appelée un grand nombre de fois.

Quand un appel de fonction est effectué dans le bras , par exemple, les quatre premiers arguments sont placés dans les registres r0à r3et autres arguments doivent être poussées sur la pile. Garder un nombre d'arguments inférieur à cinq peut faire toute une différence pour les fonctions critiques.

Pour les fonctions qui sont appelées très souvent, même le fait que le programme doit mettre en place les arguments avant chaque appel peut affecter les performances ( r0à r3peut être remplacé par la fonction appelée et devra être remplacé avant le prochain appel) si à cet égard zéro argument est le meilleur.

Mise à jour:

KjMag aborde le sujet intéressant de l'inline. Cela permet, d’une certaine manière, d’atténuer cette situation, car cela permettra au compilateur d’effectuer les mêmes optimisations que celles que vous auriez pu réaliser si vous écriviez en assemblage pur. En d'autres termes, le compilateur peut voir quels paramètres et quelles variables sont utilisés par la fonction appelée et peut optimiser l'utilisation des registres de manière à minimiser la lecture / écriture de la pile.

Il y a cependant quelques problèmes avec l'inline.

  1. L'inclusion entraîne la croissance du fichier binaire compilé, car le même code est dupliqué sous forme binaire s'il est appelé à partir de plusieurs emplacements. Ceci est préjudiciable en ce qui concerne l'utilisation d'I-cache.
  2. Les compilateurs ne permettent généralement que l’alignement jusqu’à un certain niveau (3 étapes IIRC?). Imaginez que vous appelez une fonction en ligne à partir d'une fonction en ligne à partir d'une fonction en ligne. La croissance binaire exploserait si elle inlineétait considérée comme obligatoire dans tous les cas.
  3. Il existe de nombreux compilateurs qui vont complètement ignorer inlineou vous donner des erreurs quand ils le rencontrent.
Leo
la source
Qu'il soit bon ou mauvais de transmettre un grand nombre de paramètres du point de vue des performances dépend des alternatives. Si une méthode nécessite une douzaine d'informations et qu'on l'appellera des centaines de fois avec les mêmes valeurs pour onze d'entre elles, la prise d'une méthode par un tableau peut être plus rapide que si elle prenait une douzaine de paramètres. D'autre part, si chaque appel nécessite un ensemble unique de douze valeurs, la création et le remplissage du tableau pour chaque appel peuvent être plus lents que de simplement transmettre les valeurs directement.
Supercat
L'inline ne résout-il pas ce problème?
KjMag
@KjMag: Oui, dans une certaine mesure. Mais il y a beaucoup de pièges selon le compilateur. Les fonctions ne sont généralement en ligne que jusqu'à un certain niveau (si vous appelez une fonction en ligne qui appelle une fonction en ligne qui appelle une fonction en ligne ...). Si la fonction est volumineuse et appelée de nombreux endroits, l'inlignage rend le binaire plus gros, ce qui peut signifier davantage d'erreurs dans I-cache. L'inline peut donc aider, mais ce n'est pas une solution miracle. (Sans parler du fait qu'il existe de nombreux anciens compilateurs intégrés qui ne prennent pas en charge inline.)
Leo
7

Lorsque la liste de paramètres passe à plus de cinq, définissez une structure ou un objet "context".

Ceci est fondamentalement juste une structure qui contient tous les paramètres optionnels avec quelques valeurs par défaut sensibles définies.

Dans le monde procédural C, une structure simple ferait l'affaire. En Java, C ++, un objet simple suffira. Ne plaisante pas avec les accesseurs ou les setters car le seul but de l’objet est de maintenir des valeurs "publiquement" réglables.

James Anderson
la source
Je conviens qu'un objet de contexte peut s'avérer très utile lorsque la structure des paramètres de fonction commence à devenir assez complexe. J'avais récemment blogué sur l'utilisation d' objets de contexte avec un motif semblable à celui d'un visiteur
Lukas Eder le
5

Non, il n'y a pas de directive standard

Cependant, certaines techniques peuvent rendre une fonction avec beaucoup de paramètres plus supportable.

Vous pouvez utiliser un paramètre list-if-args (args *) ou un paramètre dictionary-of-args (kwargs **)

Par exemple, en python:

// Example definition
def example_function(normalParam, args*, kwargs**):
  for i in args:
    print 'args' + i + ': ' + args[i] 
  for key in kwargs:
    print 'keyword: %s: %s' % (key, kwargs[key])
  somevar = kwargs.get('somevar','found')
  missingvar = kwargs.get('somevar','missing')
  print somevar
  print missingvar

// Example usage

    example_function('normal parameter', 'args1', args2, 
                      somevar='value', missingvar='novalue')

Les sorties:

args1
args2
somevar:value
someothervar:novalue
value
missing

Ou vous pouvez utiliser la syntaxe de définition littérale d'objet

Par exemple, voici un appel JavaScript jQuery pour lancer une demande AJAX GET:

$.ajax({
  type: 'GET',
  url: 'http://someurl.com/feed',
  data: data,
  success: success(),
  error: error(),
  complete: complete(),
  dataType: 'jsonp'
});

Si vous regardez la classe ajax de jQuery, il y a beaucoup (environ 30) propriétés supplémentaires qui peuvent être définies; principalement parce que les communications ajax sont très complexes. Heureusement, la syntaxe littérale des objets facilite la vie.


C # intellisense fournit une documentation active des paramètres, il n’est donc pas rare de voir des arrangements très complexes de méthodes surchargées.

Les langages à typage dynamique comme python / javascript n’ont pas cette capacité, il est donc beaucoup plus courant de voir les arguments de mot-clé et les définitions littérales d’objet.

Je préfère les définitions littérales d'objet ( même en C # ) pour la gestion de méthodes complexes, car vous pouvez voir explicitement quelles propriétés sont définies lorsqu'un objet est instancié. Vous devrez faire un peu plus de travail pour gérer les arguments par défaut, mais à long terme, votre code sera beaucoup plus lisible. Avec les définitions littérales d'objet, vous pouvez cesser de dépendre de la documentation pour comprendre ce que fait votre code à première vue.

IMHO, les méthodes surchargées sont fortement surestimées.

Remarque: Si je me souviens bien, le contrôle d'accès en lecture seule devrait fonctionner pour les constructeurs littéraux d'objets en C #. Ils fonctionnent essentiellement de la même manière que la définition des propriétés dans le constructeur.


Si vous n'avez jamais écrit de code non trivial dans un langage Java / typé dynamiquement (python) et / ou fonctionnel / prototype, je vous suggère fortement de l'essayer. Ce peut être une expérience enrichissante.

Il peut être effrayant d’abord de rompre votre dépendance à l’égard des paramètres pour l’initialisation de la fonction / méthode, mais vous apprendrez à en faire beaucoup plus avec votre code sans ajouter de complexité inutile.

Mise à jour:

J'aurais probablement dû fournir des exemples pour illustrer l'utilisation dans un langage à typage statique, mais je ne pense pas actuellement à un contexte à typage statique. En gros, j'ai trop travaillé dans un contexte typé dynamiquement pour basculer subitement.

Ce que je ne sais est objet syntaxe de définition littérale est tout à fait possible dans les langues statiquement typés (au moins en C # et Java) parce que je les ai utilisés auparavant. Dans les langages à typage statique, ils sont appelés "initialiseurs d'objet". Voici quelques liens pour montrer leur utilisation en Java et en C # .

Evan Plaice
la source
3
Je ne suis pas sûr d'aimer cette méthode, principalement parce que vous perdez la valeur d'auto-documentation de paramètres individuels. Ceci est parfaitement logique pour des listes d'éléments similaires (par exemple, une méthode qui prend une liste de chaînes et les concatène), mais pour un jeu de paramètres arbitraire, cela est pire que l'appel d'une méthode longue.
Michael K
@MichaelK Jetons un autre regard sur les initialiseurs d'objet. Ils vous permettent de définir explicitement les propriétés par opposition à leur définition implicite dans les paramètres de méthode / fonction traditionnels. Lisez ceci, msdn.microsoft.com/en-us/library/bb397680.aspx , pour voir ce que je veux dire.
Evan Plaice
3
Créer un nouveau type juste pour gérer la liste de paramètres ressemble exactement à la définition de complexité inutile ... Bien sûr, les langages dynamiques vous permettent d'éviter cela, mais vous obtenez alors une seule boule de paramètre goo. Quoi qu'il en soit, cela ne répond pas à la question posée.
Telastyn
@Telastyn De quoi parlez-vous? Aucun nouveau type n'a été créé, vous déclarez les propriétés directement à l'aide de la syntaxe littérale d'objet. C'est comme si vous définissiez un objet anonyme, mais la méthode l'interprète comme un groupe de paramètres clé = valeur. Ce que vous voyez est une instanciation de méthode (et non un objet encapsulant un paramètre). Si votre boeuf utilise un paramétrage, consultez le modèle d'objet de paramètre mentionné dans l'une des autres questions, car c'est exactement ce que c'est.
Evan Plaice
@EvanPlaice - Sauf que les langages de programmation statiques nécessitent généralement un type déclaré (souvent nouveau) afin d'autoriser le modèle d'objet de paramètre.
Telastyn
3

Personnellement, plus de 2, c’est là que mon code déclenche une alarme d’odeur. Lorsque vous considérez des fonctions comme des opérations (c’est-à-dire une traduction d’entrée en sortie), il est rare que plus de 2 paramètres soient utilisés dans une opération. Les procédures (c'est-à-dire une série d'étapes pour atteindre un objectif) nécessiteront davantage d'intrants et constitueront parfois la meilleure approche, mais dans la plupart des langues, ces jours ne devraient pas être la norme.

Mais encore une fois, c'est la ligne directrice plutôt qu'une règle. J'ai souvent des fonctions qui prennent plus de deux paramètres en raison de circonstances inhabituelles ou d'une facilité d'utilisation.

Telastyn
la source
2

Comme le dit Evan Plaice, je suis un fervent partisan de la simple insertion de tableaux associatifs (ou de la structure de données comparable de votre langage) dans des fonctions autant que possible.

Ainsi, au lieu de (par exemple) ceci:

<?php

createBlogPost('the title', 'the summary', 'the author', 'the date of publication, 'the keywords', 'the category', 'etc');

?>

Aller pour:

<?php

// create a hash of post data
$post_data = array(
  'title'    => 'the title',
  'summary'  => 'the summary',
  'author'   => 'the author',
  'pubdate'  => 'the publication date',
  'keywords' => 'the keywords',
  'category' => 'the category',
  'etc'      => 'etc',
);

// and pass it to the appropriate function
createBlogPost($post_data);

?>

Wordpress fait beaucoup de choses de cette façon, et je pense que cela fonctionne bien. (Bien que mon exemple de code ci-dessus soit imaginaire et ne soit pas un exemple de Wordpress.)

Cette technique vous permet de passer facilement beaucoup de données dans vos fonctions, tout en vous évitant d'avoir à vous rappeler de l'ordre dans lequel chacune doit être passée.

Vous apprécierez également cette technique lorsque vient le temps de refactoriser - au lieu de devoir potentiellement modifier l'ordre des arguments d'une fonction (par exemple, lorsque vous réalisez que vous devez passer Yet Another Argument), vous n'avez pas besoin de modifier le paramètre de votre fonction. liste du tout.

Non seulement cela vous évite d'avoir à réécrire la définition de votre fonction, mais vous évite également de devoir modifier l'ordre des arguments chaque fois que la fonction est appelée. C'est une victoire énorme.

Chris Allen Lane
la source
Voir cette publication met en évidence un autre avantage de l'approche de pass-a-hash: notez que mon premier exemple de code est si long qu'il génère une barre de défilement, tandis que le second s'adapte parfaitement à la page. La même chose sera vraisemblablement vraie dans votre éditeur de code.
Chris Allen Lane
0

Une réponse précédente mentionnait un auteur fiable qui a déclaré que moins vous avez de paramètres dans vos fonctions, mieux vous vous en portez. La réponse n'explique pas pourquoi mais les livres l'expliquent. Voici deux des raisons les plus convaincantes pour lesquelles vous devez adopter cette philosophie et avec lesquelles je suis personnellement d'accord:

  • Les paramètres appartiennent à un niveau d'abstraction différent de celui de la fonction. Cela signifie que le lecteur de votre code devra réfléchir à la nature et au but des paramètres de vos fonctions: cette pensée est "de niveau inférieur" à celle du nom et du but des fonctions correspondantes.

  • La seconde raison d’avoir le moins de paramètres possibles pour une fonction est le test: par exemple, si vous avez une fonction à 10 paramètres, réfléchissez au nombre de combinaisons de paramètres nécessaires pour couvrir tous les scénarios de test, par exemple pour une unité. tester. Moins de paramètres = moins de tests.

Billal Begueradj
la source
0

Pour donner un peu plus de contexte aux conseils relatifs au nombre idéal d'arguments de fonction nuls dans le "Code propre: manuel pour la maîtrise du logiciel agile" de Robert Martin, l'auteur cite notamment l'un des points suivants:

Les arguments sont difficiles. Ils prennent beaucoup de pouvoir conceptuel. C'est pourquoi je me suis débarrassé de la quasi-totalité d'entre eux de l'exemple. Considérons, par exemple, le StringBufferdans l'exemple. Nous aurions pu le passer sous forme d'argument plutôt que d'en faire une variable d'instance, mais nos lecteurs auraient alors dû l'interpréter à chaque fois qu'ils l'auraient vue. Lorsque vous lisez l'histoire racontée par le module, includeSetupPage() c'est plus facile à comprendre que includeSetupPageInto(newPageContent). L'argument est à un niveau d'abstraction différent du nom de la fonction et vous oblige à connaître un détail (en d'autres termes StringBuffer) qui n'est pas particulièrement important à ce stade.

Pour son includeSetupPage()exemple ci-dessus, voici un extrait de son "code propre" refactorisé à la fin du chapitre:

// *** NOTE: Commments are mine, not the author's ***
//
// Java example
public class SetupTeardownIncluder {
    private StringBuffer newPageContent;

    // [...] (skipped over 4 other instance variables and many very small functions)

    // this is the zero-argument function in the example,
    // which calls a method that eventually uses the StringBuffer instance variable
    private void includeSetupPage() throws Exception {
        include("SetUp", "-setup");
    }

    private void include(String pageName, String arg) throws Exception {
        WikiPage inheritedPage = findInheritedPage(pageName);
        if (inheritedPage != null) {
            String pagePathName = getPathNameForPage(inheritedPage);
            buildIncludeDirective(pagePathName, arg);
        }
    }

    private void buildIncludeDirective(String pagePathName, String arg) {
        newPageContent
            .append("\n!include ")
            .append(arg)
            .append(" .")
            .append(pagePathName)
            .append("\n");
    }
}

L '"école de pensée" de l'auteur plaide pour des classes réduites, un nombre faible (idéalement, 0) d'arguments de fonction et de très petites fonctions. Bien que je ne sois pas non plus totalement d’accord avec lui, j’ai trouvé cela stimulant et j’ai le sentiment que l’idée des arguments de fonction nulle en tant qu’idéal peut valoir la peine d’être examinée. Notez également que même son petit extrait de code ci-dessus possède des fonctions d’argument non nulles, je pense donc que cela dépend du contexte.

(Et comme d'autres l'ont fait remarquer, il affirme également que plus d'arguments compliquent les choses d'un point de vue test. Mais je souhaitais ici principalement mettre en évidence l'exemple ci-dessus et sa justification pour des arguments à fonction nulle.)

fiston
la source
-2

Idéalement zéro. Un ou deux vont bien, trois dans certains cas.
Quatre ou plus est généralement une mauvaise pratique.

Outre les principes de responsabilité unique que d'autres ont mentionnés, vous pouvez également y penser du point de vue des tests et du débogage.

S'il y a un paramètre, connaître ses valeurs, les tester et trouver une erreur avec elles est relativement facile car il n'y a qu'un seul facteur. Au fur et à mesure que vous augmentez les facteurs, la complexité totale augmente rapidement. Pour un exemple abstrait:

Envisagez un programme «quoi porter par ce temps». Considérez ce que cela pourrait faire avec une entrée - la température. Comme vous pouvez l’imaginer, les résultats des vêtements à porter sont assez simples en fonction de ce facteur. Maintenant, réfléchissez à ce que le programme pourrait / devrait / devrait faire si la température, l’humidité, le point de rosée, les précipitations, etc. sont dépassés

Michael Durrant
la source
12
Si une fonction a zéro paramètre, elle renvoie soit une valeur constante (utile dans certaines circonstances, mais plutôt restrictive), soit utilise un état caché qui serait mieux rendu explicite. (Dans les appels de méthode OO, l'objet context est suffisamment explicite pour ne pas causer de problèmes.)
Donal Fellows
4
-1 pour ne pas citer la source
Joshua Drake le
Êtes-vous sérieusement en train de dire qu'idéalement, toutes les fonctions ne prendraient aucun paramètre? Ou est-ce l'hyperbole?
GreenAsJade
1
Voir l'argument de Oncle Bob à l' adresse : informit.com/articles/article.aspx?p=1375308 et notez qu'il dit en bas: "Les fonctions doivent avoir un petit nombre d'arguments. Aucun argument n'est optimal, suivi de un, deux et trois. Plus de trois sont très discutables et doivent être évités avec préjugés. "
Michael Durrant
J'ai donné la source. Drôle aucun commentaire depuis lors. J'ai également essayé de répondre à la partie "recommandations", car beaucoup considèrent désormais Oncle Bob et Clean Code comme des instructions. Il est intéressant de noter que la réponse la plus élevée (jusqu’à présent) indique que personne n’est au courant Oncle Bob n'avait pas l' intention de faire autorité, mais c'est un peu le cas et cette réponse tente au moins d'être une réponse aux spécificités de la question.
Michael Durrant