Qu'est-ce que le «codage souple», vraiment?

87

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, constou 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?

K. Gkinis
la source
21
Jouez au casse-tête: quel serait le bon nom pour ces chiffres? Je pense que vous constaterez que le nom n'ajoute aucune valeur, ou qu'il décrit tout ce que le code décrit déjà et souvent en ajoutant une ambiguïté ("LedgerLimitForAuthDlg1A"?). J'ai trouvé l'article brillant exactement à cause de la façon dont cela est pertinent. J'ai maintenu des systèmes qui utilisaient les deux approches, et je peux vous dire que les règles métier appartiennent au code - cela les rend beaucoup plus faciles à suivre, à maintenir et à comprendre. Lorsque vous utilisez la configuration, vous feriez mieux de la faire compter - elle est beaucoup plus chère.
Luaan
2
La configuration doit être réservée aux éléments à configurer. Si les règles de gestion ne sont généralement pas configurables, en mettre un peu dans la configuration ne vous rapporte rien.
biziclop
Pour les langues convenablement avancées, la configuration prend la forme de sous-programmes réels et non de chaînes.
Thorbjørn Ravn Andersen

Réponses:

100

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.

En quoi le fait de s'y référer depuis un fichier de configuration, ou même un #define, const ou tout ce que votre langue fournit, est-il pire que d'inclure 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.

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 500000chiffre 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 500000figurent 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 la constvaleur, il se peut que quelqu'un qui modifie la valeur ne réalise pas qu'il 500000est 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.

Ben Cottrell
la source
28
Un langage DSL (Domain Specific Language) peut être un bon moyen de rendre le code plus lisible, comme le document d’exigence.
Ian
13
Un autre avantage d'un DSL est qu'il est également plus difficile de mélanger accidentellement une logique d'application, de présentation ou de persistance avec les règles de gestion.
Erik Eidt
16
Penser que votre application est assez spéciale pour garantir sa propre DSL est généralement un orgueil.
brian_o
8
Those requirements are typically owned and maintained by business analysts and subject matter experts, rather than by engineersce 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.
Kasperd
4
@BenCottrell Je ne proposais pas de changer les règles pour faciliter l'écriture du logiciel. Mais lorsque vous avez beaucoup de conditions dans les règles, il est tout à fait possible que certaines interactions entre celles-ci aient été omises lors de la définition des règles. Mais lorsque vous transformez la spécification en code, le développeur est obligé de remarquer qu'il existe une interaction possible entre ces conditions. À ce stade, il est possible que le développeur trouve qu'une interprétation stricte de la spécification entraîne un prix non intentionnel qui permettrait aux clients de jouer avec le système.
Kasperd
44

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.

De plus, demain, le gouvernement dit "À partir du 03/05/2050, vous devez ajouter AUTHLDG-122B au lieu de AUTHLDG-1A".

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.

Comment savez-vous que vous n'en aurez pas besoin plus tard? Ou quelqu'un d'autre d'ailleurs?

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.

JacquesB
la source
4
Il est souvent beaucoup plus compliqué de changer de code qu'un fichier de configuration. Vous aurez peut-être besoin d'un développeur et d'un cycle de génération / système de génération pour le premier, tandis que le dernier ne nécessite que la modification d'un numéro dans une zone dans une interface de configuration conviviale.
OrangeDog
6
@OrangeDog Ouais, c'est à quoi ça ressemble au premier abord. Mais si vous faites ce genre de choses, l'interface de configuration sera tout sauf conviviale, avec des centaines de zones de texte totalement vides de sens vous demandant qui sait quoi. Et maintenant, vous devez construire l'interface utilisateur et la documenter. Notez que cela ne signifie pas que la configuration n'est jamais une bonne solution - il existe des cas dans lesquels c'est absolument le bon choix. Mais pas dans une des exemples dans l'article. Et quand une loi a-t-elle été modifiée pour la dernière fois? La dernière fois que les règles de TVA ont changé ici, nous avons quand même dû refaire tous les calculs.
Luaan
2
@ OrangeDog: Vous supposez, ici, que la configuration du logiciel vous fournit les points d'ancrage nécessaires au contrôle à effectuer. Notez comme dans le PO, chacun ifrepose 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.
Matthieu M.
2
@OrangeDog donc vous suggérez qu'il devrait y avoir des changements significatifs dans la logique d'une application logicielle, sans cycle dev / qa / release et des tests appropriés?
NPSF3000
3
@OrangeDog: OK, vous utilisez YAML pour configurer la logique dans l'exemple. Comme la logique inclut des règles conditionnelles, vous trouvez un moyen de représenter ces conditions en YAML. Félicitations, vous avez réinventé Python. Pourquoi ne pas écrire toute l'application en Python alors?
JacquesB
26

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.

<statecode id="AZ">
    <document id="SR008-04X"/>
    <document id="SR008-04XI"/>
</statecode>

Peut-être que vous mettriez aussi le montant du grand livre?

<statecode id="ALL">
    <document id="AUTHLDG-1A" rule="ledgerAmt >= 50000"/>
</statecode>

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"

InvoiceRules_America2007 : InvoiceRules

que vous voudriez remplacer par un code dur ou plus configurable

InvoiceRules_America2008 : InvoiceRules

lorsque la loi ou les exigences commerciales ont changé.

Ewan
la source
4
Peut-être devriez-vous définir "DI". Et peut-être expliquer un peu plus.
Basil Bourque
9
Pourquoi ce fichier ne serait-il pas dans le système de contrôle de source?
JDługosz
2
Si c'est spécifique au client, la version codée a-t-elle un énorme désordre d' 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 .
JDługosz
2
Vous devriez vraiment refactoriser la valeur "50000" de votre XML et la placer dans un fichier de configuration séparé, vous ne pensez pas? ... et c'est supposé être 500000, à propos.
Wildcard
1
@jdlugosz le concept d'un ERE est que vous achetez le système, puis le configurez pour vos besoins. peut-être parce que les développeurs internes étaient en concurrence avec ces systèmes «flexibles», ils essaieraient de les imiter. changement de contrôle de la configuration, même dans les systèmes de grandes entreprises comme IBM était souvent une réflexion après coup. Le point de vente était le changement rapide
Ewan
17

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 nombre 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.

Et cela s'exprime en ayant (et je pourrais argumenter que même le commentaire est redondant):

 if (ledgerAmnt >= 500000) {
    //Ledger of 500K or more requires AUTHLDG-1A
    attachDocument("AUTHLDG-1A");
  }

Ceci ne fait que répéter ce que fait le code:

LEDGER_AMOUNT_REQUIRING_AUTHLDG1A=500000
if (ledgerAmnt >= LEDGER_AMOUNT_REQUIRING_AUTHLDG1A) {
    //Ledger of 500K or more requires AUTHLDG-1A
    attachDocument("AUTHLDG-1A");
}

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:

Le seul et unique changement de règle que ce dernier code logiciel puisse éventuellement prendre en compte est un changement dans le montant du grand livre nécessitant un formulaire AUTHLDG-1A. Tout autre changement de règle de gestion nécessiterait encore plus de travail - configuration, documentation, code, etc.

À 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.

Thanos Tintinidis
la source
2
Si vous introduisiez la constante 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, la ifcondition et le commentaire seront désynchronisés. Au contraire, la constante LEDGER_AMOUNT_REQUIRING_AUTHLDG1Ane se désynchronise jamais et explique son but sans le commentaire inutile.
ZeroOne
2
@ ZeroOne: Sauf que si la règle commerciale devient "Un livre de 500 Ko ou plus nécessite AUTHLDG-1A et AUTHLDG-2B", il est très probable que la personne qui ajoute la 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.)
ruakh
@ruakh, OK, alors je refactoriserais la constante d'être appelée 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.
ZeroOne
1
@ ZeroOne: Mais pour AUTHLDG-3C, le montant du grand livre est en réalité un maximum . Et pour AUTHLDG-4D, le montant approprié du grand livre dépend de l'état. (Vous avez déjà compris le point? Pour ce type de code, vous souhaitez que votre code reflète les règles commerciales, et non une tentative d'abstraction des règles commerciales, car il n'y a aucune raison de s'attendre à ce que l'évolution des règles commerciales corresponde à la abstractions que vous avez adoptées.)
ruakh
2
Personnellement, je ne m'oppose pas à la saisie du nombre magique dans le code, je m'oppose à la structuration du code pour qu'il ait besoin de ces commentaires. Si c'était moi, je ferais de chaque document une instance enum avec sa propre attachIfNecessary()méthode et une boucle sur chacun d'eux.
David Moles
8

Les autres réponses sont correctes et réfléchies. Mais voici ma réponse courte et douce.

  Rule/value          |      At Runtime, rule/value…
  appears in code:    |   …Is fixed          …Changes
----------------------|------------------------------------
                      |                 |
  Once                |   Hard-code     |   Externalize
                      |                 |   (soft-code)
                      |                 |
                      |------------------------------------
                      |                 |
  More than once      |   Soft-code     |   Externalize
                      |   (internal)    |   (soft-code)
                      |                 |
                      |------------------------------------

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.

Basil Bourque
la source
1
J'aime votre réponse, mais je pense que vous devriez également vous demander si cela change lors de la mise en œuvre. Ceci est principalement pertinent s'il s'agit d'un produit qui sera utilisé dans de nombreuses organisations qui pourraient, par exemple, avoir des règles différentes selon qu'un superviseur doit approuver un remboursement via X, etc., etc.
Bloke Down The Pub
D'accord à la fois avec cette réponse et le commentaire sur la mise en œuvre. Les produits sur lesquels je travaille sont mis en œuvre par de nombreuses organisations, et beaucoup d'entre elles ont des valeurs subtiles différentes. Nous avons tendance à stocker ces "paramètres" dans une base de données plutôt que dans un fichier de configuration, mais le principe est que nous ne voulons pas créer de versions différentes de nos logiciels pour chaque entreprise qui les implémente (répétez ces différentes versions à chaque mise à niveau). .
RosieC
7

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.

Dewi Morgan
la source
2
Pas un problème de jouet, pas un homme de paille. C’est quelque chose que vous verrez tout le temps dans ce type d’applications d’entreprise. Il n'y a pas "d'ouverture sur un nouveau marché", il n'y a pas de réutilisation du même numéro (après tout, cela lui donnerait un autre sens de toute façon) et, en tout cas, l'article ne dit rien contre DRY - s'il y a deux dépendances à la valeur, il sera soit déplacé dans une méthode ou une constante. Montrer des exemples de la manière dont ces constantes (des paramètres de configuration, cela n'a pas d'importance) doivent être nommées, et où elles doivent être stockées de manière à être futures et plus claires que le code.
Luaan
4
L'exemple ne tombe pas en panne parce que c'est un problème de jouet. Le code environnant sera toujours horrible car les règles commerciales que le logiciel doit exécuter sont horribles . Les tentatives faites pour contourner ce défi fondamental avec des moteurs de règles et des DSL, entre autres choses, sont souvent de la procrastination pour les programmeurs , car résoudre les problèmes de CS est plus agréable que résoudre les subtilités des formulaires fiscaux. Les tentatives visant à atteindre «l'élégance» sont souvent des courses insensées, car la tâche ultime du logiciel est de modéliser un sinistre compliqué.
Whatsisname
Les règles de gestion peuvent être horribles, mais ce n'est pas en soi une excuse pour écrire ce genre de code de procédure médiocre. (J'ai tendance à être d'accord avec Papadimoulis sur le fait qu'il est plus facile de modéliser et de maintenir les règles dans le code que dans la configuration, je pense simplement que ce devrait être un meilleur code.) Le problème de DRY que je vois n'est pas les nombres magiques, c'est les répétitions if (...) { attachDocument(...); }.
David Moles
2

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.

Courbé
la source
2

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, businesslogicou 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.

Ilmari Karonen
la source
C'est exactement ce que je pensais !!! Lorsque la logique est profondément ancrée dans le code, comment un expert de domaine / sujet ou un utilisateur professionnel peut-il voir les valeurs et la logique utilisées afin de garantir leur exactitude et de diagnostiquer le comportement du système? Un fichier de configuration rend les paramètres visibles . Il doit y avoir un moyen de promouvoir la visibilité des règles métier - même si cela rend le codage "plus difficile". Je peux accepter une classe mince ou un ensemble de classes qui font le travail, sans combiner d'autres préoccupations - tant que l'utilisateur professionnel a les moyens d'y accéder et de les comprendre.
ErikE