Violation du principe DRY

10

Je suis sûr qu'il y a un nom pour cet anti-modèle quelque part; cependant je ne connais pas assez la littérature anti-modèle pour la connaître.

Considérez le scénario suivant:

or0est une fonction membre d'une classe. Pour le meilleur ou pour le pire, cela dépend fortement des variables des membres de la classe. Le programmeur A vient et a besoin de fonctionnalités comme or0mais plutôt que d'appeler or0, le programmeur A copie et renomme toute la classe. Je suppose qu'elle n'appelle pas or0parce que, comme je l'ai dit, cela dépend fortement des variables membres pour sa fonctionnalité. Ou peut-être qu'elle est programmeur junior et ne sait pas comment l'appeler à partir d'un autre code. Alors maintenant, nous avons or0et c0(c pour copie). Je ne peux pas blâmer complètement le programmeur A pour cette approche - nous respectons tous des délais serrés et nous piratons le code pour faire le travail.

Plusieurs programmeurs maintiennent or0donc c'est maintenant la version orN. c0est maintenant une version cN. Malheureusement, la plupart des programmeurs qui ont maintenu la classe contenant or0semblaient ignorer complètement c0- ce qui est l'un des arguments les plus forts auxquels je puisse penser pour la sagesse du principe DRY. Et il peut également y avoir eu une maintenance indépendante du code dans c. De toute façon, il semble que or0et c0ont été maintenus indépendants les uns des autres. Et, joie et bonheur, une erreur se produit cNqui ne se produit pas orN.

J'ai donc quelques questions:

1.) Y a-t-il un nom pour cet anti-modèle? J'ai vu cela se produire si souvent que j'aurais du mal à croire que ce n'est pas un anti-modèle nommé.

2.) Je peux voir quelques alternatives:

a.) Correction orNpour prendre un paramètre qui spécifie les valeurs de toutes les variables membres dont il a besoin. Modifiez ensuite cNpour appeler orNavec tous les paramètres nécessaires transmis.

b.) Essayez de porter manuellement les correctifs de orNà cN. (Attention, je ne veux pas faire ça mais c'est une possibilité réaliste.)

c.) Recopiez orNà - encore une cNfois, beurk mais je l'énumère par souci d'exhaustivité.

d.) Essayez de comprendre où cNest cassé puis réparez-le indépendamment de orN.

L'alternative a semble être la meilleure solution à long terme, mais je doute que le client me laisse la mettre en œuvre. Jamais de temps ou d'argent pour réparer les choses mais toujours du temps et de l'argent pour réparer le même problème 40 ou 50 fois, non?

Quelqu'un peut-il suggérer d'autres approches que je n'ai peut-être pas envisagées?

Onorio Catenacci
la source
"Y a-t-il un nom pour cet anti-modèle?" L'anti-motif «violant-sec»? :) À mon humble avis, vous y avez répondu vous-même.
Steven Jeuris
Peut-être l'appeler "The Dry Violator"?
FrustratedWithFormsDesigner
2
Je l'appelle: sec sec.
AJC
5
Copier et coller le codage?
tylermac
C'est ce qu'on appelle le modèle «trop de cuisiniers gâchent le bouillon».
Doc Brown

Réponses:

18
  1. c'est juste appelé du code en double - je ne connais plus de noms fantaisistes pour cela. Les conséquences à long terme sont, comme vous l'avez décrit, pires.

  2. Bien sûr, l'élimination de la duplication est l'option idéale si seulement possible. Cela peut prendre beaucoup de temps (dans un cas récent de notre projet hérité, j'avais plusieurs méthodes dupliquées dans plus de 20 sous-classes dans une hiérarchie de classes, dont beaucoup avaient évolutivement développé leurs propres différences / extensions au fil des ans. Cela a pris environ 1,5 an à travers des tests unitaires successifs et une refactorisation pour me débarrasser de toutes les duplications. La persévérance en valait la peine).

    Dans un tel cas, vous pouvez toujours avoir besoin d'une ou plusieurs des autres options en tant que correctifs temporaires, même si vous décidez de commencer à éliminer la duplication. Cependant, lequel de ceux-ci est le meilleur dépend de nombreux facteurs, et sans plus de contexte, nous ne faisons que deviner.

    De nombreuses petites améliorations peuvent faire une grande différence à long terme. Vous n'avez pas non plus nécessairement besoin de l'approbation explicite du client pour ces derniers - un petit refactoring à chaque fois que vous touchez ladite classe pour corriger un bogue ou implémenter une fonctionnalité peut aller très loin dans le temps. Incluez simplement du temps supplémentaire pour la refactorisation dans vos estimations de tâches. C'est comme la maintenance standard pour maintenir le logiciel en bonne santé à long terme.

Péter Török
la source
3
+1, si ce n'est pas seulement pour la mention de code en double, mais pour l'effort pur impliqué dans votre histoire de refactorisation de code. : D
Andreas Johansson
9

Il y a une référence au modèle WET (We Enjoy Typing) mais je ne sais pas s'il s'agit d'un nom standard.

... La licence logicielle est une exception notable à la pratique DRY (ne vous répétez pas) - le code de licence logicielle doit être aussi mouillé (nous aimons taper - le contraire de DRY) que possible.

Si vous isolez votre logique de licence en un seul endroit, séparé des autres préoccupations, vous simplifiez considérablement la modification de votre logiciel pour désactiver complètement la licence. Il est préférable de répéter la logique de licence plusieurs fois dans l'application, de préférence de telle sorte qu'elle soit exécutée plusieurs fois au cours d'une seule exécution du logiciel.

Par exemple, nous vous suggérons d'effectuer une vérification des licences lors de l'installation, au démarrage de l'application et chaque fois que des fonctionnalités importantes sont accessibles. Ne vérifiez pas la licence une fois au démarrage et ne transmettez pas cette valeur; au lieu de cela, répliquez le contrôle de licence dans chaque zone. C'est gênant, mais bien mieux que de sortir un produit facile à casser ...

Jeremy-George
la source
3
WET peut signifier: Ecrire tout deux fois
StuperUser
1
@StuperUser J'ai découvert cela sur le dailywtf hier ...
jeremy-george
3

Si je vous comprends bien, il se passe trop de choses en classe. Cela crée des méthodes qui ne suivent pas le principe de la responsabilité unique . Menant à du code qui doit être déplacé, des morceaux pris tandis que d'autres sont laissés de côté. Cela pourrait également créer beaucoup de membres.

Vous devez également consulter les modificateurs d'accessibilité. Assurez-vous que les choses qui sont publiques devraient en fait être publiques. Le consommateur n'a pas besoin de connaître chaque petit membre ... utilisez l'encapsulation.

Cela nécessite un refactor. Il semble également que le code soit écrit sans conception initiale. Regardez dans le développement piloté par les tests. Écrivez le code comme il doit être appelé plutôt que d'appeler du code, quelle que soit sa mise en œuvre. Regardez dans TDD pour quelques conseils sur la façon d'accomplir la tâche.

P.Brian.Mackey
la source
3

Si vous copiez du code, vous introduirez une dette technique de double maintenance ou plus précisément: la duplication de code .

Habituellement, cela est résolu par une refactorisation. Plus précisément, vous redirigez tous les appels vers une nouvelle fonction (ou une nouvelle méthode dans une nouvelle classe) qui a le code commun. La façon la plus simple de commencer est de supprimer tout le code copié et de voir ce qui se casse, dans lequel vous corrigez en redirigeant les appels vers le code commun.

Faire en sorte que votre client accepte de refactoriser le code peut être difficile car il est difficile de convaincre une personne non technique de régler une dette technique. Donc, la prochaine fois que vous donnerez des estimations de temps, incluez simplement le temps nécessaire pour refactoriser vos estimations . La plupart du temps, les clients supposent que vous nettoyez le code pendant que vous effectuez la correction.

Spoike
la source
1

Cela ressemble à du code de spaghetti pour moi. La meilleure solution est une refonte / réécriture.

un terme péjoratif pour le code source qui a une structure de contrôle complexe et enchevêtrée, en particulier celle qui utilise de nombreux GOTO, exceptions, threads ou autres constructions de branchement "non structurées". Il est nommé ainsi parce que le déroulement du programme est conceptuellement comme un bol de spaghetti, c'est-à-dire tordu et emmêlé ...

http://upload.wikimedia.org/wikipedia/commons/thumb/9/93/Spaghetti.jpg/175px-Spaghetti.jpg

Tom Squires
la source
-1 Refactor et réécriture sont deux options très différentes. La réécriture totale, la suppression de logiciels, n'est jamais une bonne idée. joelonsoftware.com/articles/fog0000000069.html
P.Brian.Mackey
1
Le code spaghetti est l'OMI un terme beaucoup plus général - et plus lâche -. Bien que ce code contienne souvent des duplications, vous pouvez avoir du code spaghetti sans aucune duplication, et aussi du code hautement dupliqué mais pas du code spaghetti.
Péter Török
@ P.Brian.Mackey Je n'ai jamais dit que Refactor et réécriture étaient la même chose. OP doit décider lequel utiliser.
Tom Squires,
2
Je n'ai jamais été fan de cet article. Je suis d'accord que la réécriture était une mauvaise idée dans l'exemple cité, mais ce n'est pas parce que c'était une mauvaise idée dans ce cas que c'est toujours une mauvaise idée. Pour commencer, la réécriture bloquera-t-elle tout autre progrès? Si c'est le cas, c'est mauvais; sinon, eh bien ce n'est pas aussi mauvais.
jhocking du
@jhocking - Je crois que le point de la politique de non-réécriture n'est pas celui de bloquer la progression dans d'autres programmes, mais plutôt la perte de correctifs réels au fil du temps. Ce «si (goldenNugget> 22)» magique, bien que mal nommé, résout toujours un problème spécifique qui pourrait bien être impossible à identifier sans des heures ou des jours de recherche. Maintenant, prendre ces mêmes données et les améliorer est ce qui devrait être fait à la place. C'est un refactor. Le jeter et dire "nous le ferons bien la prochaine fois" est une perte de temps. La même raison pour résoudre des problèmes déjà résolus est une perte de temps. Ajouter un bon code en plus d'une mauvaise dette augmente
P.Brian.Mackey
0

Vous dites que vous ne pouvez pas blâmer complètement A - mais copier une classe de cette façon est en fait impardonnable. C'est un échec massif dans votre processus de révision de code. C'est peut-être l'échec le plus massif, n'ayant aucune révision de code.

Si jamais vous pensez que vous devez produire un code affreux pour respecter une date limite, alors la demande de priorité absolue la plus élevée pour la publication devrait être de corriger le code affreux MAINTENANT. Votre problème a donc disparu.

Le principe DRY est destiné aux situations qui ne sont pas tout à fait parfaites et peuvent être améliorées. Dupliquer une classe est un tout nouveau calibre. Je l'appellerais d'abord «code dupliqué», et avec le temps, il deviendra le pire de tous les temps, «code dupliqué divergent»: plusieurs copies du même code qui sont presque, mais pas tout à fait identiques, et personne ne sait si les différences sont intentionnelles, coïncidences ou bugs.

gnasher729
la source
-3

Près d'une décennie de retard pour cette fête, mais le nom de cet anti-modèle est Divergent Change , où plusieurs classes incluent des copies du même comportement, mais à mesure que le temps et la maintenance progressent et que certaines classes sont oubliées, ces comportements divergent.

Selon le comportement partagé et la façon dont il est partagé, il pourrait plutôt être appelé Shotgun Surgery , la différence étant qu'ici, une seule caractéristique logique est fournie par de nombreuses classes plutôt qu'une seule.

doOOooonkeyKoooOOOooong
la source
1
Cela ne ressemble pas à la même chose. Le changement divergent est lorsque de nombreux changements sont apportés à la même classe. L'OP décrit la duplication de code. La chirurgie au fusil de chasse n'est pas la même chose non plus. Shotgun Surgery décrit le même changement apporté à plusieurs classes différentes.
Robert Harvey