Supposons que nous ayons un module logiciel A qui implémente une fonction F. Un autre module B implémente la même fonction que F '.
Il existe plusieurs façons de se débarrasser du code en double:
- Soit A utiliser F 'de B.
- Soit B utiliser F de A.
- Mettez F dans son propre module C et laissez A et B l'utiliser.
Toutes ces options génèrent des dépendances supplémentaires entre les modules. Ils appliquent le principe DRY au prix d'augmenter le couplage.
Pour autant que je puisse voir, le couplage est toujours augmenté ou, à la location, déplacé à un niveau supérieur lors de l'application de SEC. Il semble y avoir un conflit entre deux des principes les plus élémentaires de la conception de logiciels.
(En fait, je ne trouve pas surprenant qu'il y ait de tels conflits. C'est probablement ce qui rend la conception d'un logiciel si difficile. Je trouve surprenant que ces conflits ne soient normalement pas abordés dans les textes d'introduction.)
Edit (pour clarification): Je suppose que l'égalité de F et F 'n'est pas seulement une coïncidence. Si F devra être modifié, F 'devra probablement être modifié de la même manière.
la source
Réponses:
Pourquoi oui ils le font. Mais ils diminuent le couplage entre les lignes. Ce que vous obtenez, c'est le pouvoir de changer le couplage. Le couplage se présente sous plusieurs formes. L'extraction de code augmente l'indirection et l'abstraction. Augmenter cela peut être bon ou mauvais. La première chose qui décide de ce que vous obtenez est le nom que vous utilisez pour cela. Si regarder le nom me laisse surpris quand je regarde à l'intérieur, vous n'avez rendu service à personne.
Aussi, ne suivez pas SEC dans le vide. Si vous tuez la duplication, vous prenez la responsabilité de prévoir que ces deux utilisations de ce code changeront ensemble. S'ils sont susceptibles de changer indépendamment, vous avez causé de la confusion et du travail supplémentaire pour peu d'avantages. Mais un très bon nom peut rendre cela plus agréable au goût. Si tout ce à quoi vous pouvez penser est une mauvaise réputation, alors arrêtez-vous maintenant.
Le couplage existera toujours à moins que votre système ne soit si isolé que personne ne saura jamais s'il fonctionne. Le refactoring du couplage consiste donc à choisir son poison. Suivre DRY peut être payant en minimisant le couplage créé en exprimant la même décision de conception à plusieurs reprises jusqu'à ce qu'il soit très difficile de changer. Mais DRY peut rendre impossible la compréhension de votre code. La meilleure façon de sauver cette situation est de trouver un très bon nom. Si vous ne pouvez pas penser à un bon nom, j'espère que vous êtes habile à éviter les noms dénués de sens
la source
Il existe des moyens de rompre les dépendances explicites. Une méthode courante consiste à injecter des dépendances dans l'exécution. De cette façon, vous obtenez SEC, retirez l'accouplement au prix d'une sécurité statique. C'est tellement populaire de nos jours, que les gens ne comprennent même pas, que c'est un compromis. Par exemple, les conteneurs d'applications fournissent régulièrement une gestion des dépendances qui complique énormément les logiciels en masquant la complexité. Même une injection de constructeur simple ne parvient pas à garantir certains contrats en raison d'un système de type manquant.
Pour répondre au titre - oui, c'est possible, mais préparez-vous aux conséquences de l'envoi du runtime.
De cette façon, le seul type de dépendances que vous auriez serait D en fonction de chaque autre module.
Ou enregistrez C dans le conteneur d'application avec une injection de dépendances intégrée et profitez de la possibilité de câbler automatiquement des boucles et des blocages de chargement de classe à croissance lente.
la source
Je ne suis pas sûr qu'une réponse sans autre contexte ait du sens.
Dépend
A
déjàB
ou vice versa? - dans ce cas, nous pourrions avoir un choix évident de maison pourF
.Partagez-vous
A
etB
partagez-vous déjà des dépendances communes qui pourraient être un bon foyerF
?Quelle est la taille / la complexité
F
? De quoi d'autreF
dépend-il?Sont des modules
A
etB
utilisés dans le même projet?Va
A
- t-il etB
finira- t- il par partager une dépendance commune?Quel système de langue / module est utilisé: Dans quelle mesure un nouveau module est-il pénible pour le programmeur, en termes de performances? Par exemple, si vous écrivez en C / C ++ avec le système de modules COM, ce qui cause des problèmes au code source, nécessite des outils alternatifs, a des implications sur le débogage et a des implications en termes de performances (pour les appels inter-modules), je pourrais prenez une pause sérieuse.
D'un autre côté, si vous parlez de DLL Java ou C # qui se combinent de manière plutôt transparente dans un environnement d'exécution unique, c'est une autre question.
Une fonction est une abstraction et prend en charge DRY.
Cependant, de bonnes abstractions doivent être complètes - des abstractions incomplètes peuvent très bien amener le client consommateur (programmeur) à combler le déficit en utilisant la connaissance de l'implémentation sous-jacente: cela se traduit par un couplage plus étroit que si l'abstraction était proposée à la place comme plus complète.
Donc, je dirais de chercher à créer une meilleure abstraction
A
etB
à dépendre que de simplement déplacer une seule fonction dans un nouveau moduleC
.Je chercherais un ensemble de fonctions pour taquiner une nouvelle abstraction, c'est-à-dire que je pourrais attendre que la base de code soit plus avancée afin d'identifier une refactorisation d'abstraction plus complète / plus complète à faire plutôt qu'une basée sur un seul code de fonction dire.
la source
Does A already depend on B or vice versa? — in which case we might have an obvious choice of home for F.
Cela suppose que A dépendra toujours de B (ou vice versa), ce qui est une hypothèse très dangereuse. Le fait que OP considère F comme ne faisant pas intrinsèquement partie de A (ou B) suggère que F existe sans être inhérent à l'une ou l'autre bibliothèque. Si F appartient à une bibliothèque (par exemple une méthode d'extension DbContext (F) et une bibliothèque d'encapsulation Entity Framework (A ou B)), la question de OP serait théorique.Les réponses ici qui se concentrent sur toutes les façons dont vous pouvez «minimiser» ce problème ne vous rendent pas service. Et les «solutions» offrant simplement différentes façons de créer un couplage ne sont pas vraiment des solutions.
La vérité est que vous ne comprenez pas le problème même que vous avez créé. Le problème avec votre exemple n'a rien à voir avec DRY, plutôt (plus largement) avec la conception d'application.
Demandez-vous pourquoi les modules A et B sont séparés s'ils dépendent tous deux de la même fonction F? Bien sûr, vous aurez des problèmes avec la gestion des dépendances / abstraction / couplage / you-name-it si vous vous engagez à une mauvaise conception.
Une modélisation d'application appropriée est effectuée en fonction du comportement. En tant que tel, les morceaux de A et B qui dépendent de F doivent être extraits dans leur propre module indépendant. Si cela n'est pas possible, alors A et B doivent être combinés. Dans les deux cas, A et B ne sont plus utiles au système et devraient cesser d'exister.
DRY est un principe qui peut être utilisé pour exposer une mauvaise conception, pas la provoquer. Si vous ne pouvez pas atteindre DRY ( quand cela s'applique vraiment - en notant votre modification) en raison de la structure de votre application, c'est un signe clair que la structure est devenue un handicap. C'est pourquoi le «refactoring continu» est également un principe à suivre.
Les ABC des autres principes de conception (SOLID, DRY, etc.) sont tous utilisés pour rendre la modification (y compris la refactorisation) d'une application plus indolore. Concentrez -vous sur ce que , et tous les autres problèmes commencent à disparaître.
la source
J'ai une opinion différente, au moins pour la troisième option:
D'après votre description:
Mettre F dans un module C n'augmente pas le couplage car A et B ont déjà besoin de la fonctionnalité de C.
la source