2011-01-19 21 views
15

Estoy escribiendo mi segunda aplicación de la vida real, que usa DI. En general, creo que ha permitido un mejor diseño. Pero hay algunos olores de código, que no sé cómo resolver.DI: ¿Cuánto inyectar?

Prefiero usar la inyección de constructor y he observado a menudo que necesito alrededor de 5 o más objetos para ser inyectados en el constructor. Parece ser demasiado, tal vez es un problema de diseño, no obtener el SRP correcto. Pero creo que mi uso de DI también debe ser culpado.

Estoy buscando "mejores prácticas" o "regla de oro", en general parece que inyecté todo, eso no está en el framework .Net, ¿es eso exagerar?

Para comenzar, aquí hay dos ejemplos de objetos que se inyectan, pero no estoy seguro.

Los objetos que son verdaderos singletons como la configuración de la aplicación o esas pequeñas clases de utilidades, ¿los inyecta? Parece que se inyectan muy a menudo, la única razón para inyectarlos parece ser permitir cambiar el valor para la prueba, pero Ayende parece haber resuelto el problema de otra manera: http://ayende.com/Blog/archive/2008/07/07/Dealing-with-time-in-tests.aspx.

Objetos comunes como el registro, que se utilizan en casi todos los objetos, ¿deberían inyectarse?

Respuesta

3

Mi regla personal general es la siguiente:

  • inyectarlo si usted quiere que sea inmutable
  • inyectarlo si desea ser capaz de sustituirlo con fines de prueba

Las cosas como los servicios pueden cumplir ambos criterios: el consumidor nunca debe cambiarlo, y desea poder sustituirlo en el momento de la prueba. Con los elementos inmutables, aún podría tener una propiedad en el objeto consumidor, pero esa propiedad solo tendría un getter, no un setter. Si desea cambiar el valor, debe crear una nueva instancia del objeto.

¿Se deberían inyectar los registradores?

No hay ninguna razón para hacerlo. Los registradores normalmente están expuestos a través de una clase estática, y se actualizan desde las entradas de configuración, por lo que incluso para fines de prueba no hay necesidad de inyectarlos.

¿Deben inyectarse los singleton verdaderos como la configuración de la aplicación?

Una vez más, es un objeto accesible a nivel mundial que se modifica fácilmente con fines de prueba, por lo que no es necesario inyectarlo. La única vez que inyectaría esto es si el consumidor fue 'desconectado'; es decir, creado a través de reflexión o llamado como un servicio web o un objeto remoto.

Mientras DI es un patrón agradable, demasiado de algo bueno todavía puede ser poco saludable. Si detecta un olor a código creciente, examine cada artículo que está inyectando y hágase la pregunta: ¿Es NECESIDAD para inyectar este parámetro?

+2

Si accede a la configuración de la aplicación como global (o estática), entonces su clase depende de todo de ese objeto y sería difícil de usar en otro lugar. Es mejor inyectar la parte específica de la configuración que le interesa a su objeto. –

12

La regla de oro que uso a menudo es que inyecte cosas que están en el camino de escribir pruebas unitarias correctamente. Al hacer esto, a veces terminarás abstrayendo clases BCL (como DateTime.Ahora, Archivo, etc.), y algunas veces sus propias cosas. Las cosas buenas para inyectar son los servicios (como ICustomerService, ICustomerUnitOfWorkFactory o ICustomerRepository). No inyecte cosas como entidades, DTO y mensajes.

Sin embargo, existen otras razones para inyectar objetos, como ser capaz de reemplazar módulos en otro momento (por ejemplo, cambiar implementaciones para validación, UI u O/RM), para permitir el desarrollo paralelo dentro o entre equipos, y para reducir el mantenimiento.

Yo prefiero usar inyección de constructor y, a menudo han observado que necesito aproximadamente 5 o más objetos a ser inyectado en el constructor.

Como ya se dio cuenta, tener muchas dependencias podría deberse a que no se adhirió al SRP. Sin embargo, lo que puede hacer es agrupar las dependencias comunes con su lógica en un servicio agregado e inyectar eso en los consumidores. También vea el artículo de Mark Seemann sobre Aggregate Services.

Los objetos que son verdaderos hijos únicos como configuración de la aplicación o los clases pequeñas util, hacen que se inyecte ellos?

Personalmente, no soy seguidor de la manera en que Ayende lo propone. Este es un Ambient Context, que es un tipo específico de constructo service locator. Hacer esto oculta la dependencia, porque las clases pueden llamar a esa clase estática sin tener que inyectarla. Inyectar explícitamente hace que sea mucho más claro que necesita tiempo de prueba unitaria. Además de eso, hace difícil escribir pruebas para frameworks como MSTest que tienden a ejecutar pruebas en paralelo. Sin ninguna contramedida, hace que sus pruebas sean muy poco confiables. Una mejor solución -para el ejemplo DateTime.Now- es tener una interfaz IClock, como se sugiere here. Como puede ver, esa respuesta puntúa mucho más que el enfoque Ayende, que se muestra en la misma pregunta SO.

objetos comunes como la tala, que se utilizan en casi todos los objetos, caso de que se inyectan?

Los inyecté en mi código, porque eso hace que las dependencias sean claras. Sin embargo, tenga en cuenta que en mi código casi nunca tengo que inyectar un registrador. Piense con firmeza en cada línea que quiera registrar y no sea realmente una falla (o una preocupación transversal que deba incluirse en otra parte). Normalmente lanzo una excepción cuando sucedió algo que no esperaba. Me permite encontrar errores rápidamente. O para decirlo en otras palabras: no filtrar, pero fallar rápido. Y por favor pregúntese: "Do I log too much?"

Espero que esto ayude.

3

Un buen punto de partida es inyectar Volatile Dependencies.

Es posible que también desee inyectar dependencias estables para un mayor acoplamiento libre, pero si necesita priorizar, Dependencias volátiles es el mejor lugar para comenzar.

En cuanto constructor de sobre-inyección, no deja de ser un síntoma de romper SRP: ver esta pregunta relacionada: How to avoid Dependency Injection constructor madness?