Dependencias

Voy a intentar explicar los conceptos Dependency Injection (Inyección de dependencias) y Dependency Inversion (Inversión de dependencias) de una manera fácil. Voy a omitir todos los detalles irrelevantes para explicar los conceptos y usaré ejemplos muy básicos.

Imagina que tienes un código como este:

Consumer depende de un objeto de tipo DataBase (clase concreta) y le hace una consulta para devolver los items. Ahora nuestro objetivo es hacer un test unitario para saber si Consumer devuelve Items. Sería algo así:

¿Fácil, no? Bueno, los tests unitarios deben ser rápidos de ejecutar (además de otras características). Imagina que nuestro objeto DataBase tarda mucho en devolver los items (tiene que leer del disco etc…). Es la implemetación real de nuestra base de datos en producción. ¿Qué hacemos?

En esta situación lo ideal sería que pudieramos cambiar ese DataBase por algo más ligero a la hora de hacer el test (un DataBase en memoria, por ejemplo), pero tenemos un problema: Consumer está creando la instancia de DataBase por si mismo.

Para solucionarlo vamos a inyectar la dependencia (en este caso, mediante el constructor de la clase). El código quedaría tal que así:

Y eso es Dependency Injection: acabamos de inyectar la dependencia a Consumer a través de su constructor y ahora ya no crea su propia instancia. Ahora, ya podríamos hacer lo siguiente en el test:

Pero… ¿y qué ganamos con esto? Bueno, pues ahora tenemos varias opciones:

  1. Podemos hacer una subclase de DataBase, sobreescribir los métodos para que no lea en disco, y que devuelva los items que quieras. Esta estrategia se conoce como Subclass and override. Con esto conseguiríamos nuestro objetivo.
  2. Aplicar la estrategia Extract Interface, consiguiendo con eso nuestra siguiente meta: entender Dependency Inversion

Vamos con la segunda opción, que es la que nos interesa. Según la definición de Dependency Inversion tenemos que:

A. Módulos de alto nivel no deben de depender de módulos de bajo nivel. Los dos deben de depender de abstracciones.

B. Abstracciones no deben de depender de los detalles. Los detalles deben de depender de abstracciones.

¿Qué quiere decir esto? En nuestro caso, nuestra clase Consumer depende de DataBase (detalle de implementación), y si seguimos el principio, lo estamos incumpliendo.

Por tanto, el siguiente paso sería hacer que nuestro Consumer no dependiera de un detalle de implementación, y esto lo conseguimos con una abstracción, según la definición. En el caso de Swift usaremos un protocolo:

Ahora Consumer depende de una abstracción, DataBaseProtocol. Vale, y ahora ¿qué? Ahora DataBase solo tendría que conformar el protocolo, y ya podríamos usarla como dependencia de Consumer.

Y ahora que tenemos los elementos, vamos a continuar con nuestro objetivo: testear la clase Consumer. Una de las cosas que nos permite la inversión de dependencias, es que nos permite testear más fácilmente. Lo único que tenemos que hacer es crear una implementación “falsa” de nuestra DataBase, que conforme el protocolo:

Y ahora ya podemos usarla en nuestro test y comprobar que Consumer devuelve los items:


Recapitulación:

  1. Queríamos testear la clase Consumer. Tenía una dependencía de la que nos queríamos aislar porque tardaba mucho en nuestros tests.
  2. Aprendimos que podiamos “inyectar” esa dependencia, para poderla “modificar o sustituir”, a la hora de hacer nuestro test. En nuestro caso lo hicimos a través del constructor de la clase Consumer.
  3. Aprendimos la definición de Dependency Inversion y lo aplicamos a nuestra clase Consumer.
  4. Esto nos facilitó poder crear una “falsa” DataBase para sustituirla en nuestro test y así aislarnos de la implementación real.

He obviado muchos detalles (como que en el test no sabemos si Consumer le está preguntando a la instancia de dataBase o no,…) y muchas razones por las que usar Dependency Injection y Dependency Inversion ademas de las comentadas, pero espero que con este simple ejemplo te haya servido para entender al menos, sobre que tratan esos dos conceptos.

Like what you read? Give Pedro Cid a round of applause.

From a quick cheer to a standing ovation, clap to show how much you enjoyed this story.