Pour éviter les nombres magiques, nous entendons souvent dire que nous devons donner à un littéral un nom significatif. Tel que:
//THIS CODE COMES FROM THE CLEAN CODE BOOK
for (int j = 0; j < 34; j++) {
s += (t[j] * 4) / 5;
}
-------------------- Change to --------------------
int realDaysPerIdealDay = 4;
const int WORK_DAYS_PER_WEEK = 5;
int sum = 0;
for (int j = 0; j < NUMBER_OF_TASKS; j++) {
int realTaskDays = taskEstimate[j] * realDaysPerIdealDay;
int realTaskWeeks = (realdays / WORK_DAYS_PER_WEEK);
sum += realTaskWeeks;
}
J'ai une méthode factice comme celle-ci:
Expliquez: je suppose que j'ai une liste de personnes à servir et par défaut, nous dépensons 5 $ pour acheter de la nourriture uniquement, mais lorsque nous avons plus d'une personne, nous devons acheter de l'eau et de la nourriture, nous devons dépenser plus d'argent, peut-être 6 $. Je vais changer mon code, veuillez vous concentrer sur le littéral 1 , ma question à ce sujet.
public int getMoneyByPersons(){
if(persons.size() == 1){
// TODO - return money for one person
} else {
// TODO - calculate and return money for people.
}
}
Quand j'ai demandé à mes amis de revoir mon code, l'un a dit que donner un nom à la valeur 1 donnerait un code plus propre, et l'autre a dit que nous n'avons pas besoin d'un nom constant ici parce que la valeur est significative en soi.
Donc, ma question est: Dois-je donner un nom à la valeur littérale 1? Quand une valeur est-elle un nombre magique et quand ne l'est-elle pas? Comment distinguer le contexte pour choisir la meilleure solution?
persons
vient-il et que décrit-il? Votre code n'a aucun commentaire, il est donc difficile de deviner ce qu'il fait.if(getErrorCode().equals(4095)) ...
Réponses:
Non. Dans cet exemple, 1 est parfaitement significatif.
Cependant, que se passe-t-il si persons.size () vaut zéro? Cela semble étrange qui
persons.getMoney()
fonctionne pour 0 et 2 mais pas pour 1.la source
Pourquoi un morceau de code contient-il cette valeur littérale particulière?
Si la valeur littérale a une signification qui ne ressort pas clairement du contexte, alors oui, il est utile de donner un nom à cette valeur via une constante ou une variable. Plus tard, lorsque le contexte d'origine est oublié, le code avec des noms de variable significatifs sera plus facile à gérer. N'oubliez pas que le public de votre code n'est pas principalement le compilateur (le compilateur fonctionnera avec plaisir avec du code horrible), mais les futurs responsables de ce code - qui apprécieront si le code s'explique un peu.
Dans votre premier exemple, le sens de littéraux tels que
34
,4
,5
ne ressort pas du contexte. Au lieu de cela, certaines de ces valeurs ont une signification particulière dans votre domaine problématique. Il était donc bon de leur donner des noms.Dans votre deuxième exemple, la signification du littéral
1
est très claire à partir du contexte. Introduire un nom n'est pas utile.En fait, l'introduction de noms pour des valeurs évidentes peut également être mauvaise car elle masque la valeur réelle.
Cela peut masquer les bogues si la valeur nommée est modifiée ou était incorrecte, surtout si la même variable est réutilisée dans des morceaux de code non liés.
Un morceau de code peut également fonctionner correctement pour une valeur spécifique, mais peut être incorrect dans le cas général. En introduisant une abstraction inutile, le code n'est plus évidemment correct.
Il n'y a pas de limite de taille sur les littéraux «évidents» car cela dépend totalement du contexte. Par exemple, le littéral
1024
peut être totalement évident dans le contexte du calcul de la taille du fichier, ou le littéral31
dans le contexte d'une fonction de hachage, ou le littéralpadding: 0.5em
dans le contexte d'une feuille de style CSS.la source
Il y a plusieurs problèmes avec ce morceau de code, qui, soit dit en passant, peut être raccourci comme ceci:
On ne sait pas pourquoi une personne est un cas spécial. Je suppose qu'il existe une règle commerciale spécifique qui dit qu'obtenir de l'argent d'une seule personne est radicalement différent de recevoir de l'argent de plusieurs personnes. Cependant, je dois aller voir à l'intérieur des deux
getMoneyIfHasOnePerson
etgetMoney
, en espérant comprendre pourquoi il y a des cas distincts.Le nom
getMoneyIfHasOnePerson
ne semble pas correct. D'après le nom, je m'attendrais à ce que la méthode vérifie s'il y a une seule personne et, si c'est le cas, obtienne de l'argent de sa part; sinon, ne faites rien. D'après votre code, ce n'est pas ce qui se passe (ou vous faites la condition deux fois).Y a-t-il une raison de retourner une collection
List<Money>
plutôt qu'une collection?Revenons à votre question, car il n'est pas clair pourquoi il existe un traitement spécial pour une personne, le chiffre un devrait être remplacé par une constante, sauf s'il existe un autre moyen de rendre les règles explicites. Ici, on n'est pas très différent de tout autre nombre magique. Vous pourriez avoir des règles commerciales indiquant que le traitement spécial s'applique à une, deux ou trois personnes, ou seulement à plus de douze personnes.
Vous faites tout ce qui rend votre code plus explicite.
Exemple 1
Imaginez le morceau de code suivant:
Le zéro est-il ici une valeur magique? Le code est assez clair: s'il n'y a pas d'éléments dans la séquence, ne la traitons pas et retournons une valeur spéciale. Mais ce code peut également être réécrit comme ceci:
Ici, pas plus constant, et le code est encore plus clair.
Exemple 2
Prenez un autre morceau de code:
Il ne faut pas trop de temps pour comprendre ce qu'il fait dans des langages tels que JavaScript qui n'ont pas de
round(value, precision)
surcharge.Maintenant, si vous voulez introduire une constante, comment l'appellerait-elle? Le terme le plus proche que vous pouvez obtenir est
Precision
. Donc:Améliore-t-elle la lisibilité? Ça pourrait être. Ici, la valeur d'une constante est plutôt limitée et vous pouvez vous demander si vous avez vraiment besoin d'effectuer le refactoring. La bonne chose ici est que maintenant, la précision n'est déclarée qu'une seule fois, donc si elle change, vous ne risquez pas de faire une erreur telle que:
changer la valeur dans un endroit et oublier de le faire dans l'autre.
Exemple 3
À partir de ces exemples, vous pouvez avoir l'impression que les nombres doivent être remplacés par des constantes dans tous les cas . Ce n'est pas vrai. Dans certaines situations, avoir une constante ne conduit pas à une amélioration du code.
Prenez le morceau de code suivant:
Si vous essayez de remplacer les zéros par une variable, la difficulté serait de trouver un nom significatif. Comment le nommeriez-vous?
ZeroPosition
?Base
?Default
? L'introduction d'une constante ici n'améliorerait en rien le code. Cela le rendrait légèrement plus long, et juste cela.De tels cas sont cependant rares. Donc, chaque fois que vous trouvez un numéro dans le code, faites l'effort d'essayer de trouver comment le code peut être refactorisé. Demandez-vous s'il y a une signification commerciale au nombre. Si oui, une constante est obligatoire. Si non, comment nommeriez-vous le numéro? Si vous trouvez un nom significatif, c'est parfait. Sinon, vous avez probablement trouvé un cas où la constante n'est pas nécessaire.
la source
Vous pouvez créer une fonction qui prend un seul paramètre et renvoie des temps quatre divisés par cinq qui offrent un alias propre dans ce qu'elle fait tout en utilisant le premier exemple.
Je propose juste ma propre stratégie habituelle mais peut-être que j'apprendrai aussi quelque chose.
Ce que je pense, c'est.
Désolé si je suis hors de la base mais je suis juste un développeur javascript. Je ne sais pas quelle composition j'ai justifié, je suppose que tout ne doit pas être dans un tableau ou une liste, mais .longueur aurait beaucoup de sens. Et le * 4 ferait la bonne constante puisque son origine est nébuleuse.
la source
Ce numéro 1, pourrait-il être un numéro différent? Pourrait-il être 2 ou 3, ou y a-t-il des raisons logiques pour lesquelles il doit être 1? S'il doit être égal à 1, alors utiliser 1 suffit. Sinon, vous pouvez définir une constante. N'appelez pas cette constante UN. (J'ai vu cela fait).
60 secondes en une minute - avez-vous besoin d'une constante? Eh bien, il est de 60 secondes, pas 50 ou 70. Et tout le monde le sait. Cela peut donc rester un certain nombre.
60 éléments imprimés par page - ce nombre aurait pu facilement être 59, 55 ou 70. En fait, si vous changez la taille de la police, elle pourrait devenir 55 ou 70. Donc, ici, une constante significative est plus demandée.
C'est aussi une question de clarté du sens. Si vous écrivez "minutes = secondes / 60", c'est clair. Si vous écrivez "x = y / 60", ce n'est pas clair. Il doit y avoir certains noms significatifs quelque part.
Il y a une règle absolue: il n'y a pas de règles absolues. Avec de la pratique, vous saurez quand utiliser des nombres et quand utiliser des constantes nommées. Ne le faites pas parce qu'un livre le dit - jusqu'à ce que vous compreniez pourquoi il dit cela.
la source
minutes*60
, parfois mêmehours*3600
quand j'en ai besoin sans déclarer de constantes supplémentaires. Pendant des jours, j'écrirais probablementd*24*3600
oud*24*60*60
parce que86400
c'est près du bord où quelqu'un ne reconnaîtra pas ce nombre magique d'un coup d'œil.J'ai vu une bonne quantité de code comme dans l'OP (modifié) dans les récupérations de bases de données. La requête renvoie une liste, mais les règles métier indiquent qu'il ne peut y avoir qu'un seul élément. Et puis, bien sûr, quelque chose a changé pour «juste ce cas» en une liste avec plus d'un élément. (Ouais, j'ai dit pas mal de fois. C'est presque comme s'ils ... nm)
Donc, plutôt que de créer une constante, je créerais (dans une méthode de code propre) une méthode pour donner un nom ou préciser ce que le conditionnel est censé détecter (et résumer comment il le détecte):
la source