Dans cet article de Alex Papadimoulis, vous pouvez voir cet extrait:
private void attachSupplementalDocuments()
{
if (stateCode == "AZ" || stateCode == "TX") {
//SR008-04X/I are always required in these states
attachDocument("SR008-04X");
attachDocument("SR008-04XI");
}
if (ledgerAmnt >= 500000) {
//Ledger of 500K or more requires AUTHLDG-1A
attachDocument("AUTHLDG-1A");
}
if (coInsuredCount >= 5 && orgStatusCode != "CORP") {
//Non-CORP orgs with 5 or more co-ins require AUTHCNS-1A
attachDocument("AUTHCNS-1A");
}
}
Je ne comprends vraiment pas cet article.
Je cite:
Si chaque constante de règles métier a été enregistrée dans un fichier de configuration, la vie serait beaucoup [plus ( sic )] difficile pour tout le monde en maintenant le logiciel: il y aurait beaucoup de fichiers de code qui a partagé un, gros fichier (ou, l'inverse, beaucoup de fichiers de configuration minuscules); le déploiement de modifications aux règles de gestion ne nécessite pas de nouveau code, mais une modification manuelle des fichiers de configuration; et le débogage est d'autant plus difficile.
Ceci est un argument contre le nombre entier constant "500000" dans un fichier de configuration, ou le "AUTHCNS-1A" et d'autres constantes de chaîne.
Comment cela peut-il être une mauvaise pratique?
Dans cet extrait, "500000" n'est pas un nombre. Ce n'est pas, par exemple, le même que:
int doubleMe(int a) { return a * 2;}
où 2 est un nombre qu'il n'est pas nécessaire d'extraire. Son utilisation est évidente, et il ne représente pas quelque chose qui peut être réutilisé plus tard.
Au contraire, "500000" n'est pas simplement un nombre. C'est une valeur significative, qui représente l'idée d'un point d'arrêt dans la fonctionnalité. Ce numéro peut être utilisé à plusieurs endroits, mais ce n'est pas le nombre que vous utilisez; c'est l'idée de limite / limite, en dessous de laquelle une règle s'applique et au-dessus de laquelle une autre.
Comment se réfère à partir d' un fichier de configuration, ou même #define
, const
ou quel que soit votre langue offre, y compris pire que sa valeur? Si, par la suite, le programme, ou un autre programmeur, requiert également cette limite, de sorte que le logiciel fasse un autre choix, vous êtes foutu (car lorsqu’il change, rien ne vous garantit qu’il va changer dans les deux fichiers). C'est clairement pire pour le débogage.
De plus, si demain, le gouvernement demande "À partir du 03/05/2050, vous devrez ajouter AUTHLDG-122B au lieu de AUTHLDG-1A", cette constante de chaîne n'est pas une constante de chaîne simple. C'est une idée qui représente une idée. c'est juste la valeur actuelle de cette idée (qui est "la chose que vous ajoutez si le livre est supérieur à 500k").
Laissez-moi clarifier. Je ne dis pas que l'article est faux; Je ne comprends tout simplement pas; peut-être que ce n'est pas trop bien expliqué (du moins pour ce que je pense).
Je comprends que remplacer chaque valeur littérale ou numérique de chaîne par une variable constante, definition ou de configuration n’est pas non seulement nécessaire, mais complique excessivement les choses, mais que cet exemple particulier ne semble pas appartenir à cette catégorie. Comment savez-vous que vous n'en aurez pas besoin plus tard? Ou quelqu'un d'autre d'ailleurs?
Réponses:
L'auteur met en garde contre l'abstraction prématurée.
La ligne
if (ledgerAmt > 500000)
ressemble au type de règle de gestion que vous êtes en droit de vous attendre pour les grands systèmes d’entreprise complexes dont les exigences sont incroyablement complexes, précises et bien documentées.Généralement, ces types d'exigences sont des cas exceptionnels / extrêmes plutôt qu'une logique utilement réutilisable. Ces exigences appartiennent généralement à et sont gérées par des analystes métier et des experts en la matière, plutôt que par des ingénieurs
(Notez que les analystes d'entreprise / experts métiers assument généralement la propriété des besoins lorsque les développeurs travaillant dans des domaines spécialisés ne possèdent pas une expertise suffisante du domaine; je m'attendrais quand même à une communication / coopération complète entre les développeurs et les experts du domaine à protéger. exigences ambiguës ou mal écrites.)
Lors de la maintenance de systèmes dont les exigences sont remplies de cas extrêmes et d'une logique très complexe, il n'existe généralement aucun moyen de résumer utilement cette logique ou de la rendre plus facile à gérer. les tentatives d'essayer de construire des abstractions peuvent facilement se retourner contre vous, entraînant non seulement une perte de temps, mais également un code moins gérable.
Ce type de code a tendance à être protégé par le fait que le code lui-même a probablement une correspondance individuelle avec les exigences; Par exemple, lorsqu'un développeur sait que le
500000
chiffre apparaît deux fois dans les conditions requises, ce développeur sait également qu'il apparaît deux fois dans le code.Examinez l'autre scénario (également probable) dans lequel
500000
figurent plusieurs endroits dans le document relatif aux exigences, mais les experts en la matière décident de ne modifier que l'un d'entre eux. si vous changez laconst
valeur, il se peut que quelqu'un qui modifie la valeur ne réalise pas qu'il500000
est utilisé pour signifier différentes choses - le développeur le modifie alors dans le seul et unique endroit où il le trouve dans le code, et finit par casser quelque chose n'a pas réalisé qu'ils avaient changé.Ce scénario se produit souvent dans des logiciels juridiques / financiers sur mesure (par exemple, une logique de cotation d’assurance) - les personnes qui rédigent de tels documents ne sont pas des ingénieurs et n’ont aucun problème pour copier / coller des morceaux entiers de la spécification, en modifiant quelques mots / chiffres, mais en laissant la plupart de la même chose.
Dans ces scénarios, la meilleure façon de traiter les exigences de copier-coller est d'écrire le code de copier-coller et de rendre ce code aussi similaire que possible aux exigences (y compris le codage en dur de toutes les données).
La réalité de telles exigences est qu’elles ne restent généralement pas longtemps copiées-collées et que les valeurs changent parfois de façon régulière, mais qu’elles ne le sont souvent pas simultanément. Tentez donc de rationaliser ou d’abstraire ces exigences ou de les simplifier. En fin de compte, ils créent plus de problèmes de maintenance que de traduire intégralement les exigences en code.
la source
Those requirements are typically owned and maintained by business analysts and subject matter experts, rather than by engineers
ce qui n'est pas toujours une bonne idée. Parfois, le fait de transformer ces exigences en code révélera des cas délicats où les exigences ne sont pas bien définies ou sont définies de manière à aller à l'encontre des intérêts de l'entreprise. Si les analystes métier et les développeurs peuvent coopérer pour atteindre un objectif commun, de nombreux problèmes peuvent être évités.L'article a un bon point. Comment peut-il être une mauvaise pratique d'extraire des constantes dans un fichier de configuration? Ce peut être une mauvaise pratique si cela complique inutilement le code. Avoir une valeur directement dans le code est beaucoup plus simple que de devoir la lire à partir d'un fichier de configuration, et le code tel qu'il est écrit est facile à suivre.
Oui, alors vous changez le code. Le but de l'article est qu'il n'est pas plus compliqué de changer de code que de changer un fichier de configuration.
L'approche décrite dans l'article n'échelle pas si vous obtenez une logique plus complexe, mais le fait est que vous devez faire appel à votre jugement, et parfois la solution la plus simple est tout simplement la meilleure.
C'est le but du principe YAGNI. Ne concevez pas pour un avenir inconnu qui pourrait s'avérer complètement différent, concevez pour le présent. Vous avez raison de dire que si la valeur 500000 est utilisée à plusieurs endroits du programme, elle doit bien entendu être extraite à une constante. Mais ce n'est pas le cas dans le code en question.
Le codage souple est vraiment une question de séparation des préoccupations . Vous pouvez modifier les informations de code logiciel dont vous savez qu'elles sont indépendantes de la logique applicative principale. Vous ne coderiez jamais une chaîne de connexion dans une base de données, car vous savez qu'elle peut changer indépendamment de la logique de l'application et vous devrez la différencier pour différents environnements. Dans une application Web, nous aimons séparer la logique métier des modèles html et des feuilles de style, car ils peuvent changer indépendamment et même être modifiés par différentes personnes.
Toutefois, dans l'exemple de code, les chaînes et les chiffres codés en dur font partie intégrante de la logique de l'application. Il est concevable qu'un fichier puisse changer de nom en raison d'un changement de politique indépendant de votre volonté, mais il est tout aussi concevable de devoir ajouter une nouvelle branche si vérifiant une condition différente. Extraire les noms de fichiers et les numéros brise réellement la cohésion dans ce cas.
la source
if
repose sur une variable différente! Si la variable dont vous avez besoin n'est pas accessible depuis la configuration, vous devez quand même modifier le logiciel.L'article parle ensuite de "Enterprise Rule Engine" qui sont probablement un meilleur exemple de ce contre quoi il s'oppose.
La logique est que vous pouvez généraliser au point où votre configuration devient si compliquée qu'elle contient son propre langage de programmation.
Par exemple, le code d'état pour le mappage de document dans l'exemple pourrait être déplacé vers un fichier de configuration. Mais vous devrez alors exprimer une relation complexe.
Peut-être que vous mettriez aussi le montant du grand livre?
Bientôt, vous découvrez que vous programmez dans un nouveau langage que vous avez inventé et que vous enregistrez ce code dans des fichiers de configuration dépourvus de contrôle de source ou de modification.
Il convient de noter que cet article date de 2007 lorsque ce genre de chose était une approche commune.
De nos jours, nous réglerions probablement le problème de l’ injection de dépendance . C'est-à-dire que vous auriez un "code dur"
que vous voudriez remplacer par un code dur ou plus configurable
lorsque la loi ou les exigences commerciales ont changé.
la source
if
énoncés pour donner des valeurs différentes pour chaque client? Cela ressemble à quelque chose qui devrait être dans un fichier de configuration. Être dans un type de fichier ou un autre, toutes choses étant égales par ailleurs, n’est pas une raison pour ne pas contrôler / suivre / sauvegarder le fichier. @ewan semble dire que ne peut pas être sauvegardé le fichier d'un DSL dans le cadre du projet pour une raison quelconque, quand même les actifs non-code comme des images et des fichiers audio et des documents certainement est .Et cela s'exprime en ayant (et je pourrais argumenter que même le commentaire est redondant):
Ceci ne fait que répéter ce que fait le code:
Notez que l'auteur suppose que la signification de 500000 est liée à cette règle; ce n'est pas une valeur qui est ou est susceptible d'être réutilisée ailleurs:
À mon avis, l’essentiel de l’article est que parfois un chiffre n’est qu’un chiffre: il n’a pas de signification supplémentaire, à part ce que dit le code et il n’est pas susceptible d’être utilisé ailleurs. Par conséquent, résumer maladroitement ce que le code fait (maintenant) dans un nom de variable juste pour éviter les valeurs codées en dur est au mieux une répétition inutile.
la source
LEDGER_AMOUNT_REQUIRING_AUTHLDG1A
, vous n'écririez plus le commentaire dans le code. Les programmeurs ne maintiennent pas bien les commentaires. Si le montant change jamais, laif
condition et le commentaire seront désynchronisés. Au contraire, la constanteLEDGER_AMOUNT_REQUIRING_AUTHLDG1A
ne se désynchronise jamais et explique son but sans le commentaire inutile.attachDocument("AUTHLDG-2B");
ligne ne pourra pas mettre à jour le nom de constante en même temps. Dans ce cas, je pense que le code est assez clair sans commentaire ni variable explicative. (Bien qu'il soit logique d'avoir une convention indiquant la section appropriée du document d'exigences commerciales via des commentaires de code. En vertu d'une telle convention, un commentaire de code qui serait approprié ici.)LEDGER_AMOUNT_REQUIRING_ADDITIONAL_DOCUMENTS
(ce que j'aurais probablement dû faire en premier lieu). J'ai aussi l'habitude de mettre les identifiants des besoins professionnels dans les messages de validation Git, pas dans le code source.attachIfNecessary()
méthode et une boucle sur chacun d'eux.Les autres réponses sont correctes et réfléchies. Mais voici ma réponse courte et douce.
Si les règles et les valeurs spéciales apparaissent à un endroit du code et ne changent pas au cours de l'exécution, codez en dur comme indiqué dans la question.
Si les règles ou les valeurs spéciales apparaissent à plusieurs endroits dans le code et ne changent pas pendant l'exécution, utilisez un code logiciel. Le codage souple d’une règle peut me permettre de définir une classe / méthode spécifique ou d’utiliser le modèle Builder . Pour les valeurs, le codage logiciel peut signifier la définition d’une constante ou d’une énumération unique pour la valeur à utiliser dans votre code.
Si les règles ou les valeurs spéciales peuvent changer au cours de l'exécution, vous devez les externaliser. Cela se fait généralement en mettant à jour des valeurs dans une base de données. Ou mettez à jour manuellement les valeurs en mémoire en saisissant des données par un utilisateur. Cela se fait également en stockant les valeurs dans un fichier texte (XML, JSON, texte brut, etc.) qui est analysé de manière répétée pour la modification de la date de modification du fichier.
la source
C'est le piège que nous tombons dans quand nous utilisons un problème de jouets et pose seulement Strawman solutions, quand nous essayons d'illustrer un vrai problème.
Dans l'exemple donné, le fait que les valeurs fournies soient codées en dur en tant que valeurs en ligne ou définies en tant que const ne fait aucune différence.
C'est le code environnant qui ferait de l'exemple une horreur de la maintenance et du codage. S'il n'y a pas de code environnant, l'extrait est très bien, au moins dans un environnement de refactoring constant. Dans un environnement où la refactorisation a tendance à ne pas se produire, les responsables de ce code sont déjà morts, pour des raisons qui vont bientôt devenir évidentes.
Vous voyez, s'il y a du code qui l'entoure, alors il se passe clairement de mauvaises choses.
La première mauvaise chose est que la valeur 50000 est utilisée pour une autre valeur quelque part, par exemple, le montant du registre sur lequel le taux d'imposition change dans certains États ... alors lorsque le changement se produit, le mainteneur n'a aucun moyen de savoir, lorsqu'il trouve ces deux occurrences de 50000 dans le code, qu’il s’agisse des mêmes 50k ou des 50ks totalement indépendants. Et devriez-vous également rechercher 49999 et 50001, au cas où quelqu'un les utiliserait aussi comme constantes? Ce n'est pas un appel à plonk ces variables dans un fichier de configuration d'un service séparé: mais le codage en dur en ligne est clairement aussi faux. Au lieu de cela, elles doivent être des constantes, définies et étendues dans la classe ou le fichier dans lequel elles sont utilisées. Si les deux instances de 50k utilisent la même constante, elles représentent probablement la même restriction législative; sinon, probablement pas; et de toute façon, ils auront un nom,
Les noms de fichiers sont passés à une fonction - attachDocument () - qui accepte les noms de fichiers de base sous forme de chaîne, sans chemin ni extension. Les noms de fichiers sont essentiellement des clés étrangères de certains systèmes de fichiers ou bases de données, ou de l'endroit où attachDocument () obtient les fichiers. Mais les chaînes ne vous disent rien à ce sujet - combien y a-t-il de fichiers? Quels types de fichiers sont-ils? Comment savoir, lors de l'ouverture sur un nouveau marché, si vous devez mettre à jour cette fonction? A quels types de chose peuvent-ils être attachés? Le responsable de la maintenance reste totalement dans le noir et ne dispose que d'une chaîne pouvant apparaître plusieurs fois dans le code et signifier différentes choses à chaque fois qu'il apparaît. Dans un endroit, "SR008-04X" est un code de triche. Dans un autre, c'est une commande pour commander quatre fusées de rappel SR008. Ici, c'est un nom de fichier? Sont-ils liés? Quelqu'un vient de changer cette fonction pour mentionner un autre fichier, "CLIENT". Puis, pauvre responsable, vous avez appris que le fichier "CLIENT" doit être renommé "CUSTOMER". Mais la chaîne "CLIENT" apparaît 937 fois dans le code ... où commencez-vous même la recherche?
Le problème, c'est que les valeurs sont toutes inhabituelles et peuvent être raisonnablement garanties uniques dans le code. Pas "1" ou "10" mais "50 000". Pas "client" ou "rapport" mais "SR008-04X".
L’ homme de paille est que le seul autre moyen de résoudre le problème des constantes opaques de manière impénétrable est de les insérer dans le fichier de configuration d’un service non associé.
Ensemble, vous pouvez utiliser ces deux erreurs pour prouver que tout argument est vrai.
la source
if (...) { attachDocument(...); }
.Il y a plusieurs problèmes dans ceci.
L'un des problèmes est de savoir si un moteur de règles doit être créé pour rendre toutes les règles facilement configurables en dehors du programme lui-même. La réponse dans des cas similaires à ceci est le plus souvent non. Les règles vont changer de manière étrange et difficile à prévoir, ce qui signifie que le moteur de règles doit être étendu chaque fois qu'il y a un changement.
Un autre problème est de savoir comment gérer ces règles et leurs modifications dans votre contrôle de version. La meilleure solution consiste à scinder les règles en une classe pour chaque règle.
Cela permet à chaque règle d’avoir sa propre validité, certaines règles changent chaque année, d’autres en fonction du moment où un permis a été donné ou une facture est émise. La règle elle-même contenant le contrôle pour quelle version elle doit s'appliquer.
De plus, comme la constante est privée, elle ne peut être utilisée à mauvais escient nulle part ailleurs dans le code.
Ensuite, ayez une liste de toutes les règles et appliquez la liste.
Un autre problème est de savoir comment gérer les constantes. 500000 peut sembler discret, mais un très grand soin doit être pris pour s’assurer qu’il est converti correctement. Si une arithmétique en virgule flottante est appliquée, elle peut être convertie en 500 000,00001 et une comparaison avec 500 000,00000 peut échouer. Ou pire encore, 500000 fonctionne toujours comme prévu, mais 565000 échoue lors de la conversion. Assurez-vous que la conversion est explicite et faite par vous et non par le compilateur. Cela se fait souvent en le convertissant en un certain BigInteger ou BigDecimal avant son utilisation.
la source
Bien que cela ne soit pas directement mentionné dans la question, je voudrais noter que l'important est de ne pas enterrer la logique métier dans le code.
Le code, comme l'exemple ci-dessus, qui code des exigences professionnelles spécifiées de manière externe doit réellement résider dans une partie distincte de l'arbre source, éventuellement nommée,
businesslogic
ou quelque chose de similaire, et il convient de veiller à ce qu'il ne code que les exigences professionnelles de manière simple, lisible et cohérente. aussi concis que possible, avec un minimum de passe-partout et des commentaires clairs et informatifs.Il ne doit pas être mélangé avec du code "infrastructure" qui implémente la fonctionnalité nécessaire pour exécuter la logique métier, telle que, par exemple, la mise en œuvre de la
attachDocument()
méthode dans l'exemple, ou par exemple l'interface utilisateur, la journalisation ou le code de base de données en général. Alors que l' un moyen de faire respecter cette séparation est de « code soft » toute la logique métier dans un fichier de configuration, ce qui est loin de la seule méthode (ou le meilleur).Ce code de logique métier doit également être écrit de manière suffisamment claire pour que, si vous le montriez à un expert du domaine métier sans compétences en codage, il soit en mesure de le comprendre. À tout le moins, si et lorsque les exigences commerciales changent, le code qui les code doit être suffisamment clair pour que même un nouveau programmeur n'ayant aucune connaissance préalable de la base de code puisse localiser, réviser et mettre à jour facilement la logique métier, en supposant que aucune nouvelle fonctionnalité n'est requise.
Idéalement, ce code serait également écrit dans un langage spécifique à un domaine pour imposer la séparation entre la logique métier et l'infrastructure sous-jacente, mais cela peut s'avérer inutilement compliqué pour une application interne de base. Cela dit, si vous vendez par exemple le logiciel à plusieurs clients qui ont chacun besoin de leurs propres règles de gestion, un langage de script spécifique à un domaine (par exemple, basé sur un bac à sable Lua ) peut s'avérer être la solution.
la source