Ce qui est un nombre magique, et pourquoi est-il mauvais?

Qu'est-ce qu'un nombre magique?

Pourquoi faut-il l'éviter?

y a-t-il des cas où c'est approprié?

441
demandé sur Tiny Giant 2008-09-07 02:24:24
la source

15 ответов

un nombre magique est l'usage direct d'un nombre dans le code.

par exemple, si vous avez (en Java):

public class Foo {
    public void setPassword(String password) {
         // don't do this
         if (password.length() > 7) {
              throw new InvalidArgumentException("password");
         }
    }
}

ceci doit être remanié pour:

public class Foo {
    public static final int MAX_PASSWORD_SIZE = 7;

    public void setPassword(String password) {
         if (password.length() > MAX_PASSWORD_SIZE) {
              throw new InvalidArgumentException("password");
         }
    }
}

Il améliore la lisibilité du code, et il est plus facile à maintenir. Imaginez le cas où je mets la taille du champ Mot de passe dans l'interface graphique. Si j'utilise un nombre magique, chaque fois que la taille max change, je dois changer dans deux emplacements de code. Si j'oublie premièrement, cela conduira à des incohérences.

le JDK est rempli d'exemples comme dans Integer , Character et Math classes.

PS: outils D'analyse statique comme FindBugs et PMD détecte l'utilisation de nombres magiques dans votre code et suggère le remaniement.

499
répondu Marcio Aguiar 2017-09-04 19:06:10
la source

un Nombre Magique est une valeur codée en dur qui peut changer à un stade ultérieur, mais qui peut être difficile à mettre à jour.

Par exemple, disons que vous avez une Page qui affiche les 50 dernières Commandes "Vos Commandes" Page d'Aperçu. 50 est le nombre magique ici, parce que ce n'est pas fixé par la norme ou la convention, c'est un nombre que vous avez inventé pour les raisons décrites dans la spécification.

maintenant, ce que vous faites est vous avez les 50 dans des endroits différents - votre SQL script ( SELECT TOP 50 * FROM orders ), votre site web (Vos dernières 50 Commandes), votre login de commande ( for (i = 0; i < 50; i++) ) et peut-être beaucoup d'autres endroits.

maintenant, que se passe-t-il quand quelqu'un décide de changer 50 à 25? ou 75? ou 153? Vous devez maintenant remplacer les 50 dans tous les endroits, et vous êtes très susceptible de le manquer. Trouver / Remplacer peut ne pas fonctionner, parce que 50 peut être utilisé pour d'autres choses, et remplacer aveuglément 50 par 25 peut avoir d'autres mauvais effets secondaires (i.e. votre Session.Timeout = 50 appel, qui est également fixé à 25 et les utilisateurs commencent à signaler des temps morts trop fréquents).

aussi, le code peut être difficile à comprendre, i.e. " if a < 50 then bla " - si vous rencontrez que dans le milieu d'une fonction compliquée, d'autres développeurs qui ne sont pas familiers avec le code peuvent se demander "WTF is 50???"

C'est pourquoi il est préférable d'avoir des nombres aussi ambigus et arbitraires à exactement un endroit - " const int NumOrdersToDisplay = 50 ", parce que cela rend le code plus lisible (" if a < NumOrdersToDisplay ", il aussi signifie que vous ne devez le changer dans 1 bien définie.

les endroits où les nombres magiques sont appropriés sont tout ce qui est défini par une norme, c.-à-d. SmtpClient.DefaultPort = 25 ou TCPPacketSize = whatever (pas sûr si c'est normalisé). De plus, Tout ce qui est défini dans une seule fonction peut être acceptable, mais cela dépend du contexte.

135
répondu Michael Stum 2013-09-11 19:29:56
la source

avez-vous jeté un oeil à L'entrée Wikipédia pour numéro magique?

Il va dans un peu de détail, à propos de toutes les façons le nombre magique il est fait référence. Voici une citation sur le nombre magique comme une mauvaise pratique de programmation

le terme Nombre Magique se réfère également à la mauvaise pratique de programmation d'utiliser des nombres directement dans le code source sans explication. Dans la plupart des cas, cela rend les programmes plus difficiles à lisez, comprenez et maintenez. Bien que la plupart des guides fassent une exception pour les nombres zéro et un, c'est une bonne idée de définir tous les autres nombres dans le code comme des constantes nommées.

29
répondu somas1 2017-08-26 02:01:54
la source

Un nombre magique est une séquence de caractères au début d'un format de fichier ou un protocole d'échange. Ce numéro sert de contrôle de santé mentale.

exemple: Ouvrez n'importe quel fichier GIF, vous verrez au tout début: GIF89. "GIF89" étant le nombre magique.

D'autres programmes peuvent lire les premiers caractères d'un fichier et identifier correctement les fichiers GIF.

le danger est que les données binaires aléatoires peuvent contenir ces mêmes caractères. Mais il est très peu probable.

quant à l'échange de protocole, vous pouvez l'utiliser pour identifier rapidement que le 'message' actuel qui vous est transmis est corrompu ou non valide.

les nombres magiques sont encore utiles.

17
répondu Brian R. Bondy 2008-09-07 02:27:11
la source

Nombre Magique Vs. Constante symbolique: Quand remplacer?

magie: sémantique inconnue

constante symbolique - > fournit à la fois le contexte sémantique correct et le contexte correct pour l'utilisation

sémantique: le sens ou le but d'une chose.

"Créer une constante, le nom après le sens, et remplacez-le."--Martin Fowler

D'abord, les nombres magiques ne sont pas nombre. Toute valeur de base peut être "magique". Les valeurs de base sont des entités manifestes telles que des entiers, des réals, des doubles, des flotteurs, des dates, des chaînes, des booléens, des caractères, et ainsi de suite. La question n'est pas le type de données, mais l'aspect "magique" de la valeur telle qu'elle apparaît dans notre texte de code.

qu'entend-on par "magie"? Pour être précis: par "magie", nous avons l'intention de pointer vers la sémantique (signification ou but) de la valeur dans le contexte de notre code; qu'elle est inconnue, déroutant. C'est la notion de "magie". Une valeur de base n'est pas magique lorsque son sens sémantique ou son but-être-il est rapidement et facilement connu, clair, et compris (pas confus) du contexte surround sans mots d'aide spéciaux (par exemple constante symbolique).

par conséquent, nous identifions des nombres magiques en mesurant la capacité d'un lecteur de code à connaître, être clair, et comprendre le sens et le but d'une valeur de base à partir de son contexte environnant. Le moins connu, moins claire, et plus confus le lecteur est, plus "magique" la valeur de base est.

Définitions Utiles

  • confondre: la cause (quelqu'un) pour devenir désorienté ou perplexe.
  • déconcerté: cause (quelqu'un) à devenir perplexe et confus.
  • perplexe: complètement perplexe; très perplexe.
  • déconcerté: totalement déconcerté ou perplexe.
  • perplexe: incapable de comprendre; perplexe.
  • comprendre: percevoir la signification de la (des mots, une langue, ou haut-parleur).
  • Signification: ce que signifie un mot, un texte, un concept ou une action.
  • signifie: avoir l'intention de transmettre, d'indiquer ou de mentionner (une chose ou une notion particulière); signifier.
  • signifie: être une indication de.
  • indication: un signe ou un élément d'information qui indique quelque.
  • indiquer: point; spectacle.
  • signe: un objet, une qualité ou un événement dont la présence ou l'occurrence indique la présence ou l'occurrence probable d'une autre chose.

de base

nous avons deux scénarios pour nos valeurs magiques de base. Seul le second est d'une importance primordiale pour les programmeurs et le code:

  1. valeur de base isolée (par exemple Nombre) dont la signification est inconnue, inconnue, imprécise ou confuse.
  2. une valeur de base (par exemple un nombre) dans le contexte, mais sa signification reste inconnue, inconnue, imprécise ou confuse.

une dépendance générale de la "magie" est la façon dont la seule valeur de base (p. ex. le nombre) n'a pas de sémantique communément connue( comme Pi), mais a une sémantique localement connue (p. ex. votre programme), qui n'est pas entièrement claire dans le contexte ou qui pourrait être utilisée de façon abusive dans le bon ou le mauvais contexte(s).

la sémantique de la plupart des langages de programmation ne nous permettra pas d'utiliser des valeurs de base isolées, sauf (peut-être) sous forme de données (c'est-à-dire de tableaux de données). Lorsque nous rencontrons des "nombres magiques", nous faisons généralement dans un contexte. Par conséquent, la réponse à

" dois-je remplacer ce chiffre magique par une constante symbolique?"

est:

"Comment rapidement pouvez-vous évaluer et comprendre le sens sémantique du nombre (sa raison d'être, y) dans son contexte?"

sorte de magie, mais pas tout à fait

avec cette pensée à l'esprit, nous pouvons rapidement voir comment un nombre comme Pi (3.14159) n'est pas un" nombre magique " lorsqu'il est placé dans un contexte approprié (par exemple 2 x 3.14159 X rayon ou 2*Pi*r). Ici, le numéro 3.14159 est Pi mentalement reconnu sans l'Identificateur de la constante symbolique.

Cependant, nous remplaçons généralement 3.14159 par un identifiant symbolique constant comme Pi en raison de la longueur et de la complexité du nombre. Les aspects de la longueur et de la complexité de Pi (couplés avec un besoin de précision) signifie généralement l'identificateur symbolique ou constante est moins susceptible d'erreur. La reconnaissance de " Pi " comme un nom est simplement un bonus pratique, mais n'est pas la raison principale pour avoir la constante.

pendant ce temps: Retour au Ranch

pose mis à part les constantes communes comme Pi, concentrons-nous principalement sur les nombres avec des significations spéciales, mais que ces significations sont limitées à l'univers de notre système logiciel. Un tel nombre pourrait être "2" (comme une valeur entière de base).

si j'utilise le chiffre 2 seul, ma première question pourrait être: que signifie "2"? Le sens du mot "2" en lui-même est inconnu et impossible à comprendre sans contexte, ce qui rend son utilisation imprécise et confuse. Bien qu'ayant seulement "2" dans notre logiciel ne sera pas se produire en raison de la sémantique du langage, nous voulons voir que "2" par lui-même ne porte pas de sémantique particulière ou de but évident étant seul.

mettons notre seul" 2 "dans un contexte de: padding := 2 , où le contexte est un"GUI Container". Dans ce contexte, la signification de 2 (comme pixels ou autre unité graphique) nous offre un aperçu rapide de sa sémantique (signification et but). Nous pourrions nous arrêter ici et dire que 2 est correct dans ce contexte et il n'y a rien d'autre que nous devons savoir. Cependant, peut-être dans notre univers logiciel ce n'est pas toute l'histoire. Il y a plus, mais "padding = 2" comme contexte ne peut pas le révéler.

supposons de plus que 2 comme Pixel padding dans notre programme est de la variété" default_padding " dans tout notre système. Par conséquent, écrire l'instruction padding = 2 n'est pas suffisant. La notion de "défaut" n'est pas révélé. Ce n'est que lorsque j'écris: padding = default_padding comme contexte et puis ailleurs: default_padding = 2 que je réalise pleinement une signification meilleure et plus complète (sémantique et but) de 2 dans notre système.

l'exemple ci-dessus est assez bon parce que" 2 " en soi pourrait être n'importe quoi. Ce n'est que lorsque nous limitons la portée et le domaine de compréhension à "mon programme" où 2 est le default_padding dans les parties générales de "mon programme", que nous donnons finalement un sens à "2" dans son contexte approprié. Ici "2" est un nombre "magique", qui est factorisé à une constante symbolique default_padding dans le contexte de la ligne directrice de "mon programme" afin de l'utiliser comme default_padding compris rapidement dans le contexte plus large du code d'enclos.

ainsi, toute valeur de base, dont le sens (sémantique et objectif) ne peut pas être compris suffisamment et rapidement, est un bon candidat pour une constante symbolique à la place de la valeur de base (par exemple le nombre magique).

Aller Plus Loin

nombres sur une échelle pourrait avoir la sémantique aussi bien. Par exemple, prétendre que nous sommes faire un jeu D&D, où nous avons la notion d'un monstre. Notre objet monster a une fonctionnalité appelée life_force , qui est un entier. Les nombres ont des significations qui ne sont pas connues ou claires sans les mots pour fournir le sens. Ainsi, nous commençons par dire arbitrairement:

  • full_life_force: ENTIER = 10 -- Très vivant et indemne)
  • minimum_life_force: ENTIER = 1 -- à Peine vivant (très mal)
  • dead: INTEGER = 0 -- Dead
  • morts-vivants: entier = -1 -- Min morts-vivants (presque morts)
  • zombie: entier = -10 -- Max mort-vivant (très mort-vivant)

à partir des constantes symboliques ci-dessus, nous commençons à obtenir une image mentale de la vitalité, de la mort, et de la" undeadness " (et des ramifications ou conséquences possibles) pour nos monstres dans notre jeu D&D. Sans ces mots (constantes symboliques), il ne reste que les nombres allant de -10 .. 10 . Juste la gamme sans les mots nous laisse dans un endroit de confusion peut-être grande et potentiellement avec des erreurs dans notre jeu si différentes parties du jeu ont des dépendances sur ce que cette gamme de nombres signifie à diverses opérations comme attack_elves ou seek_magic_healing_potion .

par conséquent, lors de la recherche et en envisageant le remplacement des "nombres magiques" nous voulons poser des questions très précises sur les nombres dans le contexte de notre logiciel et même comment les nombres interagir sémantiquement avec chaque autre.

Conclusion

revoyons les questions que nous devrions poser:

vous pourriez avoir un numéro magique si ...

  1. la valeur de base peut-elle avoir un sens ou un but particulier dans votre univers de logiciels?
  2. est-ce que le sens ou l'objet particulier peut être Inconnu, Inconnu, imprécis ou confus, même dans son contexte?
  3. un bon de base valeur de l'être utilisé de manière inappropriée avec de mauvaises conséquences dans le mauvais contexte?
  4. une mauvaise valeur de base soit correctement utilisé avec de mauvaises conséquences dans le bon contexte?
  5. la valeur de base ont une sémantique ou le but des relations avec d'autres valeurs de base dans des contextes spécifiques?
  6. peut-il y avoir une valeur de base à plus d'un endroit dans notre code avec une sémantique différente dans chacun, de ce fait une source de confusion pour notre lecteur?

examinez les valeurs de base de la constante manifeste autonome dans votre texte de code. Posez chaque question lentement et avec soin sur chaque instance d'une telle valeur. Considérer la force de votre réponse. Souvent, la réponse n'est pas en noir et blanc, mais a des nuances de sens et de but mal compris, de vitesse d'apprentissage et de vitesse de compréhension. Il est également nécessaire de voir comment il se connecte à la machine logicielle qui l'entoure.

à la fin, la réponse au remplacement est répondre à la mesure (dans votre esprit) de la force ou de la faiblesse du lecteur de faire la connexion (par exemple"get it"). Plus vite ils comprennent le sens et le but, Moins vous avez de "magie".

CONCLUSION: remplacer les valeurs de base par des constantes symboliques seulement lorsque la magie est assez grande pour causer des bugs difficiles à détecter provenant de confusions.

17
répondu Larry 2015-10-25 16:59:17
la source

Dans la programmation, un "nombre magique" est une valeur qui devrait être donné un nom symbolique, mais était glissé dans le code comme un littéral, généralement en plus d'un endroit.

c'est mauvais pour la même raison SPOT (Single Point of Truth) est bon: si vous vouliez changer cette constante plus tard, vous auriez à chasser à travers votre code pour trouver chaque instance. Il est également mauvais parce qu'il pourrait ne pas être clair pour les autres programmeurs ce que ce nombre représente, d'où la "magie".

les gens prennent parfois l'élimination de Nombre Magique plus loin, en déplaçant ces constantes dans des fichiers séparés pour agir comme configuration. Ceci est parfois utile, mais peut aussi créer plus de complexité que cela ne vaut la peine.

10
répondu Nick Retallack 2008-09-07 10:30:14
la source

un problème qui n'a pas été mentionné avec l'utilisation de nombres magiques...

si vous avez beaucoup d'entre eux, les chances sont raisonnablement bonnes que vous avez deux buts que vous utilisez des nombres magiques pour, où les valeurs se trouvent être les mêmes.

et puis, assez sûr, vous devez changer la valeur... pour un seul but.

10
répondu 2008-12-13 03:12:27
la source

un nombre magique peut aussi être un nombre avec une sémantique spéciale et codée en dur. Par exemple, j'ai vu une fois un système où les ID d'enregistrement > 0 étaient traités normalement, 0 lui-même était "new record", -1 était "this is the root" et -99 était "this was created in the root". 0 et -99 obligerait le service Web à fournir une nouvelle carte D'identité.

ce qui est mauvais à propos de ceci est que vous réutilisez un espace (celui des entiers signés pour les identifiants d'enregistrement) pour des capacités spéciales. Peut-être que vous ne voudrez jamais créer un enregistrez avec ID 0, ou avec un ID négatif, mais même si ce N'est pas le cas, chaque personne qui regarde le code ou la base de données pourrait tomber sur ce point et être confus au début. Il va sans dire que ces valeurs n'étaient pas bien documentée.

sans doute, 22, 7, -12 et 620 comptent comme nombres magiques, aussi. ;- )

9
répondu Sören Kuklau 2008-09-07 11:23:23
la source

je suppose que c'est une réponse à mon réponse à votre question précédente. Dans la programmation, un nombre magique est une constante numérique intégrée qui apparaît sans explication. Si elle apparaît dans deux endroits distincts, elle peut conduire à des circonstances où une instance est changée et non une autre. Pour ces deux raisons, il est important d'isoler et de définir les constantes numériques en dehors des endroits où elles sont utilisées.

3
répondu Kyle Cronin 2017-05-23 14:47:13
la source

il est intéressant de noter que parfois, vous voulez des numéros" codés " non configurables dans votre code. Il existe un certain nombre de célèbres dont 0x5F3759DF qui est utilisé dans l'algorithme de racine carrée optimisé.

dans les rares cas où je trouve le besoin d'utiliser de tels nombres magiques, je les fixe comme const dans mon code, et documente pourquoi ils sont utilisés, comment ils fonctionnent, et d'où ils viennent.

3
répondu Rob Rolnick 2008-09-07 02:59:22
la source

j'ai toujours utilisé le terme" Nombre Magique " différemment, comme une valeur obscure stockée dans une structure de données qui peut être vérifiée comme une vérification rapide de validité. Par exemple, les fichiers gzip contiennent 0x1f8b08 comme leurs trois premiers octets, les fichiers de classe Java commencent avec 0xcafebabe, etc.

vous voyez souvent des nombres magiques imbriqués dans des formats de fichier, parce que les fichiers peuvent être envoyés de manière plutôt promiscueuse et perdre toutes les métadonnées sur la façon dont ils ont été créés. Mais les nombres magiques sont aussi parfois utilisé pour les structures de données en mémoire, comme les appels ioctl ().

une vérification rapide du nombre magique avant le traitement du fichier ou de la structure de données permet de signaler les erreurs tôt, plutôt que de schlep tout le chemin à travers le traitement potentiellement long afin d'annoncer que l'entrée était balderdash complète.

3
répondu DGentry 2008-09-07 06:46:27
la source

qu'en est-il de l'initialisation d'une variable en haut de la classe avec une valeur par défaut? Par exemple:

public class SomeClass {
    private int maxRows = 15000;
    ...
    // Inside another method
    for (int i = 0; i < maxRows; i++) {
        // Do something
    }

    public void setMaxRows(int maxRows) {
        this.maxRows = maxRows;
    }

    public int getMaxRows() {
        return this.maxRows;
    }

dans ce cas, 15000 est un nombre magique (selon CheckStyles). Pour moi, définir une valeur par défaut est acceptable. Je ne veux pas avoir à faire:

private static final int DEFAULT_MAX_ROWS = 15000;
private int maxRows = DEFAULT_MAX_ROWS;

est-ce que cela rend la lecture plus difficile? Je n'ai jamais pensé à ça jusqu'à ce que J'installe CheckStyles.

3
répondu Ascalonian 2009-10-12 17:34:13
la source

@eed3si9n: je dirais même que '1' est un nombre magique. :- )

un principe lié aux nombres magiques est que chaque fait traité par votre code doit être déclaré exactement une fois. Si vous utilisez des nombres magiques dans votre code (comme l'exemple de longueur de mot de passe que @marcio a donné, vous pouvez facilement finir par dupliquer ce fait, et quand votre compréhension de ce fait change, vous avez un problème de maintenance.

1
répondu Andrew 2008-09-07 03:07:04
la source

Qu'en est-il des variables de retour?

j'ai surtout trouver qu'il est difficile lors de la mise en œuvre de procédures stockées .

Imaginer la prochaine procédure stockée (mauvaise syntaxe, je sais, juste pour montrer un exemple):

int procGetIdCompanyByName(string companyName);

Il renvoie l'Id de la société, si elle existe dans un tableau particulier. Sinon, il retourne -1. En quelque sorte c'est un nombre magique. Certaines des recommandations que j'ai lues jusqu'à présent indiquent que Je vais vraiment devoir faire quelque chose de design comme ça:

int procGetIdCompanyByName(string companyName, bool existsCompany);

d'ailleurs, que doit-elle rapporter si l'entreprise n'existe pas? Ok: il définira existesCompany comme false , mais aussi retournera -1.

Antoher option est de faire deux fonctions distinctes:

bool procCompanyExists(string companyName);
int procGetIdCompanyByName(string companyName);

donc une condition préalable pour la deuxième procédure stockée est que la société existe.

Mais j'ai peur de la concurrence, parce que dans ce système, une société peut être créée par un autre utilisateur.

La ligne de fond est: que pensez-vous de l'utilisation de ce genre de "nombres magiques" qui sont relativement connus et sûrs pour dire que quelque chose est infructueuse ou que quelque chose n'existe pas?

1
répondu Oskytar 2015-04-19 01:15:34
la source

un autre avantage de l'extraction d'un nombre magique comme constante donne la possibilité de documenter clairement l'information commerciale.

public class Foo {
    /** 
     * Max age in year to get child rate for airline tickets
     * 
     * The value of the constant is {@value}
     */
    public static final int MAX_AGE_FOR_CHILD_RATE = 2;

    public void computeRate() {
         if (person.getAge() < MAX_AGE_FOR_CHILD_RATE) {
               applyChildRate();
         }
    }
}
0
répondu jguiraud 2015-06-10 00:38:37
la source

Autres questions sur language-agnostic magic-numbers