dependency injection - que - Cuándo usar la inyección de dependencia
que es inyección de dependencias en spring (8)
En los últimos días he tenido la sensación de que la inyección de dependencia realmente debería llamarse "No puedo decidirme": patrón. Sé que esto puede parecer una tontería, pero en realidad se trata del razonamiento detrás del por qué debo usar la inyección de dependencia (DI). A menudo se dice que debo usar DI, para lograr un mayor nivel de acoplamiento suelto, y obtengo esa parte. Pero realmente ... ¿con qué frecuencia cambio mi base de datos, una vez que mi elección ha caído en MS SQL o MySQL ... Muy rara vez?
¿Alguien tiene algunas razones muy convincentes para que DI sea el camino a seguir?
Acabo de entender esta noche. Para mí, la inyección de dependencia es un método para instanciar objetos que requieren una gran cantidad de parámetros para trabajar en un contexto específico.
¿Cuándo se debe utilizar la inyección de dependencia? Puede utilizar la inyección de dependencia si crea una instancia de forma estática de un objeto. Por ejemplo, si usa una clase que puede convertir objetos en un archivo XML o JSON y si solo necesita el archivo XML. Tendrá que crear una instancia del objeto y configurar muchas cosas si no utiliza la inyección de dependencia.
¿Cuándo no debes usar la inyección de depandancia? Si un objeto se instancia con parámetros de solicitud (después de un formulario de envío), no debe usar la inyección de depandancia porque el objeto no se instancia de forma estática.
Aparte del acoplamiento suelto, las pruebas de cualquier tipo se logran con mucha mayor facilidad gracias a DI. Puede reemplazar la dependencia existente de una clase en prueba con una versión simulada, ficticia o incluso otra. Si se crea una clase con sus dependencias directamente instanciadas, a menudo puede ser difícil o incluso imposible "eliminarlas" si es necesario.
Creo que vale la pena usar DI cuando tiene muchos servicios / componentes cuyas implementaciones deben seleccionarse en tiempo de ejecución en función de la configuración externa. (Tenga en cuenta que dicha configuración puede tomar la forma de un archivo XML o una combinación de anotaciones de código y clases separadas; elija lo que sea más conveniente).
De lo contrario, simplemente usaría un ServiceLocator, que es mucho más "liviano" y más fácil de entender que todo un marco DI.
Para las pruebas unitarias, prefiero usar una API simulada que puede simular objetos a pedido, en lugar de requerir que se "inyecten" en la unidad probada desde una prueba. Para Java, una de esas bibliotecas es la mía, JMockit .
DI es muy útil para desacoplar su sistema. Si todo lo que está usando es para desacoplar la implementación de la base de datos del resto de su aplicación, entonces su aplicación es bastante simple o necesita hacer un análisis mucho más amplio del dominio problemático y descubrir qué componentes dentro de su dominio problemático son los más propensos a cambiar y los componentes dentro de su sistema que tienen una gran cantidad de acoplamiento.
DI es más útil cuando busca reutilizar el código, versatilidad y robustez ante los cambios en su dominio de problemas.
La relevancia de su proyecto depende de la vida útil esperada de su código. Dependiendo del tipo de trabajo que esté haciendo, la reutilización cero de un proyecto al siguiente para la mayoría del código que está escribiendo puede ser bastante aceptable.
Un ejemplo para usar el uso de DI es crear una aplicación que se pueda implementar para varios clientes que usan DI para inyectar personalizaciones para el cliente, que también podría describirse como el patrón de la Estrategia GOF. Muchos de los patrones GOF se pueden facilitar con el uso de un marco DI.
DI es más relevante para el desarrollo de aplicaciones empresariales en las que tiene una gran cantidad de código, requisitos comerciales complicados y la expectativa (o esperanza) de que el sistema se mantendrá durante muchos años o décadas.
Dos palabras, prueba unitaria .
Una de las razones más convincentes para DI es permitir pruebas de unidad más fáciles sin tener que acceder a una base de datos y preocuparse por configurar datos de "prueba".
Incluso si no cambia la estructura de su programa durante las fases de desarrollo, descubrirá que necesita acceder a varios subsistemas desde diferentes partes de su programa. Con DI, cada una de sus clases solo necesita solicitar servicios y no tiene que proporcionar todo el cableado manualmente.
Esto realmente me ayuda a concentrarme en la interacción de las cosas en el diseño del software y no en "quién necesita llevar las cosas porque alguien más las necesita más adelante".
Además, también ahorra MUCHO trabajo escribiendo código repetitivo. ¿Necesito un singleton? Acabo de configurar una clase para ser uno. ¿Puedo probar con tal "singleton"? Sí, todavía puedo (ya que lo CONFIGURÉ para que exista solo una vez, pero la prueba puede instanciar una implementación alternativa).
Pero, por cierto, antes de usar DI, realmente no entendía su valor, pero intentarlo fue realmente revelador para mí: mis diseños están mucho más orientados a objetos como lo han estado antes. Por cierto, con la aplicación actual NO HAGO la prueba de la unidad (mala, mala), pero AÚN no pude vivir más con DI. Es mucho más fácil mover las cosas y mantener las clases pequeñas y simples.
La inyección de dependencia le brinda la capacidad de probar unidades específicas de código de forma aislada.
Digamos que tengo una clase Foo
por ejemplo, que toma una instancia de una clase Bar
en su constructor. Uno de los métodos en Foo
podría comprobar que el valor de una propiedad de Bar
es uno que permite que tenga lugar otro procesamiento de Bar
.
public class Foo
{
private Bar _bar;
public Foo(Bar bar)
{
_bar = bar;
}
public bool IsPropertyOfBarValid()
{
return _bar.SomeProperty == PropertyEnum.ValidProperty;
}
}
Ahora digamos que la Bar
está instanciada y sus propiedades están configuradas para datos de alguna fuente de datos en su constructor. ¿Cómo podría probar el método IsPropertyOfBarValid()
de Foo
(ignorando el hecho de que este es un ejemplo increíblemente simple)? Bueno, Foo
depende de la instancia de la Bar
pasa al constructor, que a su vez depende de los datos del origen de datos a los que se configuran sus propiedades. Lo que nos gustaría hacer es tener alguna forma de aislar a Foo
de los recursos de los que depende para que podamos probarlo de forma aislada.
Aquí es donde entra la inyección de dependencia. Lo que queremos es tener alguna forma de simular una instancia de Bar
pasado a Foo
para que podamos controlar las propiedades establecidas en esta Bar
falsa y lograr lo que nos propusimos hacer, probar que la implementación of IsPropertyOfBarValid()
hace lo que esperamos que haga, es decir, devuelve true cuando Bar.SomeProperty == PropertyEnum.ValidProperty
y false para cualquier otro valor.
Hay dos tipos de objetos falsos, simulacros y talones. Los apéndices proporcionan información para la aplicación bajo prueba de modo que la prueba se pueda realizar en otra cosa. Por otro lado, los simulacros proporcionan información a la prueba para decidir si pasa / falla.
Martin Fowler tiene un gran artículo sobre la diferencia entre Mocks y Stubs
Si bien estoy de acuerdo con usted con el ejemplo de DB, una de las grandes cosas que me resultó útil usar DI es ayudarme a probar la capa que construyo sobre la base de datos.
Aquí hay un ejemplo ...
Tienes tu base de datos.
Tienes tu código que accede a la base de datos y devuelve objetos.
Tiene objetos de dominio de negocios que toman los objetos del elemento anterior y hacen algo de lógica con ellos.
Si combina el acceso a los datos con la lógica del dominio de su negocio, los objetos de su dominio pueden ser difíciles de probar. DI le permite inyectar sus propios objetos de acceso a datos en su dominio para que no dependa de la base de datos para realizar pruebas o posiblemente demostraciones (ejecutó una demostración donde se extrajeron algunos datos de XML en lugar de una base de datos).
Resumir componentes y marcos de terceros como este también te ayudaría.
Aparte del ejemplo de prueba, hay algunos lugares donde se puede usar DI a través de un enfoque de Diseño por Contrato. Puede que le resulte apropiado crear un motor de procesamiento de tipos que llame a los métodos de los objetos que está inyectando en él. Si bien puede que realmente no lo "procese", ejecuta los métodos que tienen una implementación diferente en cada objeto que proporcione.
Vi un ejemplo de esto donde cada objeto de dominio de negocios tenía una función de "Guardar" que se llamaba después de que se inyectó en el procesador. El procesador modificó el componente con información de configuración y Guardar manejó el estado primario del objeto. En esencia, DI complementó la implementación del método polimórfico de los objetos que se ajustaban a la Interfaz.