Ya he escrito sobre el principio de inversión de dependencia anteriormente y había comentado que para mí es el principio más importante, bien pues en este artículo vamos a profundizar en el principio para entender bien porque pienso de esta forma.
La inversión de dependencia bien aplicada da una flexibilidad y estabilidad a nivel de arquitectura entera de tu aplicación. Va a permitir que tu aplicación evolucione de forma más segura y estable.
Arquitectura en capas tradicional
Antes del principio, tradicionalmente en una arquitectura en capas la interfaz de usuario dependía de la capa de negocio y esta a su vez dependía de la capa de acceso de datos.
Hay que entender capa por paquete o librería. Veamos como quedaría el código.
Tendríamos una librería o paquete para la capa de acceso a datos.
// DataAccessLayer.dll
public class ProductDAO {
}
Y otra librería o paquete para la capa de lógica de negocio que depende de la capa de acceso a datos.
// BusinessLogicLayer.dll
using DataAccessLayer;
public class ProductBO {
private ProductDAO productDAO;
}
Arquitectura en capas con inversión de dependencia
La inversión de dependencia indica lo siguiente:
Los módulos de alto nivel no deberían depender de los de bajo nivel, ambos deberían depender de abstracciones.
Las abstracciones no deben depender de los detalles, los detalles deben depender de las abstracciones.
¿Cuales son los módulos de alto nivel y los de bajo nivel?
Pensando en módulos como librerías o paquetes, módulo de alto nivel serían aquellos que tradicionalmente tienen dependencias y los de bajo nivel de los que dependen.
Dicho de otra forma módulo de alto nivel seria donde se invoca la acción y de bajo nivel donde se realiza la acción.
Una conclusión razonable a sacar de este principio es que no debe existir una dependencia entre concreciones sino que se debe depender de una abstracción. Pero según el enfoque que le demos podemos estar aplicando mal la inversión de dependencia aunque dependamos de una abstracción.
Imaginemos que adaptamos nuestro código así:
Tendríamos una librería o paquete para la capa de acceso a datos donde definimos la abstracción.
// DataAccessLayer.dll
public interface IProductDAO
public class ProductDAO : IProductDAO{
}
Y otra librería o paquete para la capa de lógica de negocio que depende de la capa de acceso a datos.
// BusinessLogicLayer.dll
using DataAccessLayer;
public class ProductBO {
private IProductDAO productDAO;
}
Aunque estemos dependiendo de una abstracción la dependencia entre negocio y acceso a datos sigue siendo la misma.
Para conseguir invertir la dependencia, la interfaz de persistencia debe estar definida en el módulo o paquete de alto nivel donde esta la lógica o dominio y no en el módulo de bajo nivel.
Lo que primero se define es la capa de dominio y en ella se define la abstracción de comunicación con la persistencia.
// Domain.dll
public interface IProductRepository;
using DataAccessLayer;
public class ProductBO {
private IProductRepository productRepository;
}
Después se define la capa persistencia que depende del dominio, consiguiendo ahora si invertir la dependencia.
// Persistence.dll
public class ProductDAO : IProductRepository{
}
Profundizando en el principio
Es importante que asimilemos bien el concepto profundizando en el objetivo y las ventajas. Si nos quedamos en aprender mecánicamente el caso típico de repositorio no vamos a ser capaces de identificar cuando podemos aplicar el principio de dependencia.
¿Pero porque invertimos la dependencia? ¿cual es el objetivo principal más allá de ejemplos concretos?
Dicho vulgarmente permite que las cosas más estables no dependan de las cosas menos estables que van a cambiar con mayor frecuencia.
Es más fácil que se cambie el tipo de persistencia, ya sea la base de datos o la tecnología de acceso a la misma base de datos que la lógica de dominio o las acciones definidas para comunicarse con la persistencia. Por este motivo se invierte la dependencia porque como es más fácil que cambie la persistencia, si este cambio se produce, de esta forma conseguimos que no tengamos que cambiar el dominio. La capa de domino es la más estable de todas por eso no debe depender de nada.
Pero no solo existe este ejemplo de repositorio, hay multitud de escenarios donde aplica este principio y hay arquitecturas basadas en este principio.
Arquitecturas basadas en la inversión de dependencia
Existen arquitecturas donde la inversión de dependencia es clave en su definición, en todas el dominio es lo más importante y en él se definen las abstracciones que van a indicar el protocolo de comunicación entre el dominio y el resto de los paquetes o librerías.
Clean Architecture
En Clean architecture el dominio se sitúa en el centro y si te fijas en la dirección de las flechas, que indican la dependencia, se ve claramente cuales son las capas más importantes y estables, las capas exteriores son consideradas herramientas más inestables por eso se evita depender de ellas.
Hexagonal Architecture
Sucede de la misma forma en Hexagonal Architecture, donde el dominio se sitúa también en la parte central y los puertos son las abstracciones de comunicación desde el domino hacia el exterior. Aquí de nuevo queda en evidencia que el domino es la parte más estable y la dependencia tradicional es invertida.
Curso y artículos relacionados
Conclusiones
En importante interiorizar porque se utiliza el principio de inversión de dependencias más allá de aprenderse mecánicamente ejemplos comunes que puedas encontrar por internet o en libros. En este artículo hemos profundizado en este sentido y espero que haya quedado claro.