Pourquoi le séchage est-il important?


81

Très simplement, pourquoi voudrais-je écrire un code qui fonctionne pour tous les cas et les données évolutives alors que tout ce que je dois faire est de répéter le même processus plusieurs fois avec quelques ajustements mineurs?

Je ne vais probablement pas avoir besoin de l'éditer à nouveau de si tôt.

Il semble y avoir beaucoup moins de travail à faire ...

function doStuff1(){/*.a.*/}
function doStuff2(){/*.b.*/}
function doStuff3(){/*.c.*/}

Et si j'ai besoin d'ajouter quelque chose ...

function doStuff4(){/*.d.*/}

Et si j'ai besoin de l'enlever, je l'enlève.

Il est plus difficile de comprendre comment transformer tous ces éléments en un modèle simple dans lequel je peux simplement introduire des données et traiter tous les cas, et effectuer un ensemble de changements que je ne pense pas avoir. faire.

Pourquoi être SEC quand il semble qu'une coupe rapide + pâte va être beaucoup moins de travail?


11
parce que le séchage est encore plus rapide lorsque vous le faites correctement, même si vous faites une erreur dans un fichier. cela affecte tous les autres
Daniel Little

97
"Il est peu probable que j'aie besoin de l'éditer à nouveau de si tôt" - vous pouvez l'espérer, mais vous vous trompez probablement. Et si vous travaillez à nouveau sur ce code, mais pas si tôt, cela ne fera qu'empirer les choses; vous oublierez où se trouvent les doublons, et les doublons deviendront des différences subtiles mais perfides. "Ecrivez comme si la personne qui va maintenir votre code est un maniaque dangereux qui sait où vous habitez", pour citer les classiques.
9000

14
Je pense que vous pouvez résumer: un point de changement unique est plus facile à maintenir.
Falcon

17
Si vous ne pouvez pas y répondre vous-même, vous devez acquérir une plus grande expérience réelle du développement et de la maintenance.
David Heffernan

15
@Wayne, j'ai ressenti une grande perturbation à la source, comme si des millions de programmeurs avaient soudain crié dans la terreur.
Incognito

Réponses:


121

Si vous vous répétez, vous pouvez créer des problèmes de maintenabilité. Si doStuff1-3 comporte tous du code structuré de la même manière et que vous corrigez un problème, vous pouvez facilement oublier de le résoudre ailleurs. De plus, si vous devez ajouter un nouveau cas à gérer, vous pouvez simplement passer différents paramètres dans une fonction plutôt que de les copier-coller partout.

Cependant, DRY est souvent poussé à l'extrême par des programmeurs intelligents. Parfois, pour ne pas vous répéter, vous devez créer des abstractions si obtuses que vos coéquipiers ne peuvent pas les suivre. Parfois, la structure de deux choses n’est que vaguement similaire mais suffisamment différente. Si doStuff1-4 est suffisamment différent pour ne pas vous répéter, vous devez écrire du code non naturel ou subir des réflexions de code astucieuses qui feront que votre équipe vous éblouira, alors vous pourrez peut-être vous répéter. Je me suis plié en quatre pour ne pas me répéter plusieurs fois de façon artificielle et j'ai regretté le produit final.

Je me trompe toujours du côté de DRY, dans les rares cas où je me répète quand je pense que les avantages de la lisibilité valent le risque que quelqu'un oublie de corriger un bogue à plusieurs endroits.

Compte tenu de ces conseils, cela ressemble à votre cas

répéter le même processus plusieurs fois avec quelques ajustements mineurs

Je travaillerais dur pour ne pas me répéter dans votre cas. En supposant des "modifications" minimes - elles peuvent être traitées avec différents paramètres qui ont un impact sur le comportement ou peut-être une dépendance injectée pour effectuer différentes tâches secondaires.

Pourquoi être SEC quand il semble qu'une coupe rapide + pâte va être beaucoup moins de travail?

Derniers mots célèbres. Vous regretterez de penser que, lorsqu'un ingénieur junior modifie / corrige / refacture un doStuff et ne réalise même pas que les autres existent. L'hilarité s'ensuit. Pas de brûlures d'estomac surtout. Chaque ligne de code coûte plus cher. Combien de chemins de code devez-vous tester avec autant de fonctions répétées? Si une fonction est utilisée, il vous suffit de tester un chemin principal avec quelques modifications comportementales. Si copié-collé, vous devez tester chaque doStuff séparément. Il y a de fortes chances que vous en manquiez un et qu'un client ait un bogue indésirable et que vous ayez peut-être des courriels indésirables dans votre boîte de réception.


2
Euh, juste pour être clair, je ne propose pas que le sec soit mauvais, cette question est plutôt celle des défenseurs des démons. Je cherche vraiment une réponse logique que je peux lier à des personnes qui pensent que couper / coller + modifier le code convient.
Incognito

2
Cela étant dit, votre réponse me plait le plus dans la mesure où elle couvre à la fois les défaillances de DRY: ne pas déranger et aller trop loin, tout en expliquant les impacts. - Pour ce qui est de sacrifier la lisibilité pour les bogues, je dirais que le code répétitif est moins lisible pour la même raison que vous, il est facile de perdre la trace de choses.
Incognito

16
Je soulignerais un écueil facile de DRY: un code similaire fusionné. Si vous avez deux cas d'utilisation fonctionnellement non liés mais dont le code est très similaire, il est facile de les fusionner, car DRY est bon . Malheureusement, quand on a besoin d'évoluer, on se retrouve souvent avec la tâche désagréable de devoir scinder la fonction à nouveau, puis de consulter tous les sites d'appels et de choisir soigneusement celui qui doit être appelé ici ... Exemple: typage structurel LLVM (tous les types similaires sont fusionnés en un seul), il est presque impossible de mapper l'IR au code d'origine.
Matthieu M.

1
Bingo Si deux ou plusieurs éléments de code doivent être modifiés et que les modifications seront toujours les mêmes pour tous les éléments, ils doivent alors être fusionnés. Toute pièce qui devra changer d'une manière différente des autres ne doit pas être fusionnée. Si le code ne changera jamais, peu importe qu'il soit fusionné ou non. La question de savoir si les modifications doivent être verrouillées ou détachées est beaucoup plus importante que la taille du code en question.
Supercat

1
@ MatthieuM c'est un exemple un peu injuste. LLVM applique le typage structurel en tant qu'optimisation . c'est-à-dire que les employés de LLVM ont décidé de payer le prix d'un RI difficile à comprendre pour les avantages en termes de performances. DRY est généralement un problème de maintenabilité mais dans ce cas, il s'agissait clairement d'une décision délibérée de réduire la maintenabilité.
Benjamin Hodgson

47

Parce que DRY sera moins de travail plus tard.


SEC: (ne te répète pas)

Une fonction prenant un argument.

def log(arg):
    print(arg)

C & P: (Copier et coller)

26 milliards de fonctions font essentiellement la même chose, mais avec une différence de 2 caractères.

def logA():
    print('a')

def logB():
    print('b')

...ad infinitum...

Pourquoi ne pas mettre à jour notre impression pour spécifier ce qu'est exactement l'impression?

SEC:

def log(arg):
    print(arg + "Printed from process foo")

Terminé.

C & P:

Vous devez revenir en arrière et changer chaque fonction .


Selon vous, lequel serait plus facile à déboguer?


10
En outre, vous devez écrire autant de suites de tests similaires que de fonctions dupliquées.
9000

Vous avez bien illustré le concept, mais dans la pratique, personne ne ferait ce que vous avez décrit avec des milliards de fonctions, pas de cette façon de toute façon.
Robert Harvey

@ Robert J'espère que non! J'ai choisi une tâche très simple pour essayer de mieux illustrer le concept et pourquoi il peut être une bonne chose.
John

11
@Robert - avez-vous lu l'un des articles sur thedailywtf.com ;) - Certains voudraient le faire
HorusKol

1
@ 9000 Pas si vous n'avez pas de suites de tests: p (ce qui pourrait même souvent être le cas dans certains projets ... malheureusement ...)
Sam

16

Parce que , appliqué à votre exemple:

  • + lisibilité

    Moins de code se traduit souvent par moins de bruit . (pas toujours...)

  • + flexibilité

    Si vous avez déjà eu à changer le comportement du doStuffX, vous voudrez vous tuer vous-même ou celui qui l’a écrit,

  • + extensibilité

    Si vous aviez extrait les parties distinctes dans une structure de données de votre choix et que vous l'avez simplement réitéré en appelant un générique doStuff, vous pouvez également ajouter une ligne dans votre structure de données où vous souhaitez une nouvelle entrée, ou en supprimer une, et changer le comportement signifiera simplement l'édition doStuff. Plus facile à maintenir .

  • + rentabilité

    moins de code signifie ici:

    • => moins de développement => coût réduit
    • => moins de probabilité de bugs => moins de temps de support => coût réduit
  • + optimisation gérée (possible)

    En fonction de la langue, le compilateur / interprète peut avoir une plus grande chance de déterminer que le générique doStuffeffectue toujours les opérations presque identiques, appel après appel, et de le mettre en ligne ou de tenter de l’ optimiser . Probablement pas pour X variations de doStuffX.

  • + tests et qualité

    Le test est plus facile: il doStufffaut tester, et c'est tout. Eh bien, pas exactement, mais cela couvre déjà plus . Seules ses attentes en matière d’OI varient et doivent être testées dans différentes conditions, mais il est toujours beaucoup plus facile à tester et plus facile à maintenir que toutes les variantes de doStuffX.

Globalement, cela représente un code plus facilement maintenable et une efficacité de développement améliorée pour votre équipe. Il s'agit de l' une des nombreuses pratiques recommandées pour vous aider à produire des logiciels plus robustes et fiables.


13

Puisque tout le monde a fait un excellent travail pour expliquer les problèmes de maintenabilité avec le code en double, je dirai simplement ceci:

Une grande partie de la programmation exige que vous pensiez à l'avenir, pas seulement au présent immédiat. Vous avez raison, le copier-coller est plus facile maintenant, mais la déclaration, il est peu probable que je doive la modifier de nouveau " montre que vous ne pensez pas correctement. Oui, vous pourriez gagner un peu de temps avec Un copier / coller rapide et sale, mais en faisant cela, vous montrez que vous ne pouvez pas regarder au-delà de votre problème immédiat et penser à demain. Êtes-vous sûr de ne jamais avoir besoin de revoir ce code? Savez-vous avec certitude Pouvez-vous garantir à 100% que vous n'aurez pas besoin de la revoir lorsque votre prochain ensemble de fonctionnalités devra être implémenté? Ce sont des problèmes pour demain, et doivent être pris en compte lors de la conception d'aujourd'hui.

Bien sûr, il y a des moments où copier / coller sera nécessaire. En tant que développeur d'interface utilisateur, j'ai constaté que je devais parfois enfreindre le principe DRY. C'est nul, je grince des dents chaque fois que cela se produit et, heureusement, c'est rare. Mais il ne se produit.

La différence est que lorsque vous violez DRY, vous devriez avoir une raison très convaincante de le faire, et la déclaration, il est plus difficile de trouver comment transformer tous ces éléments en un seul modèle ne fait pas partie de ceux-ci. À moins que vous ne manquiez de temps et que votre patron ne demande pas à avoir quelque chose dans les prochaines heures, sinon vous perdriez votre emploi, je ne pense pas que ce soit une justification valable.

Ne le prends pas mal: je n'essaie pas de te calomnier ni de te châtier, mais plutôt de faire en sorte que tu saches où ta mentalité est fausse. Les programmeurs investissent dans la paresse future; DRY est un moyen d'y parvenir. Le travail que vous faites aujourd'hui pour résoudre un problème de conception difficile sera rentable pour demain.


Je ne suis pas sûr d’être d’accord avec un patron qui vous dit que "faites-le ou vous êtes viré" est une excellente raison de violer DRY. La dette technique, quand avez-vous le temps de bien faire les choses, est-ce vraiment un gain de temps, etc.?
Incognito

1
@Incognito, j'essayais d'être un peu ironique :)
bedwyr

7

Je ne vais probablement pas avoir besoin de l'éditer à nouveau de si tôt.

Si c'est vraiment le cas, vous pourrez peut-être vous en tirer, mais le plus souvent, vous travaillerez sur du code qui doit être maintenu. Cela signifie étendre les fonctionnalités, corriger les bugs et d’autres améliorations. Si vous avez de petites variantes du même code dans 10 endroits différents et qu'un jour vous revenez à ce code et que vous deviez apporter une modification, vous devez maintenant effectuer le même changement dans 10 endroits différents (Désolé, il y a il y avait 11 places, vous en avez oublié une et maintenant vous avez un bug).

Si vous pouvez généraliser le problème que vous essayez de résoudre, vous pouvez rendre votre code plus facile à étendre et à corriger si des bogues apparaissent.


Bonne réponse, mais même si je pouvais m'en tirer, qu'en est-il de la pauvre sève qui parvient à la maintenir après moi? ;).
Incognito

Voir: "le plus souvent, vous allez travailler sur du code qui doit être maintenu" :)
Alex

Même dans ce cas, ce n'est le cas que si vous copiez et collez une perfection à 100% sans aucun bug. Et ce n'est pas, et arrêtez de penser que cela pourrait être.
Dan Ray

J'admettrai que j'ai copié et collé des choses dans le passé, mais jamais pour quoi que ce soit que j'allais garder plus d'une journée. Parfois, vous avez juste besoin d'un script à jeter rapide et sale.
Alex

6

Comme je l'ai indiqué dans la réponse à une autre question, mon approche est la suivante:

  1. La première fois que je résous un certain problème, je le fais juste.
  2. La deuxième fois (c’est-à-dire lorsque je résous un problème similaire), je pense: hm, je me répète peut-être, mais je vais faire un copier-coller rapide pour le moment.
  3. La troisième fois, je pense: hm, je me répète -> généralise!

C'est-à-dire jusqu'à 2, un autre principe (YAGNI) l'emporte sur DRY. Mais à partir de 3 (ou 4 si je suis vraiment paresseux!), Il semble que j'en ai besoin et je suis donc DRY.

Mise à jour

Quelques autres idées de mon expérience récente. J'ai dû adapter / intégrer deux composants A et B développés par une autre équipe dans notre produit. Premièrement: les deux composants A et B sont très similaires, donc j'étais déjà perturbé par le fait qu’ils avaient une architecture quelque peu différente. Deuxièmement: je devais les adapter pour pouvoir utiliser des sous-classes et ne remplacer que ce dont j'avais vraiment besoin.

J'ai donc commencé à refactoriser ces deux composants (chacun comprenant environ 8 classes C ++): je souhaitais avoir une architecture commune pour A et B, puis ajouter les fonctionnalités nécessaires en définissant des sous-classes. De cette façon, nos deux nouveaux composants A 'et B' auraient été dérivés des composants existants.

Après deux semaines de tentatives pour obtenir une structure commune et bien définie du code existant et après avoir dû expliquer au cours de nos réunions quotidiennes que je n'avais que peu progressé car le code d'origine était trop compliqué, j'ai parlé à mon patron. Nous avons constaté que nous n'aurions besoin de rien d'autre que de ces deux nouveaux composants A 'et B' (il n'y en aurait pas quatre ou six, seulement ces deux).

Ok, ainsi soit-il: j'ai fait une copie massive et renommé des classes de A et B et j'ai commencé à adapter la copie du code. Je l'ai fait fonctionner dans deux semaines de plus (toujours en train de réparer des bogues maintenant).

Avantages: Nous avons la fonctionnalité presque terminée maintenant et lorsque nous avons corrigé tous les bugs que nous avons finis. Nous avons enregistré toutes les modifications et les tests de A et B.

Inconvénients: il y a deux semaines, l'autre équipe a modifié un autre composant C, utilisé par A et B. Ils ont adapté A et B, mais A 'et B' ont également été cassés et nous avons dû les modifier nous-mêmes. Cela a introduit un nouveau bogue que nous avons dû corriger. Ce travail supplémentaire aurait probablement été inutile si A 'et B' avaient partagé l'essentiel de leur code avec A et B.

Donc, la duplication de code est toujours dangereuse. Je pense que c'est toujours une question de compromis et souvent ce n'est pas facile.


5

Juste pour clarifier, comme je ne le trouve dans aucune des autres réponses:

DRY est un principe de développement logiciel visant à réduire la répétition d'informations de toutes sortes .

Chaque élément de connaissance doit avoir une représentation unique, non ambiguë et faisant autorité dans un système.

Le principe DRY mentionné par Andy Hunt et Dave Thomas ne se limite pas à empêcher la duplication de code. Il préconise également la génération de code et tous les processus d'automatisation. Ironiquement, les résultats de la génération de code pourraient même être du code en double…

La raison pour laquelle cela a déjà été expliqué en détail dans les autres réponses, mais le commentaire de Falcon le résume assez bien à mon humble avis:

Un point de changement unique est plus facile à maintenir.


Oh wow, je pensais que la balise contenait des données. Je vais mettre quelques informations là-bas.
Incognito

3

Il y a une chose telle que trop sec. Lorsque cela se produit, deux concepts qui semblent à un moment donné être suffisamment similaires pour justifier l’affacturage du code (1) peuvent s’avérer ultérieurement suffisamment différents pour mériter des implémentations distinctes.

En d'autres termes, les couplages DRY et loose sont parfois en conflit. Si vous vous attendez à ce que doStuff1 et ses amis divergent à chaque nouvelle version du logiciel, vous pouvez dupliquer leur code.

D'après mon expérience, il peut être difficile de juger de l'avenir de votre logiciel, et pour cette raison, DRY est souvent un choix sûr.

Un code trop "séché" a généralement un flux de contrôle complexe et trop de paramètres. Ce qui était initialement une fonction simple a ensuite été étendu pour prendre en charge une nouvelle fonctionnalité contrôlée par un paramètre supplémentaire. Après deux ou trois itérations, la fonction n'est plus maintenable. Corrigez un bogue qui se produit dans un paramètre et introduisez de nouveaux bogues dans d'autres paramètres.

Il est compréhensible que la qualité du code diminue souvent au fur et à mesure que le code évolue, mais j'ai déjà vu des cas où une fonction à paramètres multiples avec des spaghettis dans le corps if-then-else était le résultat d'un effort de refactorisation bien intentionné mais mal mené.

(1) J'utilise le mot "code", mais cela s'applique également à la conception.


Il serait utile de donner un exemple de "trop ​​sec" car il s'agit de l'extrémité la moins visible du spectre.
Incognito

@ Incognito: J'ai modifié ma réponse. Aucun exemple concret, mais j'espère que ce que je voulais dire est assez clair.
Joh

2

Je dois mentionner les problèmes de DRY dans le monde des bases de données relationnelles. Les bases de données sont conçues pour fonctionner rapidement et efficacement en utilisant une logique basée sur les ensembles et des requêtes simples. Les principes de DRY amènent souvent le développeur à écrire des requêtes non compressables ou à utiliser la logique Ligne par ligne pour exploiter le code existant dans plusieurs situations. DRY et l'optimisation des performances sont souvent contradictoires et dans le monde des bases de données, les performances sont généralement beaucoup plus critiques que la maintenabilité. Cela ne signifie pas que vous ne devez absolument pas utiliser les principes DRY, mais que vous devez savoir comment cela affectera la convivialité globale de la base de données. Les développeurs d’applications sèchent d’abord sur le sec, puis sur les performances, puis sur l’intégrité des données, puis sur la sécurité, puis sur la sécurité des données.

En général, j'ai remarqué que plus le nombre de couches d'abstraction dans les requêtes de base de données est lent, plus elles deviennent lentes. Je ne dis pas que je ne souhaitais pas que les concepteurs de programmes de base de données eux-mêmes ne permettent pas aux développeurs d'utiliser DRY sans affecter la performance de la base de données, mais je ne conçois pas de logiciel de base de données à ce niveau. , donc peut-être que le conflit entre abstraction et performance dans la base de données est plus difficile à résoudre que je suppose. Cependant, nous devons travailler avec les systèmes tels qu'ils sont actuellement construits. Nous pouvons demander une meilleure mise en œuvre des principes de DRY dans les versions à venir, ce qui ne réduira pas non plus les performances (et cela s'est amélioré au fil des ans, mais reste problématique), mais entre-temps, nous devons déterminer si DRY est le bon choix pour cette base de données. en ce moment.

Mais souvent, les fonctionnalités que vous souhaitez utiliser pour garantir le respect du principe DRY sont celles qui posent d'énormes problèmes à la base de données. Je ne dis pas qu'il ne faut jamais utiliser DRY mais qu'il ne faut pas en abuser.

Des exemples de ce que je parle. Vous devez importer un million de données une fois par mois. Les enregistrements peuvent déjà être ajoutés manuellement via l'interface utilisateur en appelant un proc stocké. Ce processus, parce qu’il a été conçu pour les importations d’enregistrements uniques, n’ajoute qu’un enregistrement à la fois. En utilisant DRY pour éviter d'avoir le code d'insertion à deux endroits, vous écrivez un curseur pour appeler le proc à plusieurs reprises plutôt que d'écrire les importations basées sur les ensembles dont vous avez besoin. Le temps nécessaire à l’importation va de 30 minutes à 18 heures avec la logique basée sur les ensembles. Dans ce cas, la bonne façon d’adhérer à DRY serait de corriger le processus permettant de gérer les importations d’enregistrements multiples. Malheureusement, il est souvent impossible ou très difficile d’envoyer un tableau à un proc (en fonction du back-end de la base de données) et en changeant le proc, vous finissez par casser l’application.

Les fonctions scalaires et les fonctions table sont également utilisées pour implémenter les principes DRY et, là encore, elles peuvent sérieusement affecter les performances, en particulier si vous devez les utiliser de manière à éviter que les index ne soient utiles.

Les vues sont également utiles pour la mise en œuvre de DRY. Toutefois, si vous implémentez DRY en utilisant des vues appelant des vues appelant d'autres vues, vous arriverez rapidement au point d'expiration du délai de chargement des requêtes. En fait, vous pourriez avoir besoin de générer des ensembles de données de millions d'enregistrements alors que vous n'en avez besoin que de trois à la fin. Ainsi, une vue à un niveau d'un ensemble complexe de jointures pour implémenter DRY peut être excellente (j'en ai moi-même une que nous utilisons pour nous assurer que tous les rapports financiers utilisent le même ensemble de base de tableaux et de calculs de certaines choses), plus de deux niveaux. et vous devez considérer si vous créez un gâchis de performances.


1

Je ne vois pas les points clés de ma réponse ci-dessus, alors allez-y. Ne regardez pas tellement DRY comme une règle contrefaire quelque chose. Cela peut être formulé comme ça, mais cela peut servir un objectif tout à fait différent et positif. C'est un signal pour arrêter, réfléchir et trouver une meilleure réponse. Cela me met au défi de rechercher des opportunités pour concevoir une meilleure solution. C'est le bon côté d'une mauvaise odeur dans mon code qui me pousse à repenser mon design et me permet de le faire beaucoup mieux. DRY ne concerne pas seulement une violation de syntaxe Itty Bitty. Cela me met au défi de modulariser. Cela me met au défi de composer. Cela signale une répétition qui me rappelle d’utiliser des modèles et la génération de code plutôt que la force brute et l’ignorance. Cela m'aide à comprendre que je devrais trouver du temps pour automatiser mon automatisation. Cela vous mène à un style de vie parcimonieux! Il vous aide à passer plus de temps à faire de nouvelles choses plus cool plutôt que de simples détails ennuyeux. Et cela vous donne de bonnes manières, une bonne haleine et un mode de vie sain! Eh bien, peut-être que je m'égare un peu ...


DRY a des effets très différents sur moi, cependant, si ce sont ses effets sur vous, j'aime plutôt l'idée que quelque chose soit "le signal d'arrêter, de penser et de trouver une meilleure réponse" et le défi.
n611x007

1

J'ai un ancien projet, où certains des anciens développeurs ne se souciaient pas du tout de DRY. Donc toute la base de code était encombrée de méthodes d'assistance telles que GetSystemTimeAsString (), LogToFile () et beaucoup d'autres choses. Certaines méthodes ont été légèrement adaptées aux besoins particuliers, mais la plupart consistaient simplement à copier-coller.

Malheureusement, certaines méthodes avaient des bugs subtils tels que tableau de caractères pas assez long dans certains cas, en utilisant des choses non sécurisées comme strcpy (), etc.

C'était donc un vrai PITA de trouver tous les fragments de code, de les harmoniser et de corriger les bugs. Et nous continuons d’harmoniser et de corriger les problèmes.

Vous ne savez jamais, si vous avez commis une erreur dans votre première méthode et que vous devez ensuite la corriger plusieurs fois, car vous venez de la copier. Et si vous souhaitez utiliser certaines des méthodes plus tard, comment savez-vous, laquelle des 5 méthodes de la base de code est celle qui convient à votre cas maintenant? Donc, il vous suffit de copier un, de le personnaliser et ici, il recommence ...


1

Oui, ne vous occupez pas de DRY si vous écrivez du code Throwaway .

Mais DRY est important, bien sûr, si vous prévoyez de conserver le code.


1

La phraséologie "ne vous répétez pas" est un peu simpliste. Ce qui est important, c’est «éviter d’avoir une information potentiellement modifiable encapsulée dans deux endroits indépendants ».

Si un programme est supposé traiter des widgets, chacun avec trois woozles et plusieurs boucles de la forme

for (i=0; i<3; i++)
  thisWidget.processWoozle(i);

alors, l'attente que les widgets devraient contenir trois woozles serait encapsulée dans chacune de ces boucles, et il pourrait être difficile de mettre à jour le code pour l'adapter à tout autre nombre de woozles par widget. En revanche, si on devait dire

#define WOOZLES_PER_WIDGET 3

et chaque boucle ont été réécrites

for (i=0; i<WOOZLES_PER_WIDGET; i++) ...

une telle conception pourrait rendre très facile la modification du nombre de woozles par widget.

Cependant, il est important de noter que s'il est souhaitable de consolider en un seul point des informations telles que le nombre de woozles par widget, ce n'est pas toujours pratique. Parfois, il peut être nécessaire de coder en dur la logique qui ne fonctionnera que si les choses ont une taille particulière. Par exemple, si chaque woozle a une valeur et que l'on veut trouver la médiane associée à un widget particulier, il peut être possible de trier les valeurs et de prendre celle du milieu, et une telle approche fonctionnerait avec un nombre quelconque de woozles, mais la logique qui est écrit à la main spécifiquement pour trouver la médiane de trois éléments pourrait être considérablement plus rapide.

Bien que le fait de disposer d'une constante WOOZLES_PER_WIDGET puisse rendre le code plus lisible, il convient de le commenter afin d'indiquer clairement que sa valeur ne peut pas être modifiée sans effectuer d'autres ajustements à la logique du programme. Dans ce cas, la logique codée en dur pour trois éléments et la constante WOOZLES_PER_WIDGET dupliqueraient toutes les deux l'information «chaque widget a trois woozles», mais les avantages d'une telle duplication (vitesse d'exécution supérieure) pourraient l'emporter sur le coût.


0

Bien que je sois d’accord avec les autres affiches, les commentaires sur la maintenabilité, etc., sont tous valables.

Je voudrais ajouter une petite voix dissidente au débat.

  • Ce n'est important que pour les programmeurs. Les personnes qui paient votre salaire s'en moquent bien tant que le logiciel passe en UAT.
  • En termes d’importance, il se classe bien au-dessous des éléments tels que répondre aux exigences, écouter les sponsors du projet et respecter les délais.

comme ce site est destiné aux "programmeurs", je pense qu'il est prudent de dire que la question s'adresse au "point de vue des programmeurs". Vos déclarations sur les payeurs de salaire, les UAT et le rang d'importance sont évidemment valables, mais ne concernent pas cette question spécifique.
ozz

1
Je suis totalement en désaccord. Une bonne gestion comprendra les principes et leur raison d'être s'ils sont expliqués en détail. Ce devrait être une conversation sérieuse en profondeur, pas une chute de 5 minutes par chose.
Michael Durrant

2
Votre deuxième point est tout à fait correct.
Jim G.

1
@Ozz, la fierté de votre métier est importante, voire nécessaire pour un bon programmeur, mais peut-être que le "point de vue des programmeurs" devrait inclure un minimum de souci de la "satisfaction du client".
James Anderson

0

<tl;dr>

Je ne pouvais pas lire toutes les réponses répétées, donc j'ai peut-être oublié quelque chose (et le répète moi-même <= voir ce que j'ai fait ici?).

Voici la liste des choses impressionnantes sur la prévention de la duplication de code!

  1. Plus facile à tester: il vous suffit de tester une "copie" du code.
  2. Plus facile à corriger: il suffit de trouver le bogue dans une "copie" du code et de le réparer une fois.
  3. Plus facile à mettre à jour (comme ci-dessus): les modifications nécessaires peuvent souvent être gérées en modifiant le code dans très peu d'endroits, car vous avez pris le temps de le réutiliser correctement et n'avez pas copié les mêmes lignes vers des centaines, voire des milliers, d'endroits différents dans la source.
  4. Plus facile à réutiliser: quand (non dupliqué à quelques endroits) et conservé dans des méthodes génériques au nom bien nommé, il est facile de les trouver et de les utiliser au lieu d'écrire les vôtres.
  5. Plus facile à lire: le code dupliqué est difficile à lire car il est inutilement détaillé; il contient un grand nombre de lignes qui ne font pas partie de la logique et de la fonctionnalité spécifique (par exemple, des commandes génériques servant à configurer le stade de l'action ou des tâches génériques répétées simples qui sont nécessaires à de nombreux endroits). Un code propre fait apparaître la logique et les fonctionnalités car il n'y a pas de répétition qui jonche l'espace de code.
  6. Plus facile à déboguer à cause de (1) et (5).
  7. Vous permet d'économiser du temps et de l'argent et de faire davantage de choses amusantes à l'avenir; créer spécifiquement meilleur code plus robuste. C'est la ligne de fond et c'est un résumé de presque tout ce qui précède. Si beaucoup de gens utilisent la même fonction doFoo1(a, b), il y a de meilleures chances que beaucoup de ses défauts et cas extrêmes gênants soient découverts et résolus. Si tout le monde copie le code et crée doFoo2(specialA)..., doFuu2^n(a, b, c)il duplique les problèmes doFoo1et crée concrètement beaucoup plus de travail.

</tl;dr>

Version longue:

Le problème avec la duplication de code est qu’il "croît de manière exponentielle" (en d’autres termes, il s’agrandit rapidement) car lorsque vous dupliquez du code, vous accordez inconsciemment à d’autres la permission de le faire (par exemple, vous n'êtes plus en mesure de les juger) vous les encouragez à faire de même. Il est également plus difficile de ne pas le faire car il est plus difficile de repérer et de réutiliser du code utile en cas de répétition redondante source de confusion dans le code source. Surtout si le code n'est pas déjà extrait dans une fonction bien nommée. Donc, si vous rencontrez un problème simple à résoudre, vous écrirez probablement un morceau de code qui le résout… Et vous échouerez probablement dans la vérification de quelques cas extrêmes, en ajoutant plus de code non testé.

Une autre chose est que pour un novice, cela peut sembler être un problème qui n’affectera que les grandes entreprises, mais j’ai trouvé que cela affligeait de très petites startups (comme dans 10 000 lignes de code dupliqué côté serveur). C'est un état d'esprit. Vous ne devez pas seulement maîtriser DRY, mais vous efforcer d'encourager les autres à faire de même. sinon, vous vous condamnerez surtout à dupliquer le code. Lorsque les moyens de DRY sont disponibles et appliqués, il est beaucoup plus facile de les appliquer. Lorsqu'il y a beaucoup de code dupliqué, il est beaucoup plus facile d'appliquer des solutions de copier-coller.

Choses que je trouve nuisibles dans la duplication de code:

  1. Cette fonction est-elle utilisable? Supposons que vous trouviez une fonction qui fait (ou semble faire ce dont vous avez besoin), comment savoir si elle est même supposée fonctionner correctement ou s'il s'agit simplement d'un code dupliqué et abandonné.
  2. Code redondant. Parfois, les gens dupliquent du code, l'utilisent et l'oublient (ils peuvent toujours le dupliquer à l'avenir). À un moment donné, une personne supprime les appels à la fonction dupliquée à certains endroits dans un effort de refactorisation, mais la fonction inutilisée subsiste même si elle n'est pas utilisée activement.
  3. Difficile de trouver ce que vous cherchez. Le code en double prend de la place et rend la recherche d'objets utiles et nécessaires (à l'aide d'outils comme grep) plus ardue que nécessaire, car vous obtenez des dizaines ou des milliers de résultats pour lesquels vous n'auriez dû obtenir qu'une poignée.
  4. (A déjà été mentionné): Difficile à maintenir mais également difficile à utiliser à des fins de maintenance et de régression. Si le code de test est dupliqué et n'est pas extrait correctement dans des fonctions, d'autres le dupliqueront. Quelqu'un se souciera-t-il d'écrire une API facile à utiliser et à lire pour améliorer la qualité de la vie? D'après mon expérience, non, il y a souvent quelque chose que les gens jugent plus urgent jusqu'à ce que tout cela devienne incontrôlable.
  5. La duplication de code est plus difficile à lire car elle rend le code verbeux là où il n’est pas nécessaire, là où la verbosité n’ajoute pas d’informations sur la fonctionnalité souhaitée: par exemple, les appels de méthode génériques utilisés [plusieurs fois] pour préparer le terrain pour plusieurs types de fonctionnalités prévues, rend plus difficile la sortie de cette fonctionnalité réelle.
  6. Cela a été beaucoup mentionné. Si le code est erroné, un pauvre garçon ou un gars pauvre devra rechercher et modifier chaque utilisation de ce code. Par exemple, si quelqu'un utilisait un appel non sécurisé par injection SQL à mysql_query dans très peu d'endroits dans une classe organisée où il était nécessaire, il serait facile de le réparer et d'utiliser PHP PDO à la place, mais s'il l'utilisait dans plus d'un millier d'endroits, copier l'appel et au-delà, la réparation nécessitera pratiquement d'être externalisée ou parfois plus dangereusement, le code devra être réécrit à partir de zéro.
  7. La duplication de code est une mauvaise habitude. Si vous pratiquez quelque chose, cela devient lentement une seconde nature et cela affecte les gens autour de vous. Les développeurs juniors voient que vous le faites et le faites aussi. Vous devriez pratiquer ce que vous prêchez et prendre l'habitude de faire ce qui est juste. Tu apprends plus. L'écriture de code non dupliqué est plus difficile et plus difficile. C'est une habitude enrichissante.

Dernières remarques sur la prévention de la duplication de code par trop zélé & résumé:

Cela a déjà été dit auparavant, mais parfois, éviter les doubles emplois vous amène à "faire des efforts en arrière" et à faire des choses trop sophistiquées (ou sans importance) pour que les autres comprennent. L'écriture de code illisible (ou, comme nous l'appelons en plaisantant, du code «conservant le travail») est un problème en soi, même si la prévention de la duplication de code n'est pas impliquée. Cependant, j'estime que, si la bonne infrastructure et les meilleures pratiques sont inculquées dès le début, il est beaucoup plus facile d'éviter la duplication de code et les gens peuvent souvent éviter de faire des choses inattendues. vous faites la chose dès ce début.

Qu'est-ce qui va bien? Il est difficile de répondre à cette question, mais une chose est de définir les méthodes nécessaires au projet, de voir ce qui a déjà été mis en œuvre par d’autres (à l’extérieur et à l’intérieur de l’entreprise) et de les réutiliser lorsque cela est possible. documenter tout ce que vous ajoutez à la base de code et essayer de le rendre un peu plus générique que nécessaire, mais c'est tout. N'exagérez pas les modèles de conception uniquement pour rendre le code flexible là où il n'est pas nécessaire.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.