Colocación aceptable de la raíz de la composición utilizando contenedores de inyección de dependencia (DI) e inversión de control (IoC)

8

He leído en varias fuentes, incluido el blog 'Ploeh' de Mark Seemann, acerca de cómo la ubicación adecuada de la raíz de composición de un contenedor de IoC está lo más cerca posible del punto de entrada de una aplicación.

En el mundo .NET, estas aplicaciones parecen ser comúnmente consideradas como proyectos web, proyectos WPF, aplicaciones de consola, cosas con una interfaz de usuario típica (léase: no proyectos de biblioteca).

¿Va realmente en contra de este sabio consejo colocar la raíz de composición en el punto de entrada de un proyecto de biblioteca, cuando representa el punto de entrada lógico de un grupo de proyectos de biblioteca, y el cliente de un grupo de proyecto como este es el trabajo de otra persona? , cuyo autor no puede o no agregará la raíz de la composición a su proyecto (un proyecto de IU u otro proyecto de biblioteca, incluso)?

Estoy familiarizado con Ninject como una implementación de contenedor IoC, pero imagino que muchos otros funcionan de la misma manera, ya que pueden escanear en busca de un módulo que contenga todas las configuraciones de enlace necesarias. Esto significa que podría poner un módulo de enlace en su propio proyecto de biblioteca para compilarlo con la salida de mi proyecto de biblioteca principal, y si el cliente quisiera cambiar la configuración (un escenario poco probable en mi caso), podrían colocar un dll de reemplazo para reemplazar el biblioteca con el módulo de enlace.

Esto parece evitar que los clientes más comunes tengan que lidiar con la inyección de dependencia y las raíces de composición, y sería la API más limpia para el grupo de proyectos de la biblioteca.

Sin embargo, esto parece ir en contra de la sabiduría convencional sobre el tema. ¿Es solo que la mayoría de los consejos por ahí suponen que el desarrollador también tiene cierta coordinación con el desarrollo de los proyectos de IU, en lugar de mi caso, en el que solo estoy desarrollando bibliotecas para que otros los usen?

Jeff
fuente

Respuestas:

2

Su enfoque de módulo vinculante es la mejor solución. Si es poco probable que el cliente cambie la configuración, el uso de DI es cuestionable, específicamente para su biblioteca.

Si desea crear una biblioteca para su lanzamiento al público, es probable que no desee que los clientes se ocupen de la complejidad o rigidez del sistema DI particular que prefiere en este momento. Las bibliotecas son mejores cuando son componentes de nivel inferior que se pueden utilizar sin muchas dependencias o una amplia capacitación. Cualquier sistema DI que seleccione cambiará con el tiempo y puede volverse incompatible con las aplicaciones del cliente.

Frank Hileman
fuente
2

Se supone que una biblioteca es un cuadro negro con una API limpia específica del dominio. No hay ningún problema con el uso de las herramientas o patrones que necesita dentro de una biblioteca, incluida DI, siempre que no se filtre al cliente y lo limite de alguna manera.

Si es necesario proporcionar extensibilidad o cambios en la configuración de la biblioteca, aún se puede hacer sin compartir una sola raíz de composición entre la biblioteca y el cliente.

Si puede justificar su biblioteca en función de otra biblioteca de terceros solo para implementar DI en su biblioteca, es un tema diferente, pero tenga en cuenta que el patrón DI en sí puede implementarse sin ninguna dependencia.

astreltsov
fuente
-1

Si está desarrollando bibliotecas (no aplicaciones) para que otras personas las usen, entonces aún debe implementar la inyección de dependencia. Para mí, el término "inyección de dependencia" es solo un conjunto de prácticas que conducen a una mejor separación de las preocupaciones y un acoplamiento flojo. Esto es lo que hace que su biblioteca esté bien estructurada y sea fácilmente comprobable (la mayoría de las veces).

Con respecto al contenedor de IoC, no veo ningún daño en tener el contenedor de IoC en el proyecto de la biblioteca. En algún lugar, tendrá una raíz de composición (un punto de entrada) en su biblioteca, por lo que para mí tiene mucho sentido conectar sus dependencias en la raíz de composición. Cómo lo haces depende completamente de ti.

Como ejemplo, recientemente he usado una biblioteca para capturar firmas y una biblioteca para escanear códigos de barras. Ambos eran bibliotecas de interoperabilidad simples (contenedores COM). Cada biblioteca requería que lo inicializara antes de que pudiera hacer algo. Por ejemplo:

var isReady = _signatureCapture.Initialise()
if (isReady)
{
   // Do stuff
}

La biblioteca de escaneo de códigos de barras fue muy similar:

_scanner.Initialise();
_scanner.OnScan += OnScanHandler;

He estado usando ambas bibliotecas y no tengo idea de si usan el contenedor IoC o no. Sin embargo, sé que los puntos de entrada a la biblioteca están en los Initialisemétodos. Supongo que todas las dependencias están conectadas en el Initialisemétodo, que sirve como una raíz de composición.

Si le preocupa confiar en un contenedor de IoC de un tercero, puede utilizar su propia implementación, mucho más simplificada. Los desarrolladores a menudo se preocupan de que la biblioteca se vuelva obsoleta o sea reemplazada por algo mejor, pero en realidad aún no he visto un proyecto en el que el equipo decidiera cambiar un contenedor de IoC por el otro.

CodeART
fuente
44
Las bibliotecas deben evitar dependencias innecesarias. Excepto en el caso de una biblioteca muy compleja, que se parece más a una aplicación, la mayoría de los usuarios de la biblioteca no querrán depender de una implementación DI particular.
Frank Hileman
-2

La belleza de las bibliotecas externas es que deberían hacer lo que sea que digan que harían, al tiempo que exponen una interfaz simple y directa. Lo complejo que sea realmente hacerlo, no debería ser asunto del desarrollador que lo implementa. Si DI realmente hace que el trabajo del desarrollador de API sea menos complejo, entonces tiene 100% de sentido usarlo, siempre que se use correctamente y su módulo se declare en el punto de entrada de la API. Al desarrollar una aplicación MVC recientemente, abstraje la capa de datos utilizando un patrón de repositorio y aún más abstrayendo colocando una capa de servicio entre la aplicación MVC y la capa de repositorio, ambos proyectos de Class Library. Tenía una interfaz ICache asignada a una clase de caché para mi contexto de servicio. Inicialmente lo implementé usando MVC.Web.Cache, pero en una iteración posterior lo cambié por System.runtime. caché y solo puedes imaginar cuán grande habría sido la escala de ese Refactor sin mi DI de uso. Entonces mi consejo; "Ve a por ello".

abdulgafar jagun
fuente
esta publicación es bastante difícil de leer (muro de texto). ¿Te importaría editarlo en una mejor forma?
mosquito