Est-ce une bonne idée de coder des valeurs dans nos applications? Ou est-il toujours judicieux d'appeler ces types de valeurs de manière dynamique au cas où ils devraient changer?
programming-practices
Edward
la source
la source
pi
pourrait changer ...Réponses:
Oui, mais rend les choses évidentes .
Faire:
Ne pas:
la source
diameter = 2 * radius
oudiameter = RADIUS_TO_DIAMETER_FACTOR * radius
? Il existe effectivement des cas où un nombre magique pourrait être la meilleure solution.diameter = radius << 1
? Je suppose que cela pourrait aussi êtrediameter = radius << RADIUS_TO_DIAMETER_BITS_TO_SHIFT
.diameter = radius.toDiameter()
Ce que je trouve curieux à propos de cette séance de questions-réponses jusqu’à présent, c’est que personne n’a en fait tenté de définir clairement le "code dur" ou, plus important encore, les alternatives.
tl; dr: Oui, il est parfois une bonne idée de valeurs coder en dur, mais il n'y a pas de règle simple à quand ; cela dépend complètement du contexte.
La question se limite aux valeurs , ce qui, à mon sens, désigne les nombres magiques , mais la réponse à la question de savoir si elles sont ou non une bonne idée est relative à ce à quoi elles sont réellement utilisées!
Voici quelques exemples de valeurs "codées en dur":
Valeurs de configuration
Je grince des dents chaque fois que je vois des déclarations comme
command.Timeout = 600
. Pourquoi 600? Qui a décidé ça? Était-ce la fin du temps imparti avant, et quelqu'un a-t-il augmenté le délai d'attente au lieu de résoudre le problème de performances sous-jacent? Ou s'agit-il réellement d'une attente connue et documentée en matière de temps de traitement?Celles-ci ne doivent pas être des nombres ou des constantes magiques , elles doivent être externalisées dans un fichier de configuration ou une base de données quelque part avec un nom explicite, car leur valeur optimale est déterminée en grande partie ou entièrement par l'environnement dans lequel l'application est exécutée.
Formules mathématiques
Les formules ont généralement tendance à être plutôt statiques, de sorte que la nature des valeurs constantes à l'intérieur n'est pas vraiment importante. Le volume d'une pyramide est (1/3) b * h. Est-ce que nous nous soucions d'où vient le 1 ou le 3? Pas vraiment. Un intervenant précédent a fait remarquer à juste titre que c’était
diameter = radius * 2
probablement mieux quediameter = radius * RADIUS_TO_DIAMETER_CONVERSION_FACTOR
- mais c’est une fausse dichotomie.Ce que vous devriez faire pour ce type de scénario, c'est créer une fonction . Je n'ai pas besoin de savoir comment vous en êtes arrivé à la formule, mais j'ai toujours besoin de savoir à quoi elle sert . Si, au lieu des absurdités écrites ci-dessus, j'écris
volume = GetVolumeOfPyramid(base, height)
, tout devient alors tout à fait plus clair, et il est parfaitement correct d'avoir des nombres magiques dans la fonction (return base * height / 3
) car il est évident qu'ils font simplement partie de la formule.La clé ici est bien sûr d'avoir des fonctions courtes et simples . Cela ne fonctionne pas pour les fonctions avec 10 arguments et 30 lignes de calcul. Utilisez la composition de fonction ou les constantes dans ce cas.
Domaine / règles métier
Celui-ci est toujours la zone grise car elle dépend de la valeur exacte. La plupart du temps, ce sont ces nombres magiques particuliers qui peuvent être transformés en constantes, car cela rend le programme plus facile à comprendre sans compliquer la logique du programme. Considérez le test
if Age < 19
contreif Age < LegalDrinkingAge
; vous pouvez probablement comprendre ce qui se passe sans la constante, mais c'est plus facile avec le titre descriptif.Ceux-ci peuvent également devenir candidats à une abstraction de fonction, par exemple
function isLegalDrinkingAge(age) { return age >= 19 }
. La seule chose à faire est que, souvent, votre logique métier est beaucoup plus complexe et qu'il n'est peut-être pas logique de commencer à écrire des dizaines de fonctions comportant chacune 20 à 30 paramètres. S'il n'y a pas d'abstraction claire basée sur des objets et / ou des fonctions, le recours à des constantes est acceptable.La mise en garde est que, si vous travaillez pour le service des impôts, il devient vraiment très lourd et honnêtement inutile d’écrire
AttachForm(FORM_CODE_FOR_SINGLE_TAXPAYER_FILING_JOINTLY_FOR_DEPRECIATION_ON_ARMPIT_HAIR)
. Vous n'allez pas faire cela, vous allez le faire,AttachForm("B-46")
car chaque développeur qui a déjà travaillé ou travaillera ici saura que "B-46" est le code de formulaire pour un contribuable déposant blah blah blah - les codes de formulaire font partie du domaine lui-même, ils ne changent jamais, ils ne sont donc pas vraiment des nombres magiques.Vous devez donc utiliser les constantes avec parcimonie dans la logique métier; en gros, vous devez comprendre si ce "nombre magique" est réellement un nombre magique ou s'il s'agit d'un aspect bien connu du domaine. Si c'est un domaine, vous ne le codez pas à moins qu'il y ait une très bonne chance que cela change.
Codes d'erreur et indicateurs d'état
Celles-ci ne sont jamais acceptables pour le codage en dur, comme le dit tout pauvre bâtard qui a déjà été touché
Previous action failed due to error code 46
. Si votre langue le prend en charge, vous devriez utiliser un type d’énumération. Sinon, vous aurez généralement un fichier / module complet rempli de constantes spécifiant les valeurs valides pour un type d'erreur particulier.Ne me laisse jamais voir
return 42
dans un gestionnaire d'erreur, capiche? Pas d'excuses.J'ai probablement omis plusieurs scénarios, mais je pense que cela couvre la plupart d'entre eux.
Donc, oui, il est parfois acceptable de coder de manière stricte. Juste ne soyez pas paresseux à ce sujet; il devrait s'agir d'une décision consciente plutôt que d'un vieux code bâclé.
la source
L'attribution d'un identifiant à un numéro peut avoir différentes raisons.
Cela nous donne des critères pour coder en dur les littéraux. Ils doivent être immuables, faciles à dactylographier, apparaître à un endroit ou dans un seul contexte et avoir une signification reconnaissable. Il est inutile de définir 0 comme ARRAY_BEGINNING, par exemple, ou 1 comme ARRAY_INCREMENT.
la source
En complément d'autres réponses. Utilisez des constantes pour les chaînes lorsque cela est possible. Bien sûr, vous ne voulez pas avoir
mais vous devriez avoir
(en supposant que vous ayez toujours une requête pour laquelle vous voulez obtenir tous les résultats d'une table spécifique, toujours)
Autre que cela, utilisez des constantes pour tout nombre autre que 0 (généralement). Si vous avez besoin d’un masque binaire d’autorisation de 255, n’utilisez pas
utilisez plutôt
Bien sûr, avec les constantes, sachez quand utiliser les énumérateurs. Le cas ci-dessus conviendrait probablement bien dans un cas.
la source
typedef enum {init_state=0, parse_state=1, evaluation_state=2, ... }
Cela dépend de ce que vous considérez comme codage en dur. Si vous essayez d'éviter tout ce qui est codé en dur, vous vous retrouvez dans une zone de codage souple et vous créez un système que seul le créateur peut gérer (et c'est le code définitif ultime).
Beaucoup de choses sont codées en dur dans tout cadre raisonnable et elles fonctionnent. c'est-à-dire qu'il n'y a aucune raison technique pour laquelle je ne devrais pas être en mesure de changer le point d'entrée d'une application C # (Static void Main), mais un codage en dur qui ne crée aucun problème pour aucun utilisateur (à l'exception de la question occasionnelle SO )
La règle empirique que j’utilise est que tout ce qui peut et va changer, sans affecter l’état de tout le système, doit être confugurable.
Donc, IMHO, il est idiot de ne pas coder en dur des choses qui ne changent jamais (pi, constante gravitationnelle, constante dans une formule mathématique - pensez au volume d’une sphère).
En outre, il est idiot de ne pas coder en dur les éléments ou processus qui auront un impact sur votre système et qui nécessiteront une programmation dans tous les cas, c’est-à-dire qu’il est inutile de permettre à l’utilisateur d’ajouter des champs dynamiques à un formulaire. Entrez et écrivez un script qui fera en sorte que cette chose fonctionne. En outre, il est stupide (et je l’ai vu quelques fois dans des environnements d’entreprise) de créer un outil de configuration. Ainsi, rien n’est codé en dur. Pourtant, seuls les développeurs du service informatique peuvent l’utiliser, et il est légèrement plus facile à utiliser que faire dans Visual Studio.
Ainsi, le résultat final, si une chose doit être codée en dur est une fonction de deux variables:
la source
Je code uniquement les valeurs si les valeurs sont spécifiées dans la spécification (sur une version finale de la spécification), par exemple, la réponse HTTP OK sera toujours
200
(sauf si elle change dans le RFC), vous verrez donc (dans certains de mes codes ) des constantes comme:Sinon, je stocke les constantes dans le fichier de propriétés.
La raison pour laquelle j'ai spécifié des spécifications, est que la modification des constantes dans les spécifications nécessite une gestion des modifications, dans laquelle les parties prenantes examinent les modifications et les approuvent / désapprouvent. Cela n'arrive jamais du jour au lendemain et prend des mois / années pour une approbation. N'oubliez pas que de nombreux développeurs utilisent des spécifications (HTTP, par exemple). Cela signifie donc que des millions de systèmes doivent être détruits.
la source
la source
J'ai remarqué que chaque fois que vous pouvez extraire des données de votre code, cela améliore ce qui reste. Vous commencez à remarquer de nouvelles refactorisations et à améliorer des sections entières de votre code.
C'est juste une bonne idée de travailler à l'extraction de constantes, ne le considérez pas comme une règle stupide, considérez cela comme une opportunité de mieux coder.
Le plus gros avantage serait de pouvoir trouver des constantes similaires comme la seule différence entre les groupes de code - les résumer dans des tableaux m'a aidé à réduire certains fichiers de 90% de leur taille et à corriger quelques bugs de copier-coller entre-temps. .
Je n'ai pas encore vu un seul avantage à ne pas extraire de données.
la source
J'ai récemment codé une fonction MySQL pour calculer correctement la distance entre deux paires lat / long. Vous ne pouvez pas simplement faire Pythagore; les lignes de longitude se rapprochent au fur et à mesure que la latitude augmente vers les pôles, il y a donc un trig assez poilu impliqué. En fait, j’étais assez découragé de décider de coder en dur la valeur représentant le rayon de la Terre en miles.
J'ai fini par le faire, même si le fait est que les lignes lat / gauche sont beaucoup plus rapprochées sur, par exemple, la lune. Et ma fonction sous-représenterait considérablement les distances entre points sur Jupiter. Je me suis dit que les chances que le site Web que je construis aient un emplacement extraterrestre dans lequel on entre est assez mince.
la source
Cela dépend si votre langue est compilée. Si ce n'est pas compilé, ce n'est pas grave, il suffit de modifier le code source, même s'il sera légèrement délicat pour un non-programmeur.
Si vous programmez avec un langage compilé, ce n'est clairement pas une bonne idée, car si les variables changent, vous devez recompiler, ce qui est une grosse perte de temps si vous souhaitez ajuster cette variable.
Vous n'avez pas besoin de faire un curseur ou une interface pour modifier dynamiquement sa variable, mais le moins que vous puissiez faire est un fichier texte.
Par exemple, avec mon projet ogre, j'utilise toujours la classe ConfigFile pour charger une variable que j'ai écrite dans un fichier de configuration.
la source
Deux fois où les constantes sont (à mon avis du moins) OK:
Des constantes qui ne concernent rien d'autre; vous pouvez modifier ces constantes quand bon vous semble sans rien changer d'autre. Exemple: La largeur par défaut d'une colonne de la grille.
Constantes absolument immuables, précises et évidentes, telles que "nombre de jours par semaine".
days = weeks * 7
Le remplacement7
par une constanteDAYS_PER_WEEK
n'apporte pratiquement aucune valeur.la source
Je suis tout à fait d'accord avec Jonathan mais comme toutes les règles il y a des exceptions ...
"Nombre magique dans la spécification: Nombre magique dans le code"
Fondamentalement, tout code magique qui reste dans la spécification après des tentatives raisonnables pour obtenir un contexte descriptif doit être reflété en tant que tel dans le code. Si des nombres magiques restent dans le code, tout doit être mis en oeuvre pour les isoler et les lier clairement à leur point d'origine.
J'ai effectué quelques contrats d'interfaçage pour lesquels il est nécessaire de renseigner des messages avec des valeurs mappées à partir de la base de données. Dans la plupart des cas, la mise en correspondance est assez simple et correspondrait bien aux directives générales de Jonathan, mais j'ai rencontré des cas où la structure du message cible était tout simplement horrible. Plus de 80% des valeurs devant être transmises dans la structure étaient des constantes imposées par la spécification du système distant. Ceci, ajouté au fait que la structure du message était gigantesque, a obligé à remplir BEAUCOUP de telles constantes. Dans la plupart des cas, ils ne fournissaient pas de sens ni de raison, ils disaient simplement "mettre M ici" ou "mettre 4.10.53.10100.889450.4452 ici". Je n'ai pas non plus essayé de mettre un commentaire à côté d'eux car cela aurait rendu le code résultant illisible.
Cela dit, quand on y réfléchit ... il s’agit en gros de rendre cela évident ...
la source
Si vous codez en dur la valeur de la constante gravitationnelle de la Terre, personne ne s'en souciera. Si vous codez en dur l'adresse IP de votre serveur proxy, vous rencontrez des problèmes.
la source
Généralement non, mais je pense que cela vaut la peine de noter que vous aurez le plus de problèmes lorsque vous commencerez à dupliquer la valeur codée en dur. Si vous ne le dupliquez pas (par exemple, utilisez-le une seule fois dans l'implémentation d'une classe), le fait de ne pas utiliser de constante peut suffire.
la source