Le code qui pue 2 – Trop de paramètres
Le deuxième article de la série sur les code smells traite d’un problème relativement fréquent, mais qui peut être difficile à résoudre et surtout à refactorer (refactoriser?). Pour ceuz qui avaient manqué le premier article, un code smells est une caractéristique plus ou moins commune du code qui indique pratiquement à tous coups un problème de conception sous-jacent.
Aujourd’hui, on traite du nombre de paramètres.
Quel est le nombre idéal de paramètres?
Un. Vous effectuez une seule opération sur un seul paramètre et retournez le résultat. Maximum deux, dans le cas où un paramètre serait nécessaire pour appliquer la seule opération sur le premier.
Mais Sylvain 😅 c’est impossible?!
Je te l’accorde. Mais avec un objectif comme ça, vous verrez plus rapidement les signes qu’un peu de refactoring est nécessaire.
En gros, le fait d’avoir un troisième paramètre devrait commencer à vous sonner des cloches. Rien n’est encore alarmant, car certains algorithmes peuvent nécessiter ce troisième argument. Par contre, c’est assez rare. Voici quelques symptômes communs.
Un membre de classe se cache dans les paramètres
Le principal symptôme serait de voir une méthode publique recevant un paramètre qui est ensuite passé à d’autres méthodes privées, ou qui serait aussi utilisé dans plus d’une méthode publique. Bref, lorsqu’un même paramètre revient plus d’une fois dans une même classe dans plusieurs méthodes, c’est souvent parce ce paramètre devrait être une propriété de la classe.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
class CodeSmell { void doSomething(int someQuantity) {} void doSomethingElse(int someQuantity) {} void wellYouGuessedIt(int someQuantity) {} public static void main(String[] args) { int someNumber = 10; CodeSmell cs = new CodeSmell(); cs.doSomething(someNumber); cs.doSomethingElse(someNumber); cs.wellYouGuessedIt(someNumber); } } |
Dans ce cas précis, on peut remarquer que someNumber semble être un chiffre qui définit une caractéristique de l’objet, mais sans y être encapsulé. La valeur est fournie à l’objet via les paramètres de son API à répétition, donc elle devrait probablement être un attribut de la classe. La technique d’encapsulation peut être utilisée pour faire le refactoring.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
class CodeSmell { private int someQuantity; CodeSmell(int someQuantity) { this.someQuantity = someQuantity; } void doSomething() {} void doSomethingElse() {} void wellYouGuessedIt() {} public static void main(String[] args) { int someNumber = 10; CodeSmell cs = new CodeSmell(someNumber); cs.doSomething(); cs.doSomethingElse(); cs.wellYouGuessedIt(); } } |
Un objet se cache dans les paramètres
Ça peut être un peu plus difficile à trouver parce que l’ordre dans lequel ils apparaissent peut différer, mais ils se retrouvent toujours ensembles dans plusieurs fonctions.
L’exemple de plus flagrant :
1 2 3 4 5 6 7 8 9 |
class CodeSmell { private int x; private int y; void setPosition(int x, int y) { this.x = x; this.y = y; } } |
On peut clairement voir dans l’exemple ci-dessus que x et y viennent toujours en paire et à plusieurs endroits dans le code. On peut simplement appliquer la technique d’introduction d’objet (dans le paramètre!), comme ceci :
1 2 3 4 5 6 7 8 9 10 11 12 |
class CodeSmell { private Position position; void setPosition(Position position) { this.position = position; } } class Position { int x; int y; } |
La fonction ne respecte pas le SRP
Le principe de responsabilité unique (Single Responsibility Principle ou SRP) est un principe de l’orienté-objet qui peut, lorsque brisé, entraîner une augmentation du nombre de paramètres. En effet, si deux algorithmes distincts se cachent dans une fonction, il faudra que les paramètres nécessaires leurs soient passés.
L’exemple est tiré par les cheveux, mais imaginez que les system.out.println() sont des algorithmes distincts :
1 2 3 4 5 6 7 8 9 10 |
class CodeSmell { void printInfo(String name, int quantity) { System.out.println(String.format("Name : %s", name)); System.out.println(String.format("Quantity : %d", quantity)); } public static void main(String[] args) { new CodeSmell().printInfo("Produit 1", 15); } } |
On peut utiliser une autre technique de refactoing appelée l’extraction de méthode :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
class CodeSmell { private void printQuantity(int quantity) { System.out.println(String.format("Quantity : %d", quantity)); } private void printName(String name) { System.out.println(String.format("Name : %s", name)); } public static void main(String[] args) { CodeSmell cs = new CodeSmell(); cs.printName("Produit 1"); cs.printQuantity(15); } } |
Ainsi, on diminue le nombre de paramètres et permet une meilleure réutilisation de l’algorithme puisqu’il est maintenant scindé en deux.
Aujourd’hui, vous avez appris un nouveau code smells avec ses symptômes les plus courants et quelques techniques pour les identifier et les retirer une bonne fois pour toute de votre code. Lorsqu’on développe, on ne pense pas nécessairement qu’un seul paramètre peut cacher un problème parce que les véritables symptômes arrivent beaucoup plus tard dans le développement. la plupart du temps, c’est à la veille de la mise en production…
À la prochaine! Merci de partager avec vos collègues 🙂
Commentaires
Laisser un commentaire