¿Por dónde empezamos hoy? Pues si conocemos de antemano la arquitectura DDD, sabremos que uno de los aspectos más importante en su implementación es la inyección de dependencia.
El concepto de aplicaciones orientadas al dominio explica claramente que debemos aislar la lógica del dominio de cualquier tipo de detalle técnico.
La “Guía de arquitectura N-capas orientada al dominio” nos dice…
“Esta capa debe ser responsable de representar conceptos de negocio, información sobre la situación de los procesos de negocio e implementación de las reglas del dominio. También debe contener los estados que refleja n la situación de los procesos de negocio, aun cuando los detalles técnicos se delegan a las capas inferiores….”
Resumiendo un poco, el dominio debe saber “Qué” se hace, pero nunca “Cómo” se hace…
Por otro lado, el concepto de una interfaz es un contrato que indica lo que se debe hacer, pero nunca incluye código de cómo se debe hacer… De aquí, que la forma de aislar el dominio en una arquitectura DDD de su implementación, sea mediante interfaces.
La importancia de la inyección de dependencia en este tipo de arquitectura es precisamente esta, inyectar instancias de objetos que saben “cómo” hacer algo mediante interfaces que indican “qué” se debe hacer. Es lógico que los objetos que se inyecten deban implementar la interfaz, pero si no lo hacen ya se encargará el framework de avisarnos con un ruidoso error.
Para usar inyección de dependencia existen muchos frameworks. Algunos de ellos son:
– Ninject
– Unity
– Castle.Windsor
– Autofac
– StructureMap
Aquí encontraras un buen debate sobre cuál es mejor o peor o cuáles son sus ventajas o desventajas.
http://stackoverflow.com/questions/4581791/how-do-the-major-c-sharp-di-ioc-frameworks-compare
A mí en esta parte siempre me entra la duda, si hablamos de un dominio que no es afectado por los detalles técnicos entonces, ¿debería preocuparme por saber cuál debe ser el Framework que usaré para inyectar dependencias? Bueno, tampoco pasemos olímpicamente de esto, claro que debía preocuparme por temas de performance… pero estos frameworks evolucionan y el que es mejor hoy, mañana puede ser peor.
¿Qué hago entonces? ¿Pues no les gustaría poder inyectar a quien te inyecta? ¿Nunca han querido pagar con la misma moneda? Yo decidí inyectar el framework de inyección…
De lo que hemos visto, el objetivo para mí de un Framework de inyección de dependencia es precisamente retornarme una instancia de un objeto mediante su interfaz. Entonces, lo que necesito sería algo como esto:
public interface IContainer
{
void InitializeContainer();
T GetInstanceOf<T>();
T GetInstanceOf<T, TParamType>(TParamType paramInjection);
}
Ahora necesito algún elemento de configuración que me indique cómo instanciar mi framework de IoC. ¿De dónde sale la configuración? Pues no lo sé, lo que realmente me importa es su contrato, no cómo lo haga. La interfaz para la configuración contiene una propiedad que me retorna el QualifiedName usado para crear el tipo concreto del framework de IoC.
public interface IContainerConfiguration
{
string IocQualifiedName { get; set; }
Type IocObjectType { get; }
}
Para combinar el Container con su configuración nos implementamos un Factory:
public sealed class IocFactory
{
public IContainer Create(IContainerConfiguration cfg)
{
var container = (IContainer)Activator.CreateInstance(cfg.IocObjectType);
container.InitializeContainer();
return container;
}
}
Hasta aquí ya tenemos definidas las interfaces… pero ¿quién implementa estas interfaces? y lo más importante, ¿cómo se usaría al final?
Cada aplicación que hago, “debería” tener aspectos que son generales a nivel de toda la aplicación. Me refiero a parámetros cómo:
– Formato de fecha que usaré por defecto
– Idioma que usaré por defecto
– Zona horaria en que se encuentra la aplicación
Estos parámetros son un poco a mi gusto personal, quiero olvidarme de si el formato de fecha/Hora tiene que ser o no independiente al idioma o si el servidor donde hospedo la aplicación está en América o el viejo continente, por eso predefino este tipo de datos. A estos parámetros se suma ahora mi Framework de IoC, que también será de uso general por toda la aplicación.
Cómo hemos repetido durante todo el artículo, en este punto no sé de dónde saldrá esta información. A algunos les será más útil sacarlo de base de datos y a otros del archivo de configuración de la aplicación, así que sigo creando interfaces.
public interface IAppConfigurationElement
{
string Name { get; set; }
string DateTimeFormat { get; set; }
string LanguageDefault { get; set; }
double TimeZoneOffset { get; set; }
}
Esta interfaz define los parámetros generales de mi aplicación. En la siguiente interfaz, combinamos estos parámetros de configuración con la interfaz de IoC.
public interface IAppConfigurationSection
{
IAppConfigurationElement Parameters { get; set; }
IContainerConfiguration Ioc { get; set; }
}
Finalmente combinamos las interfaces que darán a nuestra aplicación los parámetros que hemos definido y el Framework de IoC que usaremos
public interface IGlobalSettings
{
IContainer Ioc { get; }
IAppConfigurationElement Parameters { get; }
}
Con esto mejor cerramos el artículo de hoy, creo que me he pasado de largo así que dejamos la implementación y los test para otro día…
Hasta la próxima…