Dado un constructor que nunca tendrá que usar implementaciones diferentes de varios objetos que inicializa, ¿sigue siendo práctico usar DI? Después de todo, aún podríamos querer hacer una prueba unitaria.
La clase en cuestión inicializa algunas otras clases en su constructor y las clases que usa son bastante específicas. Nunca usará otra implementación. ¿Tenemos justificación para evitar intentar programar en una interfaz?
Respuestas:
Depende de qué tan seguro esté de que "nunca, nunca" es correcto (durante el tiempo que se utilizará su aplicación).
En general:
fuente
Si bien la ventaja de codificar en una interfaz es bastante evidente, debe preguntarse qué se gana exactamente al no hacerlo.
La siguiente pregunta es: ¿es parte de la responsabilidad de la clase en cuestión elegir las implementaciones o no? Ese puede o no ser el caso y debe actuar en consecuencia.
En última instancia, siempre existe la posibilidad de que surja alguna restricción tonta de la nada. Es posible que desee ejecutar el mismo código al mismo tiempo, y la posibilidad de inyectar la implementación podría ayudar con la sincronización. O después de perfilar su aplicación, puede descubrir que desea una estrategia de asignación diferente de la instanciación simple. O surgen inquietudes transversales y no tiene el apoyo de AOP a mano. ¿Quién sabe?
YAGNI sugiere que al escribir código, es importante no agregar nada superfluo. Una de las cosas que los programadores tienden a agregar a su código sin siquiera darse cuenta, son supuestos superfluos. Como "este método puede ser útil" o "esto nunca cambiará". Ambos agregan desorden a su diseño.
fuente
Depende de varios parámetros, pero aquí hay algunas razones por las que aún podría querer usar DI:
En pocas palabras: probablemente pueda vivir sin DI en ese caso, pero hay posibilidades de que el uso de DI termine en un código más limpio.
fuente
Cuando diseña un programa o una característica, parte del proceso de pensamiento debe ser cómo lo va a probar. La inyección de dependencia es una de las herramientas de prueba y debe considerarse como parte de la mezcla.
Los beneficios adicionales de la Inyección de dependencias y el uso de interfaces en lugar de clases también son beneficiosos cuando se extiende una aplicación, pero también se pueden adaptar al código fuente más tarde de manera bastante fácil y segura mediante la búsqueda y el reemplazo. - Incluso en proyectos muy grandes.
fuente
Muchas respuestas a esta pregunta se pueden debatir como "es posible que lo necesite porque ..." como YAGNI si no desea realizar pruebas unitarias.
Si está preguntando qué razones, además de las pruebas unitarias, requieren programar en una interfaz
Sí , la inyección de dependencia vale la pena fuera de UnitTesting si necesita una inversión de control . Por ejemplo, si la implementación de un módulo necesita otro módulo al que no se puede acceder en su capa.
Ejemplo: si tiene los módulos
gui
=>businesslayer
=>driver
=>common
.En este escenario
businesslayer
puede usardriver
perodriver
no puede usarbusinesslayer
.Si
driver
necesita alguna funcionalidad de nivel superior, puede implementar esta funcionalidad en labusinesslayer
que implementa una interfaz encommon
capa.driver
solo necesita conocer la interfaz encommon
capa.fuente
Sí, en primer lugar, olvídate de las pruebas unitarias como una razón para diseñar tu código en torno a las herramientas de prueba unitarias, nunca es una buena idea doblar el diseño de tu código para que se ajuste a una restricción artificial. Si sus herramientas lo obligan a hacerlo, obtenga mejores herramientas (por ejemplo, Microsoft Fakes / Moles que le permiten muchas más opciones para crear objetos simulados).
Por ejemplo, ¿dividiría sus clases en métodos solo públicos solo porque las herramientas de prueba no funcionan con métodos privados? (Sé que la sabiduría predominante es fingir que no es necesario probar métodos privados, pero creo que esto es una reacción a la dificultad de hacerlo con las herramientas actuales, no una reacción genuina a la no necesidad de probar pruebas privadas).
En general, todo se reduce a qué tipo de TDDer eres: el "simulacro" como los describe Fowler , necesita cambiar el código para adaptarlo a las herramientas que usa, mientras que los probadores "clásicos" crean pruebas que son más integrales en la naturaleza. (es decir, pruebe la clase como una unidad, no cada método) para que haya menos necesidad de interfaces, especialmente si utiliza las herramientas que pueden burlarse de clases concretas.
fuente
La inyección de dependencia también aclara que su objeto TIENE dependencias.
Cuando alguien más vaya a usar su objeto ingenuamente (sin mirar al constructor), descubrirá que necesitará configurar servicios, conexiones, etc. Eso no era obvio porque no tenía que pasarlos al constructor. . Pasar las dependencias deja más claro lo que se necesita.
También está ocultando potencialmente el hecho de que su clase puede estar violando SRP. Si está pasando muchas dependencias (más de 3), su clase puede estar haciendo demasiado y debería ser refactorizada. Pero si los está creando en el constructor, este olor a código se ocultará.
fuente
Estoy de acuerdo con ambos campos aquí y el asunto aún está abierto a debate en mi opinión. YAGNI exige que no aborde el cambio de mi código para que se ajuste a la suposición. Las pruebas unitarias no son un problema aquí porque creo firmemente que la dependencia nunca cambiará. Pero si comenzara a realizar las pruebas unitarias, nunca habría llegado a este punto de todos modos. Como me habría deslizado en DI finalmente.
Permítanme ofrecer otra alternativa para mi escenario específicamente
Con un patrón de fábrica puedo localizar dependencias en un solo lugar. Al probar, puedo cambiar la implementación según el contexto, y eso es lo suficientemente bueno. Esto no va en contra de YAGNI debido a los beneficios de abstraer varias construcciones de clase.
fuente