web-dev-qa-db-fra.com

Est-il possible d'appliquer DRY sans augmenter le couplage?

Supposons que nous avons un module logiciel A qui implémente une fonction F. Un autre module B implémente la même fonction que f '.

Il existe un certain nombre de façons de se débarrasser du code dupliqué:

  1. Laissez une utilisation f 'de B.
  2. Soit B utiliser f de A.
  3. Mettez F dans son propre module C et laissez-les à la fois A et B.

Toutes ces options génèrent des dépendances supplémentaires entre les modules. Ils appliquent le DRY principe au coût de l'accouplement croissant.

Autant que je puisse le constater, le couplage est toujours augmenté ou loué à 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 qu'il est surprenant qu'il y ait des conflits comme ça. C'est probablement ce qui rend la conception logicielle si difficile. Je trouve qu'il est surprenant que ces conflits ne soient normalement pas traités dans des textes d'introduction.)

Modifier (pour clarification): Je suppose que l'égalité de F et F 'n'est pas simplement une coïncidence. Si F devra être modifiée, F 'devra probablement être modifiée de la même manière.

14
Frank Puffer

Toutes ces options génèrent des dépendances supplémentaires entre les modules. Ils appliquent le DRY principe au coût de l'accouplement croissant.

Pourquoi oui ils font. Mais ils diminuent le couplage entre les lignes. Ce que vous obtenez est le pouvoir de changer le couplage. Le couplage se présente sous de nombreuses formes. L'extraction du code augmente l'indirection et l'abstraction. Croissant qui peut être bon ou mauvais. La seule chose qui décide que vous obtenez est le nom que vous utilisez pour cela. Si regarder le nom me laisse surprise lorsque je regarde à l'intérieur, vous n'avez fait personne de faveurs.

Aussi, ne suivez pas DRY dans un vide. Si vous tuez la duplication, vous prenez la responsabilité de prévoir que ces deux utilisations de ce code changent ensemble. S'ils sont susceptibles de changer de manière indépendante. Vous avez causé une confusion et un travail supplémentaire pour peu d'avantages. Mais un très bon nom peut rendre cela plus agréable. Si tout ce que vous pouvez penser est un mauvais nom, alors s'il vous plaît, arrêtez-vous maintenant.

L'accouplement existera toujours à moins que votre système soit isolé que personne ne sache jamais si cela fonctionne. Donc, le couplage refactoring est un jeu de choisir votre poison. Suivant DRY=== peut payer en minimisant le couplage créé en exprimant la même décision de conception à travers et plus dans de nombreux endroits jusqu'à ce qu'il soit très difficile de changer. Mais DRY peut rendre impossible de comprendre votre code. Le meilleur moyen de sauver que la situation consiste à 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 sans signification

14
candied_orange

Il existe des moyens de casser des dépendances explicites. Un populaire est d'injecter des dépendances en runtime. De cette façon, vous obtenez sec, éliminez le couplage au coût de la sécurité statique. C'est si 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 de dépendance extrêmement compliquant le logiciel en dissimulant la complexité. Même la vieille injection du constructeur en plaine ne garantit pas certains contrats dus au manque de système de type.

Pour répondre au titre - oui, il est possible, mais préparez-vous aux conséquences de l'envoi d'exécution.

  • Définir l'interface FUNE dans A, fournissant des fonctionnalités de f
  • Définir l'interface FB en b
  • Mettre f en c
  • Créer un module D pour gérer toutes les dépendances (cela dépend de A, B et C)
  • Adaptez f à fUNE et fB en D
  • Injecter des wrappers (passer) à A et B

De cette façon, le seul type de dépendances que vous auriez eu est d en fonction de l'autre module.

Ou inscrivez-vous C dans le conteneur d'applications avec injection de dépendance intégrée et profitez de la fortune de la mise en forme d'une mise en forme d'automne en croissance progressive.

3
Basilevs

Je ne suis pas sûr qu'une réponse sans autre contexte ait du sens.

A dépendra-t-il déjà de B ou inversement? - auquel cas nous pourrions avoir un choix évident de la maison pour F.

Do A et B partage déjà toutes les dépendances courantes qui pourraient être une bonne maison pour F?

Quelle est la taille du complexe F? Quoi d'autre fait F dépend de?

Sont des modules A et B utilisé dans le même projet?

A et B finalement partager une dépendance commune de toute façon?

Quel système de langue/module est utilisé: quelle douleur est un nouveau module, dans la douleur au programmeur, en hauteur de performance? Par exemple, si vous écrivez en C/C++ avec le système de module étant COM, ce qui cause une douleur au code source, nécessite une alternance d'outils, a des implications sur le débogage et comporte une implication de performance (pour les invocations inter-module), je pourrais prenez une pause sérieuse.

D'autre part si vous parlez de Java ou C # dlls qui se combinent de manière assez transparente dans un environnement d'exécution unique, c'est une autre affaire.


Une fonction est une abstraction et supporte le sec.

Cependant, de bonnes abstractions doivent être complètes - les abstractions incomplètes peuvent très bien causer au client de la consommation (programmeur) de compenser le déficit en utilisant la connaissance de la mise en œuvre sous-jacente: il en résulte un couplage plus étroit que si l'abstraction était offerte à la place.

Donc, je discuterais de chercher à créer une meilleure abstraction pour A et B _ Pour dépendre de simplement une seule fonction dans un nouveau module C.

Je rechercherais un ensemble de fonctions pour taquiner une nouvelle abstraction, qui est à dire, j'attendrais que la base de code soit plus longue afin d'identifier une abstraction complète/plus complète refactoring à faire plutôt qu'à une seule fois. sur un seul code de fonction dit.

1
Erik Eidt

Les réponses ici qui se concentrent sur toutes les façons que vous pouvez "minimiser" ce problème vous fait un mauvais service. Et "Solutions" en offrant simplement différentes façons de créer des couples ne sont pas vraiment des solutions.

La vérité est que cela ne comprenne pas le problème même que vous avez créé. Le problème avec votre exemple n'a rien à voir avec sèche, plutôt (plus largement) avec la conception des applications.

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 de gestion de dépendance/abstraction/couplage/vous-nommez-le si vous vous engagez à une conception médiocre.

Une modélisation appropriée des applications est effectuée en fonction du comportement. En tant que tels, les pièces de A et B dépendantes de F doivent être extraites dans leur propre module indépendant. Si cela n'est pas possible, A et B doivent être combinés. Dans les deux cas, A et B ne sont plus utiles au système et cessent d'exister.

Sec est un directeur qui peut être utilisé pour exposer une conception médiocre, pas la cause. Si vous ne pouvez pas réaliser DRY (-quand Il s'applique vraiment - notant votre édition) En raison de la structure de votre application, il s'agit d'un signe clair que la structure a Devenir une responsabilité. C'est pourquoi "refactoring continu" est également un directeur à suivre.

L'ABC d'autres directeurs de conception (solide, sec, etc.), il existe tout utilisé pour faire change (y compris refactoring) une application plus indolore. Concentrez-vous sur que, et tous les autres problèmes commencent à disparaître.

0
king-side-slide

Toutes ces options génèrent des dépendances supplémentaires entre les modules. Ils appliquent le DRY principe au coût de l'accouplement croissant.

J'ai un avis différent, au moins pour la troisième option:

De votre description:

  • Un besoin f
  • B a besoin de f
  • Ni A ni b ne sont nécessaires.

Mettre F dans un module C n'augmente pas le couplage car les deux et B ont déjà besoin de C.

0
mouviciel