Supongamos que tenemos un módulo de software A que implementa una función F. Otro módulo B implementa la misma función que F '.
Hay varias formas de deshacerse del código duplicado:
- Deje que A use F 'de B.
- Deje que B use F de A.
- Coloque F en su propio módulo C y deje que A y B lo usen.
Todas estas opciones generan dependencias adicionales entre módulos. Aplican el principio DRY a costa de aumentar el acoplamiento.
Por lo que puedo ver, el acoplamiento siempre aumenta o, al arrendar, se mueve a un nivel superior al aplicar DRY. Parece haber un conflicto entre dos de los principios más básicos del diseño de software.
(En realidad, no me sorprende que haya conflictos como ese. Esto es probablemente lo que hace que un buen diseño de software sea tan difícil. Me parece sorprendente que estos conflictos normalmente no se aborden en los textos introductorios).
Editar (para aclarar): supongo que la igualdad de F y F 'no es solo una coincidencia. Si F tendrá que modificarse, F 'probablemente tendrá que modificarse de la misma manera.
fuente
Respuestas:
¿Por qué sí lo hacen? Pero disminuyen el acoplamiento entre líneas. Lo que obtienes es el poder de cambiar el acoplamiento. El acoplamiento viene en muchas formas. La extracción de código aumenta la indirección y la abstracción. Aumentar eso puede ser bueno o malo. La cosa número uno que decide cuál obtienes es el nombre que usas para ello. Si mirar el nombre me sorprende cuando miro adentro, entonces no le has hecho ningún favor a nadie.
Además, no siga DRY en el vacío. Si elimina la duplicación, asume la responsabilidad de predecir que estos dos usos de ese código cambiarán juntos. Si es probable que cambien de forma independiente, ha causado confusión y trabajo extra por poco beneficio. Pero un nombre realmente bueno puede hacerlo más agradable al paladar. Si todo lo que puede pensar es un mal nombre, por favor, deténgase ahora.
El acoplamiento siempre existirá a menos que su sistema esté tan aislado que nadie sepa si funciona. Así que refactorizar el acoplamiento es un juego de elegir tu veneno. Seguir a DRY puede ser rentable al minimizar el acoplamiento creado al expresar la misma decisión de diseño una y otra vez en muchos lugares hasta que sea muy difícil cambiarlo. Pero DRY puede hacer que sea imposible entender su código. La mejor manera de salvar esa situación es encontrar un nombre realmente bueno. Si no puedes pensar en un buen nombre, espero que seas hábil para evitar nombres sin sentido
fuente
Hay formas de romper dependencias explícitas. Una popular es inyectar dependencias en tiempo de ejecución. De esta manera, obtiene SECO, elimina el acoplamiento a costa de la seguridad estática. Es tan popular hoy en día, que las personas ni siquiera entienden, eso es una compensación. Por ejemplo, los contenedores de aplicaciones proporcionan rutinariamente una gestión de dependencias que complica enormemente el software al ocultar la complejidad. Incluso la simple inyección de constructor antiguo no garantiza algunos contratos debido a la falta de un sistema de tipos.
Para responder al título, sí, es posible, pero prepárese para las consecuencias del despacho de tiempo de ejecución.
De esta manera, el único tipo de dependencias que tendría es D, dependiendo de cada módulo.
O registre C en el contenedor de la aplicación con inyección de dependencia incorporada y disfrute de fortunas de autoconexión de bucles y puntos muertos de tiempo de ejecución de crecimiento lento.
fuente
No estoy seguro de que una respuesta sin más contexto tenga sentido.
¿
A
Ya dependeB
o viceversa? - en cuyo caso podríamos tener una opción obvia de hogar paraF
.¿ Comparte
A
yB
ya comparte dependencias comunes que podrían ser un buen hogarF
?¿Qué tan grande / complejo es
F
? ¿De qué másF
depende?¿Son módulos
A
y seB
utilizan en el mismo proyecto?¿
A
YB
terminará compartiendo alguna dependencia común de todos modos?¿Qué sistema de lenguaje / módulo se está utilizando? Por ejemplo, si está escribiendo en C / C ++ con el sistema de módulos como COM, lo que causa dolor al código fuente, requiere herramientas alternativas, tiene implicaciones en la depuración y tiene implicaciones de rendimiento (para invocaciones entre módulos), podría toma una pausa seria.
Por otro lado, si está hablando de Java o C # DLL que se combinan sin problemas en un solo entorno de ejecución, ese es otro asunto.
Una función es una abstracción y admite DRY.
Sin embargo, las buenas abstracciones deben completarse; las abstracciones incompletas pueden muy bien hacer que el cliente consumidor (programador) compense el déficit utilizando el conocimiento de la implementación subyacente: esto da como resultado un acoplamiento más estricto que si la abstracción se ofreciera como más completa.
Por lo tanto, argumentaría que debería buscar crear una mejor abstracción
A
yB
depender de ella, que simplemente mover una sola función a un nuevo móduloC
.Estaría buscando un conjunto de funciones para generar una nueva abstracción, es decir, podría esperar hasta que la base del código esté más avanzada para identificar una refactorización de abstracción más completa / completa que hacer en lugar de una basada en un solo código de función tell.
fuente
Does A already depend on B or vice versa? — in which case we might have an obvious choice of home for F.
Esto supone que A siempre dependerá de B (o viceversa), lo cual es una suposición muy peligrosa. El hecho de que OP vea a F como parte inherente de A (o B) sugiere que F existe sin ser inherente a ninguna de las bibliotecas. Si F pertenece a una biblioteca (por ejemplo, un método de extensión DbContext (F) y una biblioteca de contenedor Entity Framework (A o B)), entonces la pregunta de OP sería discutible.Las respuestas aquí que se centran en todas las formas en que puede "minimizar" este problema le están perjudicando. Y las "soluciones" que simplemente ofrecen diferentes formas de crear acoplamiento no son realmente soluciones en absoluto.
La verdad es que no entienden el problema que usted ha creado. El problema con su ejemplo no tiene nada que ver con DRY, más bien (más ampliamente) con el diseño de la aplicación.
Pregúntese por qué los módulos A y B están separados si ambos dependen de la misma función F? Por supuesto, tendrá problemas con la gestión de dependencias / abstracción / acoplamiento / nombre-si se compromete con un diseño deficiente.
El modelado adecuado de la aplicación se realiza de acuerdo con el comportamiento. Como tal, las piezas de A y B que dependen de F deben extraerse en su propio módulo independiente. Si esto no es posible, entonces A y B deben combinarse. En cualquier caso, A y B ya no son útiles para el sistema y deberían dejar de existir.
DRY es un principio que se puede usar para exponer un diseño deficiente, no para causarlo. Si no puede lograr DRY ( cuando realmente se aplica, teniendo en cuenta su edición) debido a la estructura de su aplicación, es una clara señal de que la estructura se ha convertido en una responsabilidad. Es por eso que la "refactorización continua" también es un principio a seguir.
De otros principios de diseño (sólido, seco, etc) por ahí son el ABC de todo usado para hacer el cambio (incluyendo refactorización) una aplicación más indolora. Concéntrese en eso , y todos los otros problemas comienzan a desaparecer.
fuente
Tengo una opinión diferente, al menos para la tercera opción:
De tu descripción:
Poner F en un módulo C no aumenta el acoplamiento ya que tanto A como B ya necesitan la función de C.
fuente