Est-ce une violation du principe ouvert-fermé de mettre à jour une constante représentant une valeur réelle?

10

J'ai une classe qui calcule le revenu annuel net des travailleurs. Il a une constante représentant un pourcentage de taxe. Mais un jour, le taux d'imposition a changé, je dois donc corriger le code.

Le fait de fixer cette constante indique-t-il une violation du principe ouvert-fermé , car il postule qu'une classe doit être fermée à toute modification?

Analyse Paradisys
la source
10
Le logiciel change parce que le monde réel change. D'un autre côté, faire d'un pourcentage de taxe une constante n'est pas tant une violation du principe ouvert-fermé que c'est simplement une chose ignorante à faire. Le pourcentage de taxe est un élément modifiable évident qui doit être lié au moment de l'exécution.
Richard Chambers
4
Je suis complètement d'accord avec Richard. Si vous devez changer le code pour corriger cette "constante", OCP est le moindre de vos problèmes.
Robert Harvey
3
Ce qui constitue une violation d'OCP est hautement subjectif et le tout est quelque peu obsolète de toute façon (car l'héritage de l'implémentation n'est plus la meilleure pratique). Il s'agit d'une question typique où vous devez deviner ce que pense la personne qui pose la question.
Robert Bräutigam
2
@DocBrown: qu'est-ce qui constitue une "nouvelle exigence"? Vous me montrez du code, je peux signaler de nouvelles exigences qui nécessiteront certainement un changement de code, quelle que soit la façon dont vous le faites. Revenons donc à la question: si le développeur a interrogé l'expert métier à ce sujet, et qu'il n'y avait aucune attente que le taux d'imposition change plus d'une fois tous les deux ans, il est inutile de le rendre configurable ou injectable. Restez simple et préparez-vous à ce que vous savez . Et pour ces choses, bien sûr, rendez-les externes à la classe. Cela dépend donc .
Robert Bräutigam
1
@ RobertBräutigam: mon point est qu'il n'y a pas à mon humble avis "OCP conforme", il n'y a que "OCP conforme dans le contexte de certaines catégories d'exigences". Il peut certainement y avoir une certaine subjectivité à quelles catégories un composant doit être "conforme à l'OCP". Mais dans le cas décrit dans cette question, d'après ce que je comprends, une exigence changeante a déjà été identifiée, de sorte que cette "classe de calcul du revenu" n'obéit clairement pas à l'OCP dans le contexte de cette exigence spécifique.
Doc Brown

Réponses:

14

L'OCP peut être mieux compris en pensant aux classes ou aux composants fournis par un fournisseur A dans une sorte de bibliothèque de boîte noire, pour une utilisation par les utilisateurs B, C et D (notez que ce n'est qu'un modèle mental que j'utilise pour plus de clarté, peu importe si en réalité le seul utilisateur de la classe est A lui-même).

Si B, C et D peuvent utiliser ou réutiliser les classes fournies pour différents cas d'utilisation, sans avoir besoin de modifier le code source de la bibliothèque, alors le composant remplit l'OCP ( par rapport à une catégorie de cas d'utilisation ). Il existe différents moyens pour y parvenir, comme

  • rendre la classe héritable (généralement en conjonction avec le modèle de méthode de modèle ou le modèle de stratégie)

  • en fournissant des "points d'injection" pour l'injection de dépendance

  • en fournissant des paramètres de configuration pour la classe ou le composant (par exemple, en ayant un paramètre constructeur "pourcentage de taxe", comme dans votre cas, ou en utilisant un autre mécanisme de configuration)

  • peut-être d'autres moyens, selon le langage de programmation ou l'écosystème

Les exemples typiques que vous trouvez dans les manuels sont souvent du premier ou du deuxième type (je suppose que, aux yeux des auteurs de ces livres, le troisième type est trop trivial pour être mentionné).

Comme vous le voyez, cela n'a rien à voir avec l'interdiction de tout changement du code source par le fournisseur A (comme pour la correction de bogues, l'optimisation ou l'ajout de nouvelles fonctionnalités d'une manière rétrocompatible), ce qui est tout à fait indépendant de l'OCP. L'OCP concerne la façon dont A conçoit l'interface et la granularité des composants dans la bibliothèque, de sorte que différents scénarios de réutilisation (comme le réajustement avec différents taux de taxe) n'entraînent pas automatiquement des exigences de changement.

Donc malgré ce qu'on vous dit ici, la réponse est clairement "oui" , ce serait une violation de l'OCP.

EDIT: semble entre quelqu'un a écrit un article de blog détaillé sur exactement ce sujet. Bien que certaines parties auraient pu être mieux formulées (comme l'a souligné Derek Elkins), il semble que l'auteur partage généralement mon point de vue selon lequel "remplir l'OCP" n'est pas une propriété absolue, mais quelque chose qui ne peut être évalué que dans le contexte de certains catégories de modifications des exigences.

Doc Brown
la source
OK, donc OCP consiste à fournir un comportement extensible pour différents cas d'utilisation avec l'un des trois moyens que vous avez répertoriés, non? Mais que faire si l'exemple d'un PO implique que quelque chose de fondamental est sur le point de changer? Je ne sais pas de quel pays OP, mais dans mon pays le taux d'imposition est quelque chose qui ne change pas très souvent. C'était un mauvais exemple, mais peut-être qu'il a été intentionnellement extrait dans une constante, pour souligner le point. Je suis sûr que ce n'était pas censé être configurable ou extensible. Alors peut-être que la question portait sur «cela n'a rien à voir avec l'interdiction de toute modification du code source par le fournisseur A».
Vadim Samokhin
Au moins, je l'ai compris de cette façon. Le pauvre gars qui a supprimé sa réponse acceptée l'a fait soit je suppose. Vous l'avez vu sous un angle un peu différent - je comprends votre point et je suis d'accord avec lui. Mais il semble que le commentaire le plus sage ait été donné par @Robert Bräutigam. Jusqu'à présent, je n'avais pas réalisé que l'OCP est SI subjectif.
Vadim Samokhin
1
Je suppose que si jamais on me pose la même question, il y a une question que je devrais poser en réponse: "ce comportement est-il censé être étendu ou configuré d'une manière ou d'une autre?". Si oui - que la modification directe d'une classe elle-même est une violation de l'OCP. Si non, OCP n'est tout simplement pas applicable dans cette situation.
Vadim Samokhin,
1
@Zapadlo: Je pense que si un composant remplit l'OCP pour une classe d'exigences n'est pas très subjectif - il est assez clair dans la plupart des cas si une nouvelle exigence nécessite une modification du code source d'un composant, ou si le composant prend en charge cette exigence ". Les approches possibles pour l'implémenter ne se limitent pas aux 3 premiers moyens que j'ai énumérés, voir ma modification. Votre notion de subjectivité pourrait être causée parce que l'OCP a juste un nom trompeur et est assez mal expliqué dans de nombreux manuels.
Doc Brown
Ma notion de subjectivité est due au fait que je n'ai pas bien compris ce que vous avez dit - mais je le sais maintenant, je suppose. Merci beaucoup pour vos commentaires perspicaces et votre réponse.
Vadim Samokhin
4

Comme d'autres le disent, l'idéal serait que la classe de revenu des travailleurs permette le paramétrage de la constante, rendant cette classe indépendante de cette valeur.

En fin de compte, l'application appelante pourrait également permettre le paramétrage en termes de configuration externe (par exemple un fichier). Une fois que nous avons une configuration externe, nous pouvons changer le taux de taxe - mais considérez que si le fichier de configuration n'est lu qu'une seule fois au démarrage, l'application devra être redémarrée pour que les pourcentages de taxe mis à jour prennent effet, c'est donc quelque chose à conserver esprit. Nous pourrions fournir une fonctionnalité d'application pour relire la configuration lorsque cela est demandé, ou nous pourrions fournir un mécanisme plus compliqué qui remarque lorsque le fichier de configuration change ...

À long terme, vous constaterez peut-être que les problèmes fiscaux nécessitent plus qu'un simple pourcentage - par exemple, qu'un jour les lois fiscales seront plus complexes et nécessiteront plusieurs pourcentages et certaines constantes (par exemple, le montant inférieur à 10000 $ taxé à X%, tandis que le le reste est taxé à Y%).

Cela suggère essentiellement d'utiliser un modèle de stratégie, où la classe principale en question ici accepte un objet de stratégie pour calculer la taxe.

Les différentes stratégies (et les constantes% et s) doivent être choisies dans le fichier de configuration, et maintenant, l'ajout d'une nouvelle stratégie nécessite l'ajout de nouveau code, mais pas nécessairement des mises à jour du code existant.

Chaque stratégie peut savoir comment analyser / interpréter ses propres arguments de configuration externes, ainsi que la façon de calculer la taxe réelle.

Dynamiquement, la taxe peut en outre dépendre des paramètres régionaux en vigueur, vous pouvez donc avoir des paramètres régionaux associés aux revenus ou aux employés (ou les deux). Dans la configuration externe, nous pouvons associer les paramètres régionaux à la stratégie fiscale.


Voir également l' injection de dépendance , où nous gérons ces choses de manière explicite.

Erik Eidt
la source
1
La question n'était pas de savoir si c'est une mauvaise idée d'enterrer quelque chose comme un pourcentage de taxe dans le code, je suis sûr que cela est évident pour la plupart d'entre nous ici (y compris le PO). La question était, "est-ce que cela viole l'OCP?" Je ne vois donc pas comment votre réponse fait référence à cette question.
Doc Brown
1

Si vous devez modifier la classe pour changer la valeur de la taxe, sa conception viole en effet l'OCP. La conception appropriée, pour ce que vous avez décrit jusqu'à présent, est que la classe de calculatrice prenne la valeur de taxe comme paramètre.

Si votre classe est instanciée (ce qui signifie que ce n'est pas une classe statique), en créant la propriété de classe de variable fiscale, dont la valeur est injectée via le constructeur, vous amélioreriez également la cohésion de la classe.

En bref, votre conception actuelle fait dépendre votre classe d'une valeur constante qui n'est pas vraiment une constante (définissant la constante comme une valeur qui ne changerait jamais quoi qu'il arrive, comme la valeur de PI). Il viole l'OCP. Modifiez la conception pour recevoir la valeur de taxe comme argument constructeur.

Christopher Francisco
la source
0

Tout à fait d'accord avec @Becuzz, et je veux juste résumer ceci: OCP consiste à trouver des abstractions réutilisées (donc utiles) qui sont injectées dans une classe. Ainsi, le comportement de la classe est modifié non pas en changeant son code, mais en lui fournissant différentes implémentations. Ceci est parfaitement clair dans le livre de Robert Martin " Développement logiciel agile, principes, modèles et pratiques ", consultez le chapitre correspondant "Le principe ouvert-fermé", le sous-chapitre "L'abstraction est la clé". Il clarifie une autre idée fausse selon laquelle le comportement ne peut être modifié qu'avec l'héritage. C'est Bertrand Meyer qui a proposé cela en 1988 dans son livre « Object Oriented Software Construction », pas Robert Martin.

Vadim Samokhin
la source
-2

La façon dont je le vois n'est pas une violation du principe ouvert et fermé. Pourtant, le fait que quelque chose qui est appelé à changer dans le temps (comme le pourcentage de taxe) soit une constante est un défaut de conception: vous ne devez pas modifier la valeur de la constante mais la façon dont vous gérez le pourcentage de taxe. Cela devrait être un type de paramètre qui pourrait être modifié sans recompiler le tout.

Zalomon
la source
Le "défaut de conception" étant qu'il viole le principe d'ouverture et de fermeture car vous devez recompiler le code pour changer la constante?
Erdrik Ironrose