El único anti-patrón legítimo de inyección de dependencia que conozco es el Localizador de servicios patrón , que es un antipatrón cuando se usa un marco DI para él.
Todos los otros llamados antipatrones de DI que he escuchado, aquí o en otros lugares, son casos un poco más específicos de antipatrones generales de diseño de software / OO. Por ejemplo:
La sobreinyección del constructor es una violación del Principio de responsabilidad única . Demasiados argumentos de constructor indican demasiadas dependencias; Demasiadas dependencias indican que la clase está tratando de hacer demasiado. Por lo general, este error se correlaciona con otros olores de código, como nombres de clase inusualmente largos o ambiguos ("administrador"). Las herramientas de análisis estático pueden detectar fácilmente el acoplamiento aferente / eferente excesivo.
La inyección de datos, en oposición al comportamiento, es un subtipo del antipatrón poltergeist , siendo el 'geist en este caso el contenedor. Si una clase necesita estar al tanto de la fecha y hora actuales, no se inyecta un DateTime
, que es datos; en su lugar, inyecta una abstracción sobre el reloj del sistema (generalmente llamo al mío ISystemClock
, aunque creo que hay uno más general en el proyecto SystemWrappers ). Esto no solo es correcto para DI; es absolutamente esencial para la capacidad de prueba, para que pueda probar funciones que varían en el tiempo sin tener que esperarlas.
Declarar cada ciclo de vida como Singleton es, para mí, un ejemplo perfecto de programación de culto de carga y, en menor grado, el " pozo negro de objetos " denominado coloquialmente . He visto más abuso de singleton del que me gustaría recordar, y muy poco de eso involucra DI.
Otro error común son los tipos de interfaz específicos de la implementación (con nombres extraños como IOracleRepository
) realizados solo para poder registrarlo en el contenedor. Esto es en sí mismo una violación del Principio de Inversión de Dependencia (solo porque es una interfaz, no significa que sea realmente abstracto) y, a menudo, también incluye una hinchazón de la interfaz que viola el Principio de Segregación de la Interfaz .
El último error que generalmente veo es la "dependencia opcional", que hicieron en NerdDinner . En otras palabras, hay un constructor que acepta la inyección de dependencia, pero también otro constructor que usa una implementación "predeterminada". Esto también viola el DIP y tiende a conducir a violaciones de LSP , ya que los desarrolladores, con el tiempo, comienzan a hacer suposiciones sobre la implementación predeterminada y / o comienzan instancias nuevas utilizando el constructor predeterminado.
Como dice el viejo dicho, puedes escribir FORTRAN en cualquier idioma . La Inyección de dependencias no es una bala de plata que evitará que los desarrolladores arruinen su administración de dependencias, pero sí evita una serie de errores / antipatrones comunes:
...y así.
Obviamente, no desea diseñar un marco para depender de una implementación específica del contenedor de IoC , como Unity o AutoFac. Es decir, una vez más, violar el DIP. Pero si te encuentras incluso pensando en hacer algo así, entonces ya debes haber cometido varios errores de diseño, porque la inyección de dependencias es una técnica de gestión de dependencias de propósito general y no vinculada al concepto de un contenedor IoC.
Cualquier cosa puede construir un árbol de dependencia; tal vez es un contenedor de IoC, tal vez es una prueba unitaria con un montón de simulacros, tal vez es un controlador de prueba que proporciona datos ficticios. Su marco no debería importarle, y a la mayoría de los marcos que he visto no les importa, pero aún así hacen un uso intensivo de la inyección de dependencia para que pueda integrarse fácilmente en el contenedor de IoC elegido por el usuario final.
DI no es ciencia espacial. Solo trate de evitar new
y static
excepto cuando haya una razón convincente para usarlos, como un método de utilidad que no tenga dependencias externas o una clase de utilidad que posiblemente no tenga ningún propósito fuera del marco (los contenedores de interoperabilidad y las claves de diccionario son ejemplos comunes de esta).
Muchos de los problemas con los marcos de IoC surgen cuando los desarrolladores aprenden por primera vez cómo usarlos, y en lugar de cambiar realmente la forma en que manejan las dependencias y las abstracciones para adaptarse al modelo de IoC, intentan manipular el contenedor de IoC para cumplir con las expectativas de sus clientes. estilo de codificación antiguo, que a menudo implicaría un alto acoplamiento y baja cohesión. El código incorrecto es un código incorrecto, ya sea que use técnicas DI o no.