En tant que développeur de logiciels expérimenté, j'ai appris à éviter les chaînes magiques.
Mon problème est que cela fait si longtemps que je ne les ai pas utilisés, j'ai oublié la plupart des raisons. Par conséquent, j'ai du mal à expliquer pourquoi ils posent problème à mes collègues moins expérimentés.
Quelles sont les raisons objectives pour les éviter? Quels problèmes causent-ils?
Dans un langage qui compile, la valeur d'une chaîne magique est non vérifiée au moment de la compilation. Si la chaîne doit correspondre à un modèle particulier, vous devez exécuter le programme pour garantir qu'il correspond à ce modèle. Si vous avez utilisé quelque chose comme une énumération, la valeur est au moins valide au moment de la compilation, même si elle peut être incorrecte.
Si une chaîne magique est écrite à plusieurs endroits vous devez tous les changer sans aucune sécurité (comme une erreur de compilation). Cela peut être contré en le déclarant seulement en un seul endroit et en réutilisant la variable, cependant.
Les fautes de frappe peuvent devenir de graves bogues. Si vous avez une fonction:
func(string foo) {
if (foo == "bar") {
// do something
}
}
et quelqu'un tape accidentellement:
func("barr");
C'est pire, plus la chaîne est rare ou complexe, surtout si vous avez des programmeurs qui ne connaissent pas la langue maternelle du projet.
Les cordes magiques sont rarement auto-documentées. Si vous voyez une chaîne, cela ne vous dit rien de ce que la chaîne pourrait/devrait être d'autre. Vous devrez probablement examiner l'implémentation pour vous assurer d'avoir choisi la bonne chaîne.
Ce type d'implémentation est fuite, nécessitant une documentation externe ou un accès au code pour comprendre ce qui doit être écrit, d'autant plus qu'il doit être parfait (comme au point 3).
À court de fonctions de "recherche de chaîne" dans les IDE, il existe un petit nombre d'outils qui prennent en charge le modèle.
Vous pouvez utiliser par hasard la même chaîne magique à deux endroits, alors qu'en réalité ce sont des choses différentes, donc si vous avez fait un Find & Replace, et changé les deux, l'un d'eux pourrait se casser pendant que l'autre fonctionnerait.
Le sommet de ce que les autres réponses ont saisi n'est pas que les "valeurs magiques" sont mauvaises, mais qu'elles devraient être:
Ce qui distingue généralement les "constantes" acceptables des "valeurs magiques" est une violation d'une ou plusieurs de ces règles.
Bien utilisées, les constantes nous permettent simplement d'exprimer certains axiomes de notre code.
Ce qui m'amène à un dernier point, à savoir un usage excessif des constantes (et donc un nombre excessif d'hypothèses ou de contraintes exprimées en termes de valeurs), même s'il satisfait par ailleurs aux critères ci-dessus (mais surtout s'il s'en écarte), peut impliquer que la solution en cours de conception n'est pas suffisamment générale ou bien structurée (et donc nous ne parlons plus vraiment des avantages et des inconvénients des constantes, mais des avantages et inconvénients d'un code bien structuré).
Les langages de haut niveau ont des constructions de modèles dans les langages de bas niveau qui devraient utiliser des constantes. Les mêmes modèles peuvent également être utilisés dans le langage de niveau supérieur, mais ne devraient pas l'être.
Mais il peut s'agir d'un jugement d'expert basé sur une impression de toutes les circonstances et de ce à quoi devrait ressembler une solution, et la manière exacte dont ce jugement sera justifié dépendra fortement du contexte. En effet, cela peut ne pas être justifiable en termes de principe général, sauf pour affirmer "Je suis assez vieux pour avoir déjà vu ce genre de travail, que je connais, fait mieux"!
EDIT: ayant accepté une modification, rejeté une autre, et ayant maintenant effectué ma propre modification, puis-je maintenant considérer que le style de formatage et de ponctuation de ma liste de règles est réglé une fois pour toutes haha!
Exemple concret: je travaille avec un système tiers dans lequel des "entités" sont stockées avec des "champs". Fondamentalement, un système EAV . Comme il est assez facile d'ajouter un autre champ, vous pouvez y accéder en utilisant le nom du champ comme chaîne:
Field nameField = myEntity.GetField("ProductName");
(notez la chaîne magique "ProductName")
Cela peut entraîner plusieurs problèmes:
Ma solution a donc été de générer des constantes pour ces noms, organisées par type d'entité. Alors maintenant, je peux utiliser:
Field nameField = myEntity.GetField(Model.Product.ProductName);
Il s'agit toujours d'une constante de chaîne et se compile exactement au même binaire, mais présente plusieurs avantages:
Suivant sur ma liste: cacher ces constantes derrière les classes générées fortement typées - puis le type de données est également sécurisé.
Cordes magiques pas toujours mauvaises, donc cela pourrait être la raison pour laquelle vous ne pouvez pas trouver une raison générale de les éviter. (Par "chaîne magique", je suppose que vous entendez littéral chaîne dans le cadre d'une expression, et non défini comme une constante.)
Dans certains cas particuliers, les cordes magiques doivent être évitées:
Mais dans certains cas, les "cordes magiques" vont bien. Supposons que vous ayez un analyseur simple:
switch (token.Text) {
case "+":
return a + b;
case "-":
return a - b;
//etc.
}
Il n'y a vraiment pas de magie ici, et aucun des problèmes décrits ci-dessus ne s'applique. Il n'y aurait aucun avantage à mon humble avis à définir string Plus="+"
etc. Restez simple.
Pour ajouter aux réponses existantes:
Si le texte à afficher à l'écran est codé en dur et enfoui dans des couches de fonctions, vous aurez du mal à fournir des traductions de ce texte dans d'autres langues.
Certains environnements de développement (par exemple Qt) gèrent les traductions par recherche d'une chaîne de texte de la langue de base vers la langue traduite. Les cordes magiques peuvent généralement survivre à cela - jusqu'à ce que vous décidiez d'utiliser le même texte ailleurs et d'obtenir une faute de frappe. Même dans ce cas, il est très difficile de trouver les chaînes magiques à traduire lorsque vous souhaitez ajouter la prise en charge d'une autre langue.
Certains environnements de développement (par exemple MS Visual Studio) adoptent une autre approche et nécessitent que toutes les chaînes traduites soient conservées dans une base de données de ressources et relues pour les paramètres régionaux actuels par l'ID unique de cette chaîne. Dans ce cas, votre application avec des chaînes magiques ne peut tout simplement pas être traduite dans une autre langue sans retouche majeure. Un développement efficace nécessite que toutes les chaînes de texte soient entrées dans la base de données des ressources et reçoivent un ID unique lorsque le code est écrit pour la première fois, et i18n par la suite est relativement facile. Essayer de remblayer cela après coup nécessitera généralement un effort très important (et oui, j'y suis allé!) Il est donc beaucoup mieux de bien faire les choses en premier lieu.
Ce n'est pas une priorité pour tout le monde, mais si jamais vous voulez pouvoir calculer les mesures de couplage/cohésion sur votre code de manière automatisée, les chaînes magiques rendent cela presque impossible. Une chaîne à un endroit fera référence à une classe, une méthode ou une fonction à un autre endroit, et il n'existe aucun moyen simple et automatique de déterminer que la chaîne est couplée à la classe/méthode/fonction simplement en analysant le code. Seul le cadre sous-jacent (angulaire, par exemple) peut déterminer qu'il existe un lien - et il ne peut le faire qu'au moment de l'exécution. Pour obtenir vous-même les informations de couplage, votre analyseur doit tout savoir sur le framework que vous utilisez, au-delà du langage de base dans lequel vous codez.
Mais encore une fois, ce n'est pas quelque chose dont beaucoup de développeurs se soucient.