L'instinct habituel est de supprimer toute duplication de code que vous voyez dans le code. Cependant, je me suis retrouvé dans une situation où la duplication est illusoire .
Pour décrire la situation plus en détail: Je développe une application Web et la plupart des vues sont fondamentalement les mêmes. Elles affichent une liste d’éléments dans lesquels l’utilisateur peut faire défiler et choisir, une seconde liste contenant les éléments "bouton pour enregistrer la nouvelle liste.
Il m'a semblé que le problème est facile. Cependant, chaque vue a ses propres particularités - parfois, vous devez recalculer quelque chose, parfois vous devez stocker des données supplémentaires, etc. Cela a été résolu en insérant des points d'ancrage dans le code logique principal.
Les différences entre les vues sont si nombreuses qu'il devient de moins en moins facile à gérer, car je dois fournir des rappels pour pratiquement toutes les fonctionnalités, et la logique principale commence à ressembler à une énorme séquence d'appels de rappel. En fin de compte, je ne gagne pas de temps ni de code, car chaque vue a son propre code exécuté - le tout en rappel.
Les problèmes sont:
- les différences sont si minimes que le code est presque identique à tous les points de vue,
- il y a tellement de différences que lorsque vous regardez les détails, coder n'est pas un peu pareil
Comment dois-je gérer cette situation?
Avoir une logique de base entièrement composée d'appels de rappel est-il une bonne solution?
Ou devrais-je plutôt dupliquer le code et abandonner la complexité du code basé sur le rappel?
la source
Réponses:
En fin de compte, vous devez vous prononcer sur la possibilité de combiner un code similaire pour éliminer les doublons.
Il semble exister une fâcheuse tendance à considérer les principes du type "Ne vous répétez pas" comme des règles à suivre systématiquement. En fait, ce ne sont pas des règles universelles, mais des directives qui devraient vous aider à réfléchir et à développer un bon design.
Comme tout dans la vie, vous devez considérer les avantages par rapport aux coûts. Combien de code dupliqué sera supprimé? Combien de fois le code est répété? Combien d'effort faudra-t-il pour écrire un design plus générique? À quel point êtes-vous susceptible de développer le code dans le futur? Etc.
Sans connaître votre code spécifique, ceci n'est pas clair. Il existe peut-être un moyen plus élégant d’éliminer les doubles emplois (comme celui suggéré par LindaJeanne). Ou peut-être qu'il n'y a tout simplement pas assez de répétition vraie pour justifier une abstraction.
Une attention insuffisante au design est un piège, mais il faut aussi se méfier du sur-design.
la source
Rappelez-vous que DRY concerne la connaissance . Peu importe que deux éléments de code soient similaires, identiques ou totalement différents. Ce qui compte, c'est si le même élément de connaissance sur votre système peut être trouvé dans les deux éléments.
Une connaissance peut être un fait ("l'écart maximal autorisé par rapport à la valeur souhaitée est de 0,1%") ou un aspect de votre processus ("cette file d'attente ne contient jamais plus de trois éléments"). Il s’agit essentiellement d’une information encodée dans votre code source.
Ainsi, lorsque vous décidez si une duplication doit être supprimée, demandez-lui s'il s'agit d'une duplication de connaissances. Si ce n'est pas le cas, il s'agit probablement d'une duplication accidentelle et son extraction à un endroit commun risque de poser des problèmes si vous souhaitez créer ultérieurement un composant similaire lorsque cette partie apparemment dupliquée est différente.
la source
Avez-vous envisagé d'utiliser un modèle de stratégie ? Vous auriez une classe View contenant le code commun et les routines appelées par plusieurs vues. Les enfants de la classe View contiendraient le code spécifique à ces instances. Ils utiliseraient tous l'interface commune que vous avez créée pour la vue. Ainsi, les différences seraient encapsulées et cohérentes.
la source
Quel est le potentiel de changement? Par exemple, notre application dispose de 8 domaines d’activité différents avec un potentiel de 4 types d’utilisateurs ou plus pour chaque domaine. Les vues sont personnalisées en fonction du type d'utilisateur et de la zone.
Initialement, cela a été fait en utilisant la même vue avec quelques vérifications ici et là pour déterminer si différentes choses devraient apparaître. Au fil du temps, certains secteurs d’activité ont décidé de prendre des mesures radicalement différentes. Au final, nous avons essentiellement migré vers une vue (vues partielles, dans le cas d’ASP.NET MVC) par fonctionnalité et par domaine d’activité. Tous les domaines d’activité n’ont pas la même fonctionnalité, mais si l’on souhaite une fonctionnalité identique à celle d’un autre, cette zone obtient son propre point de vue. C'est beaucoup moins lourd pour la compréhension du code, ainsi que pour la testabilité. Par exemple, faire un changement pour un domaine ne provoquera pas de changement indésirable pour un autre domaine.
Comme @ dan1111 l'a mentionné, il peut s'agir d'un jugement. Avec le temps, vous constaterez peut-être que cela fonctionne ou non.
la source
L’un des problèmes peut être que vous fournissez une interface (interface théorique, et non une fonctionnalité linguistique) à un seul niveau de fonctionnalité:
Au lieu de plusieurs niveaux selon le degré de contrôle requis:
D'après ce que j'ai compris, vous n'exposez que l'interface de haut niveau (A), en masquant les détails de la mise en œuvre (les autres éléments présents).
Masquer les détails de la mise en œuvre présente des avantages, et vous venez de constater un inconvénient: le contrôle est limité, à moins que vous ajoutiez explicitement des fonctionnalités pour chaque chose qui aurait été possible si vous utilisiez directement les interfaces de bas niveau.
Donc, vous avez deux options. Soit vous utilisez uniquement l'interface de bas niveau, vous utilisez l'interface de bas niveau car l'interface de haut niveau demandait trop de travail à maintenir, ou vous exposiez des interfaces de niveau haut et bas. La seule option judicieuse consiste à offrir des interfaces de haut niveau et de bas niveau (et tout ce qui se trouve entre les deux), en supposant que vous souhaitiez éviter un code redondant.
Ensuite, lorsque vous écrivez une autre de vos choses, vous regardez toutes les fonctionnalités disponibles que vous avez écrites jusque-là (d'innombrables possibilités, à vous de décider lesquelles seront réutilisées) et de les assembler.
Utilisez un seul objet où vous avez besoin de peu de contrôle.
Utilisez la fonctionnalité de niveau le plus bas lorsque l’étranger doit se produire.
Ce n'est pas non plus très noir et blanc. Peut-être que votre grande classe de haut niveau PEUT raisonnablement couvrir tous les cas d'utilisation possibles. Peut-être que les cas d'utilisation varient tellement que rien, à part la fonctionnalité primitive de niveau le plus bas, ne suffit. A vous de trouver l'équilibre.
la source
Il y a déjà d'autres réponses utiles. Je vais ajouter le mien.
La duplication est mauvaise parce que
Donc, le fait est que vous n'éliminez pas le double emploi pour le plaisir ou parce que quelqu'un a dit que c'était important. Vous le faites parce que vous voulez réduire les bugs / problèmes. Dans votre cas, il semble que si vous modifiez quelque chose dans une vue, vous n'aurez probablement pas besoin de changer exactement la même ligne dans toutes les autres vues. Donc, vous avez une duplication apparente , pas une duplication réelle.
Un autre point important est de ne jamais réécrire à partir de zéro quelque chose qui fonctionne à présent uniquement sur la base d'une question de principe, comme l'a dit Joel (vous auriez déjà entendu parler de lui ...). Donc, si vos points de vue fonctionnent, continuez à vous améliorer étape par étape et ne tombez pas dans le piège de la "pire erreur stratégique qu'une société de logiciels puisse commettre".
la source