Muchas veces mientras divagamos entre conceptos de Diseño de Software nos encontramos con terminologías que, si bien están bastamente documentadas, siguen tendiendo a la confusión entre los desarrolladores. El objetivo de este post es explicar dos patrones relacionados que tienden a confundirse el uno con el otro: Inversion of Control (IoC) y Dependency Injection (DI).
Inversion of Control (IoC): Delegando responsabilidades
Se refiere a todo aquel diseño de software cuyo propósito obedece a la necesidad de querer controlar el flujo de ejecución de este, de forma automática y transparente, es decir, ceder el control de ese flujo a un “agente externo”, normalmente un framework. He aquí el concepto de Inversion of Control.
Si solo ahondamos apenas un poquito en algunas de las herramientas que utilizamos en nuestro desarrollo, nos daremos cuenta que este patrón de diseño está presente en múltiples ocasiones facilitándonos enormemente el trabajo.
Los desarrolladores .Net utilizamos este paradigma continuamente sin darnos cuenta dado que utilizamos el Framework .Net el cual resuelve el ciclo de vida de las aplicaciones. Por ejemplo, cuando utilizamos Windows Forms, .Net gestiona los eventos, cuando utilizamos los helpers de MVC y una larga lista de componentes que daría para escribir otro post.
Dependency Injection (DI): Inyectando componentes
DI es un patrón de diseño que sirve para “inyectar” componentes a las clases que tenemos implementadas. Esos componentes son contratos que necesitan nuestras clases para poder funcionar, de ahí el concepto de “dependencia”. La diferencia sustancial en este patrón de diseño es que nuestras clases no crearán esos objetos que necesitan, sino que se les suministrará otra clase “contenedora” perteneciente al Framework DI que estemos utilizando y que inyectarán la implementación deseada a nuestro contrato, y todo ello sin tener que hacer un solo “new”.
Todo esto está muy bien, pero en algún momento podemos pensar: ¿por qué necesito que otra clase me suministre los objetos?
DI y las bondades del bajo acoplamiento
Pese a que la inyección de dependencias puede realizarse referenciando directamente las clases de dichas dependencias, esa no es una buena práctica dado que sus componentes tienen una fuerte relación entre sí, que al final nos supondrá un inconveniente para poder mantener nuestro software. Para resolver ese problema normalmente los frameworks DI utilizan en la inyección de dependencias Interfaces entre componentes.
Al componer esa relación entre interfaces conseguimos abstraer la relación entre una clase A que depende de una clase B sin importar la implementación de cada uno de los dos. A ese concepto le llamamos desacoplamiento y está presente en el mandato DIP (Dependency Injection Principle) de los cinco que componen los principios SOLID.
Evitar propagación de errores:
El poco acoplamiento nos permite tener la relación entre nuestras clases separadas por capas de abstracción (Interfaces). Por lo tanto, al no tener una relación directa entre los diferentes módulos de nuestro software evitamos que un cambio interno en uno de ellos afecte a toda la aplicación, de ese modo podemos arreglar el problema directamente cambiando las lineas de implementación conflictivas de la clase en cuestión.
Reutilización modular:
Con la inyección de dependencias podemos reutilizar nuestros componentes en toda la aplicación debido a su poco acoplamiento. Con esa premisa nos obligamos a programar nuestras clases bajo el llamado “Single Responsability Principle” concretando así el principio de única responsabilidad en el comportamiento de una clase, haciendo de esta un componente más reutilizable.
Mejor UNIT TESTING:
El “Single Responsability Principle” de SOLID, nos ayudará a testear mejor nuestras clases y el uso de interfaces nos ayudará a resolver implementaciones que en un momento dado deban ser diferentes para ejecutar los tests de una forma más eficiente, como por ejemplo el hecho de utilizar una clase que se conecte a una base de datos y por ello nos suponga una penalización en el tiempo de ejecución del test. Como tenemos una interfaz que abstrae la clase que conecta a la base de datos, en un momento dado cambiamos la implementación por una instanciación de una clase “Mock” o “Fake” y hacemos correr el test sin menor complicación.
Buenas prácticas:
Cuando utilizamos un framework DI nos obliga a implementar, tal y como he mencionado antes, el Dependency Injection Principle, que nos obliga a abstraer la relación entre clases con Interfaces, haciendo de nuestro código más mantenible y escalable.
Ejemplo de registro de los componentes en el objeto contenedor DI…
Ejemplo de instanciación de los componentes en controlador…
Conclusión:
Mientras desarrollamos código, utilizamos patrones de diseño de forma más o menos intencionada. Si nos fijamos bien, nos daremos cuenta que la naturaleza funcional de estos patrones no está alejada unos de otros, sino que a menudo se fusionan entre sí. Por ejemplo podemos utilizar un patrón Service Locator y ver que en realidad utiliza el patrón Dependency Injection y que ambos, a su vez, tienen de forma inherente el patrón IoC.
En conclusión, estos dos conceptos tienen relación entre sí pero no de forma simétrica. En programación orientada a objetos hay varias formas de implementar el patrón IoC uno de ellos es la Inyección de dependencias, pero no todo patrón IoC es Inyección de dependencias.
Hay varios Frameworks DI disponibles para que utilicemos en nuestros proyectos .Net dejo una lista aquí de la página de Scott Hanselman:
http://www.hanselman.com/blog/ListOfNETDependencyInjectionContainersIOC.aspx
Referencias:
- http://www.hanselman.com/blog/ListOfNETDependencyInjectionContainersIOC.aspx
- http://www.c-sharpcorner.com/uploadfile/shivprasadk/di-and-ioc/
- https://en.wikipedia.org/wiki/Dependency_injection
- https://en.wikipedia.org/wiki/Inversion_of HYPERLINK
- https://en.wikipedia.org/wiki/Inversion_of_control#Implementation_techniques» HYPERLINK
- https://en.wikipedia.org/wiki/Inversion_of_control#Implementation_techniques» HYPERLINK
- https://en.wikipedia.org/wiki/Inversion_of_control#Implementation_techniques»_control#Implementation_techniques
- http://codecriticon.com/dependencia-inyeccion-dummies/
Eduard Moret es técnico superior en desarrollo de aplicaciones informáticas y actualmente especializado en tecnología .Net. Amante de la computación gráfica y la programación, Eduard se incorporó a Sogeti en 2015. Actualmente desempeña su labor en la empresa como programador Junior.
Una aclaración: DIP no se refiere a Dependency Injection Principle, sino a: Dependency Inversion Principle
Me gustaMe gusta
Muy buen aporte, me sirvió bastante
Me gustaMe gusta
Pingback: “Easy Factories” con Castle Windsor | itblogsogeti