web-dev-qa-db-fra.com

Éliminer les nombres magiques: quand est-il temps de dire "non"?

Nous sommes tous conscients que les numéros magiques (valeurs codées dures) peuvent causer des ravages dans votre programme, en particulier lorsqu'il est temps de modifier une section de code qui n'a aucun commentaire, mais où dessinez-vous la ligne?

Par exemple, si vous avez une fonction qui calcule le nombre de secondes entre deux jours, remplacez-vous?

seconds = num_days * 24 * 60 * 60

avec

seconds = num_days * HOURS_PER_DAY * MINUTES_PER_HOUR * SECONDS_PER_MINUTE

À quel moment décidez-vous qu'il est complètement évident que la valeur codée dur signifie et la laisser seul?

36
oosterwal

Il y a deux raisons d'utiliser des constantes symboliques au lieu de littéraux numériques:

  1. Simplifier la maintenance si les numéros magiques changent. Cela ne s'applique pas à votre exemple. Il est extrêmement improbable que le nombre de secondes d'une heure, ou le nombre d'heures d'heure aura changé.

  2. Améliorer la réadapibilité. L'expression "24 * 60 * 60" est assez évidente pour presque tout le monde. "Secondes_per_day" est également, mais si vous recherchez un bogue, vous devrez peut-être aller vérifier que SECOND_PER_DAY a été défini correctement. Il y a de la valeur dans la brièveté.

Pour les nombres magiques qui apparaissent exactement une fois et sont indépendants du reste du programme, décidant de créer un symbole pour ce nombre constitue une question de goût. En cas de doute, allez-y et créez un symbole.

Ne faites pas cela:

public static final int THREE = 3;
40
kevin cline

L'un des meilleurs exemples que j'ai trouvés pour la promotion de l'utilisation de constantes pour une chose évidente comme HOURS_PER_DAY est:

Nous calculions combien de temps les choses étaient assises dans la file d'attente d'une personne. Les exigences étaient vaguement définies et le programmateur codé dur 24 Dans un certain nombre de places. Finalement, nous avons compris qu'il n'était pas juste de punir les utilisateurs de s'asseoir sur un problème pendant 24 heures lorsque le travail ne fonctionne vraiment que pendant 8 heures par jour. Lorsque la tâche est venue à résoudre ce problème et de voir ce que les autres rapports pourraient avoir le même problème, il était assez difficile de grep/la recherche à travers le code de 24 aurait été beaucoup plus facile de plus facilement au grep/recherche de HOURS_PER_DAY

7
bkulyk

Je dirais probablement "non" à des choses comme:

#define HTML_END_TAG "</html>"

Et définitivement dirait "non" à:

#define QUADRATIC_DISCRIMINANT_COEF 4
#define QUADRATIC_DENOMINATOR_COEF  2
7
dan04

Je pense que tant que le nombre est complètement constant et n'a aucune possibilité de changer, c'est parfaitement acceptable. Donc, dans votre cas, seconds = num_days * 24 * 60 * 60 va bien (en supposant bien sûr que vous ne faites pas quelque chose d'idiot comme faire ce type de calcul à l'intérieur d'une boucle) et sans doute mieux pour la lisibilité que seconds = num_days * HOURS_PER_DAY * MINUTES_PER_HOUR * SECONDS_PER_MINUTE.

C'est quand tu fais des choses comme ça c'est mauvais:

lineOffset += 24; // 24 lines to a page

Même si vous ne pouviez plus correspondre à des lignes sur la page ou même si vous n'avez aucune intention de changer, utilisez une variable constante, car un jour, il va revenir vous hanter. En fin de compte, le point est la lisibilité et ne sauve pas 2 cycles de calcul sur la CPU. Ce n'est plus 1978 lorsque des octets précieux ont été pressés pour toute leur valeur.

4
Neil
seconds = num_days * 24 * 60 * 60

Est parfaitement bien. Ce ne sont pas vraiment des nombres magiques car ils ne changeront jamais.

Tous les nombres pouvant raisonnablement changer ou n'ont aucune signification évidente devraient être mis en variables. Ce qui signifie à peu près tous.

3
Carra

Je voudrais éviter de créer des constantes (valeurs magiques) pour convertir une valeur d'une unité à d'autres. En cas de conversion, je préfère un nom de méthode de parole. Dans cet exemple, ce serait E.G. DayToSeconds(num_days) Internal La méthode n'a pas besoin de valeurs magiques car, le sens de "24" et "60" est clair.

Dans ce cas, je n'utiliserais jamais des secondes/minutes/heures. Je n'utiliserais que Timespan/DateTime.

3
KayS

Utilisez le contexte comme paramètre pour décider

Par exemple, vous avez une fonction appelée "Calculatesecondsbetween: Aday et: un jour", vous n'aurez pas besoin de faire beaucoup d'exaclanation sur ce que ces chiffres font, car le nom de la fonction est assez représentatif.

Et une autre question est, qui sont les possibilités de calculer de manière différente? Parfois, il y a beaucoup de façons de faire la même chose, afin de guider les futurs programmeurs et de leur montrer quelle méthode avez utilisée, définissant les constantes pourraient vous aider à comprendre.

1
guiman