Clean Code: Fonctions avec peu de paramètres [fermé]

49

J'ai lu les premiers chapitres de Clean Code de Robert C. Martin, et il me semble que c'est assez bon, mais j'ai un doute, dans une partie il est mentionné qu'il est bon (cognitivement) que les fonctions aient aussi peu de paramètres Autant que possible, cela suggère même que 3 paramètres ou plus, c'est trop pour une fonction (que je trouve très exagérée et idéaliste), alors j'ai commencé à me poser des questions ...

Les pratiques consistant à utiliser des variables globales et à transmettre de nombreux arguments aux fonctions seraient de mauvaises pratiques de programmation, mais l'utilisation de variables globales peut considérablement réduire le nombre de paramètres dans les fonctions ...

Je voulais donc savoir ce que vous en pensez. Est-il utile d'utiliser des variables globales pour réduire le nombre de paramètres des fonctions ou pas? Dans quels cas serait-ce?

Ce que je pense, c'est que cela dépend de plusieurs facteurs:

  • Taille du code source.
  • Nombre de paramètres en moyenne des fonctions.
  • Nombre de fonctions.
  • Fréquence à laquelle les mêmes variables sont utilisées.

À mon avis, si la taille du code source est relativement petite (moins de 600 lignes de code), il existe de nombreuses fonctions, les mêmes variables sont transmises en tant que paramètres et les fonctions ont de nombreux paramètres. L'utilisation de variables globales vaudrait la peine aimerait savoir...

  • Partagez-vous mon opinion?
  • Que pensez-vous des autres cas où le code source est plus gros, etc.?

PS . J'ai vu ce billet , les titres sont très similaires, mais il ne me demande pas ce que je veux savoir.

OiciTrap
la source
144
Je ne pense pas que l'alternative serait globale, mais plutôt de consolider des arguments en objets. C'est probablement plus une suggestion qui postLetter(string country, string town, string postcode, string streetAddress, int appartmentNumber, string careOf)est une version malodorante de postLetter(Address address). Continuez à lire le livre, j'espère qu'il dira quelque chose comme ça.
Nathan Cooper
3
@DocBrown J'ai pris la question comme signifiant quelque chose de plus semblable à l'oncle Bob qui dit de ne pas utiliser plus de 3 paramètres pour que je contourne ce problème en utilisant des variables globales, n'est-ce pas? :-) Je pense que probablement l'auteur ne sait pas qu'il existe de meilleurs moyens de contourner ce problème - comme mentionné dans les réponses ci-dessous.
bytedev
9
Pas plus de n paramètres est une règle de base (pour toute valeur de n), non gravée sur un diamant. Ne confondez pas un bon conseil avec un mandat. Beaucoup de paramètres sont généralement une odeur de code que vous avez trop dans une fonction / méthode. Les gens avaient l'habitude d'éviter de se scinder en plusieurs fonctions pour éviter les frais supplémentaires liés aux appels supplémentaires. Peu d'applications sont aussi intensives en performances et un profileur peut vous dire quand et où vous devez éviter des appels supplémentaires.
Jared Smith
14
Cela montre ce qui ne va pas avec ce type de règle sans jugement: cela ouvre la porte à des «solutions» sans jugement. Si une fonction a de nombreux arguments, elle peut indiquer une conception sous-optimale, généralement pas seulement de la fonction, mais du contexte dans lequel elle est utilisée. La solution (si besoin est) est de chercher à refactoriser le code. Je ne peux pas vous donner une règle simple, générale et sans jugement sur la façon de le faire, mais cela ne signifie pas que "pas plus de N arguments" est une bonne règle.
sdenham
4
Si vous avez trop de paramètres pour une fonction, les probabilités sont que certains d'entre eux sont liés et doivent être regroupés dans un objet qui devient alors un paramètre unique encapsulant plusieurs éléments de données. Il y a une troisième option ici.

Réponses:

113

Je ne partage pas votre opinion. À mon avis, l’utilisation de variables globales est une pratique pire que davantage de paramètres, quelles que soient les qualités que vous avez décrites. Mon raisonnement est que plus de paramètres peuvent rendre une méthode plus difficile à comprendre, mais les variables globales peuvent causer de nombreux problèmes pour le code, notamment une testabilité médiocre, des bogues de simultanéité et un couplage étroit. Quel que soit le nombre de paramètres d’une fonction, elle n’aura pas les mêmes problèmes que les variables globales.

... les mêmes variables sont passées en paramètres

Ce peut être une odeur de design. Si vous transmettez les mêmes paramètres à la plupart des fonctions de votre système, vous devrez peut-être résoudre un problème transversal en introduisant un nouveau composant. Je ne pense pas que transmettre la même variable à plusieurs fonctions soit un bon raisonnement pour introduire des variables globales.

Lors d'une édition de votre question, vous avez indiqué que l'introduction de variables globales pourrait améliorer la lisibilité du code. Je ne suis pas d'accord. L'utilisation de variables globales est masquée dans le code d'implémentation, tandis que les paramètres de fonction sont déclarés dans la signature. Les fonctions devraient idéalement être pures. Ils ne devraient opérer que sur leurs paramètres et ne devraient avoir aucun effet secondaire. Si vous avez une fonction pure, vous pouvez raisonner à propos de cette fonction en regardant une seule fonction. Si votre fonction n'est pas pure, vous devez tenir compte de l'état des autres composants et il devient beaucoup plus difficile de raisonner.

Samuel
la source
Ok, c’est bien d’entendre d’autres opinions, mais en ce qui concerne le design , je programme en C des problèmes résolus par des méthodes d’intelligence artificielle et j’ai tendance à utiliser de nombreuses fonctions qui utilisent presque toujours les mêmes matrices, tableaux ou variables (qui Je passe comme paramètres aux fonctions), je dis cela parce que je ne sens pas que je peux mettre ces variables dans un concept / chose commun comme une structure ou une union afin que je ne sache pas comment faire un meilleur design, c'est pourquoi je pense que l'utilisation de variables globales dans ce cas pourrait valoir la peine, mais je me trompe probablement.
OiciTrap
1
Cela ne ressemble pas à un problème de conception. Je pense toujours que le meilleur design est de passer des paramètres aux fonctions. Dans un système d'intelligence artificielle comme celui que vous décrivez, il serait utile d'écrire des tests unitaires pour tester les éléments du système. Le moyen le plus simple de procéder consiste à utiliser des paramètres.
Samuel
96
Plus de paramètres rendent un sous-programme plus difficile à comprendre, des variables globales rendent l'ensemble du programme, autrement dit, tous les sous-programmes plus difficiles à comprendre.
Jörg W Mittag
2
Je maintiens une base de code où certaines fonctions prennent plus d'une douzaine de paramètres. C'est un énorme gaspillage de temps - chaque fois que j'ai besoin d'appeler la fonction, j'ai besoin d'ouvrir ce fichier dans une autre fenêtre pour que je sache dans quel ordre les paramètres doivent être spécifiés. Si j'utilisais un IDE qui me donnait quelque chose comme intellisense ou si j'utilisais un langage qui avait des paramètres nommés, ce ne serait pas si grave, mais qui peut se souvenir de l'ordre dans lequel se trouvent une douzaine de paramètres pour toutes ces fonctions?
Jerry Jeremiah
6
La réponse est correcte dans ce qui est dit, néanmoins il semble que cela prenne le malentendu des PO à propos des recommandations dans "Clean Code" pour acquis. Je suis sûr qu'il n'y a aucune recommandation pour remplacer les paramètres de fonction par des globales dans ce livre.
Doc Brown
68

Vous devriez éviter les variables globales comme la peste .

Je ne mettrais pas une limite difficile à nombre d'arguments (comme 3 ou 4), mais vous ne voulez les garder au minimum, si possible.

Utilisez structs (ou des objets en C ++) pour regrouper des variables dans une seule entité et les transmettre (par référence) aux fonctions. Habituellement, une fonction reçoit une structure ou un objet (contenant quelques éléments différents), ainsi que deux autres paramètres indiquant à la fonction de faire quelque chose struct.

Pour que le code soit modulaire, propre et qui sent bon, essayez de vous en tenir au principe de responsabilité unique . Faites-le avec vos structs (ou objets), les fonctions et les fichiers source. Si vous faites cela, le nombre naturel de paramètres passés à une fonction sera évident.

robert bristow-johnson
la source
5
Quelle est la principale différence entre transmettre des dizaines de paramètres cachés dans une structure et les transmettre explicitement?
Ruslan
21
@Ruslan Cohesion.
abuzittin gillifirca
9
Et vous êtes plus susceptible de reformuler la fonction en fonctions plus petites, car vous pouvez simplement transmettre un paramètre aux sous-fonctions au lieu de dizaines de paramètres. Et moins de risque de confondre les paramètres si vous utilisez des arguments de position.
Hans Olsson
8
C'est bien, mais vous devez assurer la cohérence dans les structures - assurez-vous que les paramètres regroupés dans une structure sont «liés». Vous pouvez utiliser plusieurs structures dans certaines circonstances.
Andrew Dodds
8
@abuzittingillifirca Vous n'obtenez pas automatiquement la cohésion. Si la seule justification pour mettre des paramètres dans une structure est de les passer à une fonction particulière, la cohésion est probablement illusoire.
sdenham
55

Nous parlons de charge cognitive, pas de syntaxe. La question est donc ... Qu'est - ce qu'un paramètre dans ce contexte?

Un paramètre est une valeur qui affecte le comportement de la fonction. Plus vous avez de paramètres, plus vous obtenez de combinaisons de valeurs possibles, plus le raisonnement sur la fonction est complexe.

En ce sens, les variables globales utilisées par la fonction sont des paramètres. Ce sont des paramètres qui n'apparaissent pas dans sa signature, qui ont des problèmes d'ordre de construction, de contrôle d'accès et de rémanence.

À moins que ce paramètre ne soit considéré comme une préoccupation transversale , c'est-à-dire un état à l'échelle du programme que tout utilise mais que rien ne change (par exemple un objet de journalisation), vous ne devez pas remplacer les paramètres de fonction par des variables globales. Ils seraient toujours des paramètres, mais plus méchants.

Quentin
la source
11
Pour vous un +1, que ce soit une toilette ou une commode, ils ont la même odeur. Joli boulot en montrant le loup déguisé en mouton.
Jared Smith
1
+1 pour avoir déclaré que tant de parmes que de vars globaux sont mauvais. Mais je veux clarifier quelque chose. Dans la plupart des langages, les paramètres primitifs sont passés par valeur par défaut (Java), et dans d'autres, vous pouvez les passer explicitement par valeur (PL / SQL). D'autre part, les primitives globales sont toujours accessibles par référence (pour ainsi dire). Ainsi, les paramètres, au moins ceux de type primitif, sont toujours plus sûrs que les variables globales. Bien sûr, avoir plus de deux ou trois paramètres est une odeur, et avoir douze paramètres est une odeur énorme qui doit être refactorisée.
Tulains Córdova
4
Absolument, une variable globale EST un paramètre caché.
Bill K
+1 En ce qui vous concerne, j'ai vu des simulations MATLAB s'appuyant sur des variables globales pour transmettre des données. Le résultat était complètement illisible car il était si difficile de dire quelles variables étaient des paramètres pour quelle fonction.
Cort Ammon
34

IMHO votre question est basée sur un malentendu. Dans "Clean Code", Bob Martin ne suggère pas de remplacer les paramètres de fonction répétés par des globaux, ce serait un conseil vraiment affreux. Il suggère de les remplacer par des variables membres privées de la classe de la fonction. Et il propose également de petites classes cohérentes (généralement plus petites que les 600 lignes de code que vous avez mentionnées), de sorte que ces variables membres ne sont définitivement pas des globales.

Ainsi, lorsque vous avez l’opinion dans un contexte comportant moins de 600 lignes "l’utilisation de variables globales en vaut la peine" , vous partagez parfaitement l’opinion de Oncle Bob. Bien entendu, il est discutable de choisir le nombre idéal de "3 paramètres au maximum" et si cette règle entraîne parfois un trop grand nombre de variables membres, même dans de petites classes. IMHO c'est un compromis, il n'y a pas de règle absolue où tracer la ligne.

Doc Brown
la source
10
Je n'ai jamais compris pourquoi quelqu'un préférait donner à sa classe l'état de son groupe en introduisant des paramètres dans un constructeur au lieu de simplement vivre avec un argument réel. Cela m'a toujours semblé être une énorme augmentation de la complexité. (Un exemple concret que j'ai vu de cela est un objet de connexion à une base de données, ce qui rendait impossible le suivi de l'état de la base de données via le programme presque impossible lorsqu'il était associé à une injection de dépendance.) Mais peut-être que Clean Code en a plus à dire à ce sujet matière. Les règles globales sont, bien sûr, une option encore pire en ce qui concerne l’état des choses.
jpmc26
2
@ jpmc26: on n'obtient une "énorme augmentation de complexité" que si les classes deviennent trop grandes et reçoivent trop de variables membres, le résultat n'est donc plus cohérent.
Doc Brown
4
Je pense que cette réponse ne tient pas compte de la difficulté à gérer un état (qui pourrait même être modifiable) qui est réparti dans de nombreuses classes. Lorsqu'une fonction dépend non seulement des arguments, mais également de la manière dont l'objet a été construit (ou même modifié au cours de sa durée de vie), il est plus difficile de comprendre son état actuel lorsque vous effectuez un appel particulier. Vous devez maintenant rechercher la construction d' un autre objet, juste pour comprendre ce que l'appel va faire. L'ajout de variables d'instance augmente activement la quantité d'état du programme, sauf si vous construisez l'objet et le jetez immédiatement.
jpmc26
3
@ jpmc26 Un des motifs que j'utilise régulièrement lors du refactoring est que le constructeur agit comme si on mettait un contexte, alors les arguments de méthode sont spécifiques à une action. L'objet n'a pas exactement d'état, car l'état qu'il détient ne change jamais, mais le fait de déplacer ces actions communes dans les méthodes de ce conteneur améliore considérablement la lisibilité là où il est utilisé (le contexte n'est défini qu'une seule fois, ce qui s'apparente aux gestionnaires de contexte de python), et réduit les duplications si plusieurs appels sont faits aux méthodes de l'objet.
Izkata
3
+1 Pour dire clairement que les variables membres ne sont pas des variables globales. Beaucoup de gens pensent qu'ils sont.
Tulains Córdova
34

Avoir beaucoup de paramètres est considéré comme indésirable, mais les transformer en champs ou en variables globales est bien pire car cela ne résout pas le problème réel mais introduit de nouveaux problèmes.

Avoir de nombreux paramètres n’est pas en soi le problème, mais c’est un symptôme que vous pourriez avoir un problème. Considérez cette méthode:

Graphics.PaintRectangle(left, top, length, height, red, green, blue, transparency);

Avoir 7 paramètres est un signe avant-coureur. Le problème sous-jacent est que ces paramètres ne sont pas indépendants mais appartiennent à des groupes. leftet topappartiennent ensemble en tant que Positionstructure, lengthet en heighttant que Sizestructure, et red, blueet en greentant que Colorstructure. Et peut Color- être que la transparence appartient à une Brushstructure? Peut Position- être et Sizeappartient-il dans une Rectanglestructure, auquel cas nous pouvons même envisager de la transformer en une Paintméthode sur l' Rectangleobjet à la place? Donc on peut se retrouver avec:

Rectangle.Paint(brush);

Mission accomplie! Mais l’important est que nous avons réellement amélioré la conception globale et que la réduction du nombre de paramètres en est une conséquence . Si nous réduisons simplement le nombre de paramètres sans aborder les problèmes sous-jacents, nous pourrions faire quelque chose comme ceci:

Graphics.left = something;
Graphics.top = something;
Graphics.length = something;
...etc
Graphics.PaintRectangle();

Ici, nous avons obtenu la même réduction du nombre de paramètres, mais nous avons en fait aggravé la conception .

Conclusion: pour tout conseil en matière de programmation et règles empiriques, il est vraiment important de comprendre le raisonnement sous-jacent.

JacquesB
la source
4
+1 belle réponse constructive, compréhensible et non théorique.
AnoE
1
Sans oublier, que diable est votre "carré" faisant à la fois une longueur et un attribut de hauteur. :)
Wildcard
1
+1 pour reconnaître que la troisième voie évidente impliquée par certaines réponses (c'est-à-dire de nombreuses assignations à une structure / un objet avant l'appel de fonction) n'est pas meilleure.
benxyzzy
@Wildcard: Merci, changez-le en "rectangle" pour éviter de confondre le problème!
JacquesB
7

est-il utile d'utiliser des variables globales pour réduire le nombre de paramètres des fonctions ou pas?

ne pas

J'ai lu les premiers chapitres de ce livre

Avez-vous lu le reste du livre?

Un global est juste un paramètre caché. Ils causent une douleur différente. Mais ça fait toujours mal. Arrêtez de penser aux moyens de contourner cette règle. Pensez à la façon de le suivre.

Qu'est-ce qu'un paramètre?

C'est des trucs. Dans une boîte bien étiquetée. Pourquoi est-ce important de savoir combien de boîtes vous avez lorsque vous pouvez y mettre ce que vous voulez?

C'est le coût d'expédition et de manutention.

Move(1, 2, 3, 4)

Dis-moi que tu peux lire ça. Allez, essaie.

Move(PointA, PointB)

C'est pourquoi.

Cette astuce s'appelle introduire un paramètre objet .

Et oui, c'est juste un truc si vous ne faites que compter les paramètres. Ce que vous devriez compter, ce sont des idées! Abstractions! A quel point me fais-tu penser à la fois? Rester simple.

Maintenant, c'est le même compte:

Move(xyx, y)

OW! C'est horrible! Qu'est-ce qui s'est mal passé ici?

Il ne suffit pas de limiter le nombre d'idées. Ils doivent être des idées claires. Qu'est-ce que c'est que le xyx?

Maintenant c'est encore faible. Quelle est la meilleure façon de penser à cela?

Les fonctions devraient être petites. Pas plus petit que ça.

Oncle Bob

Move(PointB)

Pourquoi faire en sorte que la fonction fasse plus que ce dont elle a réellement besoin? Le principe de responsabilité unique ne concerne pas que les cours. Sérieusement, cela vaut la peine de changer toute une architecture pour éviter qu'une fonction ne devienne un cauchemar surchargé de 10 paramètres parfois liés, dont certains ne peuvent pas être utilisés avec d'autres.

J'ai vu le code où le nombre le plus commun de lignes dans une fonction était 1. Sérieusement. Je ne dis pas que vous devez écrire de cette façon, mais sheesh, ne me dites pas qu'un monde est la SEULE façon de respecter cette règle. Arrêtez d'essayer de sortir de refactoriser cette fonction correctement. Vous savez que vous pouvez. Cela pourrait se décomposer en quelques fonctions. Il pourrait en fait se transformer en quelques objets. Enfer, vous pourriez même en casser une partie dans une application totalement différente.

Le livre ne vous dit pas de compter vos paramètres. Cela vous dit de faire attention à la douleur que vous causez. Tout ce qui résout le problème résout le problème. Sachez simplement que vous échangez simplement une douleur contre une autre.

confits_orange
la source
3
"Avez-vous lu le reste du livre?" Votre question reçoit une réponse dans les 8 premiers mots de mon message ...
OiciTrap
Je suis tout à fait d’accord. L’important est de décomposer le problème en petits morceaux. Les objets peuvent réellement aider à organiser ces pièces et à les regrouper. Ils permettent également de passer une seule unité conceptuelle en tant que paramètre plutôt qu’un ensemble de pièces non liées. Je deviens nerveux quand je vois une méthode avec plus de 3 paramètres. 5 est une indication que ma conception est tombée en ruine et qu'il me faut une autre série de modifications. Le meilleur moyen que j'ai trouvé de résoudre des problèmes de conception tels que le nombre de paramètres est simplement de reformuler les choses en unités plus petites et plus simples (classes / méthodes).
Bill K
2
Le ton de cette réponse pourrait être amélioré. Il se lit comme très abrupt et dur. Par exemple: "Dis-moi que tu peux lire ça. Vas-y, essaie." semble très agressif et pourrait être réécrit comme "Parmi les deux appels de fonction ci-dessus / ci-dessous, lequel est le plus facile à lire?" Vous devriez essayer de faire passer le message sans l'agression. Le PO essaie juste d'apprendre.
Kyle Un
N'oubliez pas que le PO essaie également de rester éveillé.
candied_orange
4

Je n'utiliserais jamais de variables globales pour réduire les paramètres. La raison en est que les fonctions globales peuvent être modifiées par n’importe quelle fonction / commande, ce qui rend l’entrée de la fonction peu fiable et sujette à des valeurs hors de ce que la fonction peut gérer. Et si la variable était modifiée pendant l'exécution de la fonction et que la moitié de la fonction avait des valeurs différentes de celles de l'autre moitié?

En revanche, le passage de paramètres limite la portée de la variable à sa propre fonction, de sorte que seule la fonction peut modifier un paramètre une fois qu'elle est appelée.

Si vous devez transmettre des variables globales au lieu d'un paramètre, il est préférable de redéfinir le code.

Juste mes deux cents.

Dimos
la source
"Je n'utiliserais jamais de variables globales pour réduire les paramètres" totalement d'accord. Cela crée un couplage inutile.
bytedev
2

Je suis avec Oncle Bob à ce sujet et je suis d'accord pour dire qu'il faut éviter plus de 3 paramètres (j'utilise très rarement plus de 3 paramètres dans une fonction). Avoir beaucoup de paramètres sur une seule fonction crée un problème de maintenance plus important et donne probablement à penser que votre fonction en fait trop / a trop de responsabilités.

Si vous utilisez plus de 3 dans une méthode dans un langage OO, vous devriez considérer que les paramètres ne sont pas liés les uns aux autres d'une manière ou d'une autre et que vous devriez donc plutôt passer un objet à la place.

De plus, si vous créez plus de fonctions (plus petites), vous remarquerez également que les fonctions ont tendance à avoir plus souvent 3 paramètres ou moins. La fonction / méthode d'extraction est votre amie :-).

N'utilisez pas de variables globales pour éviter d'avoir plus de paramètres! C'est échanger une mauvaise pratique contre une pire encore!

bytedev
la source
1

Une alternative valable à de nombreux paramètres de fonction consiste à introduire un objet paramètre . Ceci est utile si vous avez une méthode composée qui passe (presque) tous ses paramètres à un tas d'autres méthodes.

Dans les cas simples, il s’agit d’un simple DTO n’ayant que les anciens paramètres comme propriétés.

Timothy Truckle
la source
1

L'utilisation de variables globales semble toujours un moyen facile de coder (surtout dans un petit programme), mais cela rendra votre code difficile à étendre.

Oui, vous pouvez réduire le nombre de paramètres dans une fonction en utilisant un tableau pour lier les paramètres dans une entité.

function <functionname>(var1,var2,var3,var4.....var(n)){}

La fonction ci-dessus sera modifiée et remplacée par [using associative array] -

data=array(var1->var1,
           var2->var2
           var3->var3..
           .....
           ); // data is an associative array

function <functionname>(data)

Je suis d'accord avec la réponse de robert bristow-johnson : vous pouvez même utiliser une structure pour lier des données dans une seule entité.

Narender Parmar
la source
1

En prenant un exemple tiré de PHP 4, regardez la signature de la fonction pour mktime():

  • int mktime ([ int $hour = date("H") [, int $minute = date("i") [, int $second = date("s") [, int $month = date("n") [, int $day = date("j") [, int $year = date("Y") [, int $is_dst = -1 ]]]]]]] )

Ne trouvez-vous pas cela déroutant? La fonction s'appelle "make time" mais elle prend des paramètres de jour, mois et année ainsi que trois paramètres de temps. Est-il facile de se souvenir de l'ordre dans lequel ils vont? Et si tu vois mktime(1, 2, 3, 4, 5, 2246);? Pouvez-vous comprendre cela sans avoir à vous référer à autre chose? Est 2246interprété comme un temps de 24 heures "22:46"? Que signifient les autres paramètres? Ce serait mieux comme objet.

En passant à PHP 5, il y a maintenant un objet DateTime. Parmi ses méthodes sont deux appelés setDate()et setTime(). Leurs signatures sont les suivantes:

  • public DateTime setDate ( int $year , int $month , int $day )
  • public DateTime setTime ( int $hour , int $minute [, int $second = 0 ] )

Vous devez toujours vous rappeler que l'ordre des paramètres va du plus grand au plus petit, mais c'est une grande amélioration. Notez qu’aucune méthode unique ne vous permet de définir les six paramètres en même temps. Vous devez faire deux appels séparés pour le faire.

Ce dont parle Oncle Bob, c'est d'éviter d'avoir une structure plate. Les paramètres associés doivent être regroupés dans un objet. Si vous avez plus de trois paramètres, il est fort probable que vous ayez un pseudo-objet, ce qui vous donne la possibilité de créer un objet approprié pour une plus grande séparation. Bien que PHP ne dispose pas d' un séparé Dateet Timeclasse, vous pouvez considérer que DateTimecontient vraiment un Dateobjet et un Timeobjet.

Vous pourriez éventuellement avoir la structure suivante:

<?php
$my_date = new Date;
$my_date->setDay(5);
$my_date->setMonth(4);
$my_date->setYear(2246);

$my_time = new Time;
$my_time->setHour(1);
$my_time->setMinute(2);
$my_time->setSecond(3);

$my_date_time = new DateTime;
$my_date_time->setTime($my_time);
$my_date_time->setDate($my_date);
?>

Est-il obligatoire de définir deux ou trois paramètres à chaque fois? Si vous voulez changer l'heure ou le jour, il est maintenant facile de le faire. Oui, l'objet doit être validé pour s'assurer que chaque paramètre fonctionne avec les autres, mais c'était le cas avant.

La chose la plus importante est: est-ce plus facile à comprendre et donc à maintenir? Le bloc de code en bas est plus gros qu'une seule mktime()fonction, mais je dirais que c'est beaucoup plus facile à comprendre; même un non-programmeur n'aurait pas beaucoup de mal à comprendre ce qu'il fait. L’objectif n’est pas toujours un code plus court ou plus intelligent, mais un code plus facile à gérer.

Oh, et n'utilise pas de globals!

CJ Dennis
la source
1

Beaucoup de bonnes réponses ici mais la plupart ne répondent pas à la question. Pourquoi ces règles empiriques? Il s’agit de la portée, des dépendances et de la modélisation appropriée.

Les arguments globaux pour les arguments sont pires car il semble que vous ayez simplifié les choses tout en dissimulant la complexité. Vous ne le voyez plus dans le prototype, mais vous devez tout de même en prendre conscience (ce qui est difficile, car il n'est plus à votre disposition pour le voir) et il ne vous sera pas utile de comprendre la logique de la fonction. Soyez une autre logique cachée qui intervient derrière votre dos. Votre portée est allée partout et vous avez introduit une dépendance sur quoi que ce soit parce que tout peut maintenant jouer avec votre variable. Pas bon.

La principale chose à maintenir pour une fonction est que vous pouvez comprendre ce qu’elle fait en regardant le prototype et l’appel. Donc, le nom doit être clair et sans ambiguïté. Mais aussi, plus il y a d'arguments, plus il sera difficile de comprendre ce qu'il fait. Cela élargit la portée dans votre tête, trop de choses se passent, c'est pourquoi vous voulez limiter le nombre. Peu importe le type d'arguments à traiter, certains sont pires que d'autres. Un booléen optionnel supplémentaire qui permet un traitement insensible à la casse ne rend pas la fonction plus difficile à comprendre, vous ne voudriez donc pas en faire tout un plat. En note de bas de page, les enums font de meilleurs arguments que les booléens, car leur signification est évidente dans l'appel.

Le problème typique n’est pas que vous écriviez une nouvelle fonction avec une énorme quantité d’arguments, vous ne commencerez avec quelques-uns que lorsque vous ne réaliserez pas encore à quel point le problème que vous résolvez est complexe. Au fur et à mesure que votre programme évolue, les listes d'arguments ont tendance à s'allonger progressivement. Une fois qu'un modèle est défini dans votre esprit, vous souhaitez le conserver car il s'agit d'une référence sûre que vous connaissez. Mais, rétrospectivement, le modèle n’est peut-être pas si bon. Vous avez manqué une étape ou trop dans la logique et vous n'avez pas reconnu une entité ou deux. "OK ... je pourrais recommencer et passer un jour ou deux à refactoriser mon code ou ... je pourrais ajouter cet argument pour que je puisse enfin faire ce qu'il faut et en finir. Pour l'instant. Pour ce scénario Pour éliminer ce bogue de mon assiette afin que je puisse déplacer le pense-bête à fini. "

Plus vous utilisez souvent la deuxième solution, plus la maintenance sera coûteuse et plus le refactor deviendra difficile et peu attrayant.

Il n’existe pas de solution de plaque de chaudière permettant de réduire le nombre d’arguments dans une fonction existante. Le simple fait de les regrouper en composés ne facilite pas vraiment les choses, c'est simplement un autre moyen de supprimer la complexité sous le tapis. Faire les choses correctement implique de regarder à nouveau la pile d'appels et de reconnaître ce qui manque ou a été mal fait.

Martin Maat
la source
0

Plusieurs fois, j'ai constaté que le regroupement de nombreux paramètres envoyés ensemble améliorait les choses.

  • Cela vous oblige à donner un bon nom à cette agrupation de concepts utilisés ensemble. Si vous utilisez ces paramètres ensemble, il se peut qu'ils aient une relation (ou que vous ne deviez pas les utiliser ensemble).

  • Une fois avec l'objet, je trouve habituellement que certaines fonctionnalités peuvent être déplacées par rapport à cet objet apparemment stuypide. Il est généralement facile à tester et avec une grande cohésion et un faible couplage, ce qui rend la chose encore meilleure.

  • La prochaine fois que je devrai ajouter un nouveau paramètre, je pourrai l’inclure sans changer la signature de nombreuses méthodes.

Cela peut donc ne pas fonctionner 100% du temps, mais demandez-vous si cette liste de paramètres doit être groupée dans un objet. Et s'il vous plaît. N'utilisez pas de classes non typées comme Tuple pour éviter de créer l'objet. Vous utilisez une programmation orientée objet, cela ne vous gêne pas de créer plus d’objets si vous en avez besoin.

Borjab
la source
0

Avec tout le respect que je vous dois, je suis presque certain que vous avez complètement manqué le point d'avoir un petit nombre de paramètres dans une fonction.

L'idée est que le cerveau ne peut contenir qu'un maximum d'informations " actives" à la fois, et si vous avez n paramètres dans une fonction, vous avez n autres éléments "d'informations actives" qui doivent être dans votre cerveau pour pouvoir fonctionner facilement et avec précision. comprendre ce que fait le morceau de code (Steve McConnell, dans Code Complete (un livre bien meilleur, IMO), dit quelque chose de similaire à propos de 7 variables dans le corps d’une méthode: nous atteignons rarement cela, mais plus et vous perdez la garder tout droit dans la tête).

L’intérêt d’un petit nombre de variables est de pouvoir garder les exigences cognitives associées à l’utilisation de ce code afin que vous puissiez y travailler (ou le lire) plus efficacement. Une cause secondaire de ceci est que le code bien factorisé aura tendance à avoir de moins en moins de paramètres (par exemple, un code mal factorisé a tendance à grouper un tas de choses dans un fouillis).

En passant des objets au lieu de valeurs, vous gagnerez peut-être un niveau d'abstraction pour votre cerveau, car il doit maintenant comprendre que j'ai un contexte de recherche à utiliser, au lieu de penser aux 15 propriétés pouvant se trouver dans ce contexte de recherche.

En essayant d'utiliser des variables globales, vous êtes complètement allé dans la mauvaise direction. Maintenant, non seulement vous n’avez pas résolu le problème de trop de paramètres pour une fonction, vous l’avez pris et l’avez jeté dans un bien meilleur problème que vous devez maintenant garder à l’esprit!

Désormais, au lieu de travailler uniquement au niveau de la fonction, vous devez également prendre en compte la portée globale de votre projet (bâillement, quelle horreur! Je frémis ...). Vous n'avez même pas toutes les informations devant vous dans la fonction (merde, quel est ce nom de variable globale?) (J'espère que cela n'a pas été modifié par autre chose depuis que j'ai appelé cette fonction).

Les variables globales constituent l'une des pires choses à voir dans un projet (grand ou petit). Ils dénotent un handicap pour une bonne gestion de la portée, ce qui est une compétence extrêmement fondamentale pour la programmation. Ils. Sont. Mal.

En déplaçant des paramètres hors de votre fonction et en les plaçant dans des globales, vous vous êtes tiré dans le sol (ou la jambe, ou le visage). Et Dieu vous préserve jamais de décider que, hé, je peux réutiliser ce global pour autre chose… mon esprit tremble à la pensée.

L'idéal est de garder les choses faciles à gérer, et les variables globales ne le feront PAS. J'irais même jusqu'à dire que c'est l'une des pires choses que vous puissiez faire pour aller dans la direction opposée.

jleach
la source
-1

J'ai trouvé une approche très efficace (en JavaScript) pour minimiser les frictions entre interfaces: Utilisez une interface uniforme pour tous les modules , en particulier: les fonctions à un seul paramètre.

Lorsque vous avez besoin de plusieurs paramètres: Utilisez un seul objet / hachage ou tableau.

Ours avec moi, je promets que je ne vais pas traîner ...

Avant de dire «à quoi sert un paramètre param func?» Ou «Existe-t-il une différence entre 1 tableau et les fonctions multi-argument?»

Hé bien oui. C'est peut-être visuellement subtile, mais la différence est multiple - j'explore les nombreux avantages ici

Apparemment, certaines personnes pensent que 3 est le bon nombre d'arguments. Certains pensent que c'est 2. Eh bien, cela pose toujours la question "quel param va dans arg [0]?" Au lieu de choisir l'option qui contraint l'interface avec une déclaration plus rigide.

Je suppose que je préconise une position plus radicale: ne comptez pas sur des arguments de position. Je me sens juste que c'est fragile et conduit à des arguments sur la position de ces maudits arguments. Ignorez-le et continuez tout droit vers l'inévitable bagarre autour des noms de fonctions et de variables. 😉

Sérieusement, une fois que le nom a été réglé, nous espérons que vous obtiendrez le code suivant, qui est quelque peu auto-documenté, non sensible à la position, et permet de gérer les modifications de paramètres futures dans la fonction:

function sendMessage({toUser, fromUser, subject, body}) { }

// And call the method like so:
sendMessage({toUser: this.parentUser, fromUser: this.currentUser, subject: ‘Example Alert’})

Dan Levy
la source
6
Truquer des arguments nommés ne passe pas vraiment un seul argument.
JDługosz
Pourquoi est-ce "simulé" si j'ai atteint un objectif que je m'étais fixé? Je place une priorité plus élevée sur les arguments nommés. Comme les arguments positionnels ne sont pas évidents pour appeler du code, et avec le nombre de fonctions nommées, un développeur doit le mémoriser, il n'est donc pas utile de se rappeler quels paramètres sont où et où ils sont facultatifs. ... Finalement, vous voudrez ajouter un paramètre requis après les options, bonne chance pour documenter et améliorer ce château de cartes.
Dan Levy
2
Les paramètres nommés sont également une astuce d’apprentissage du renforcement - les humains attachent plus de sens aux collections de mots.
Dan Levy