DDD: 2- Framework de IoC (Service Pack 1)

Después de la última sacudida recibida Sad smile por la encapsulación del Container que hicimos en el artículo anterior, sacamos este Service Pack 1 Smile y de paso cuento un poco cómo llegamos aquí.

Cuando me pasan estas cosas, siempre recuerdo el pasaje de una lectura que tengo por casa…

“Denis Cochin preparo un estudio sobre Química y lo presento a Pasteur. El trabajo comenzaba con las palabras. “Se sabe que…“

– ¿Que es lo que se sabe? – Interrumpió Pasteur al leerlo. – No se sabe nada.
– Pero señor – Contesto Cochin – lo que iba a citar es un trabajo de usted.

– No importa – replico Pasteur. – Yo podría haberme equivocado. Empiece Ud. de nuevo”

Tras los comentarios de Unai y Eduard más la referencia al artículo de Mark sobre el patrón o anti-patrón Service-Locator (Martin Fowler, 2004), había que profundizar más en el tema, así que sin pensarlo dos veces me compré el libro de “Dependency Injection in .NET” el cual recomiendo muchísimo por la claridad en el contenido, además de estar orientado directamente a NET.

En el libro, cuando Mark habla del Service Locator como un anti-patrón, dice: “Some people consider it a proper design pattern, whereas others (me included) consider it an anti-pattern.”

Tras esta definición no puedo evitar preguntarme ¿Y en qué bando me pongo yo? Es evidente que la opinión de Eduard, Unai, Mark y seguramente la de muchos otros, pesa muchísimo, así que lo más probable es que termine más rápido si busco alguna deficiencia en la implementación anterior que me lleve finalmente a verlo como ellos.

Tras no mucho tiempo… me imaginé la siguiente situación:

Tengo varios controladores (MVC) que usan inyección de dependencia con uno o varios servicios (Application services), tengo servicios que usan dependencias a uno o más repositorios, tengo varios repositorios que usan dependencia a una unidad de trabajo, tengo una unidad de trabajo que depende de una cadena de conexión. En esa situación, tendré en mis controladores llamadas al Resolve del container para crear los servicios, en los servicios llamadas al Resolve para crear instancias de los repositorios, tendré también llamadas al Resolve en los repositorios para recuperar la unidad de trabajo y así en toda mi arquitectura…

Salta a simple vista que mis controladores dependen de mis servicios y del Service Locator. Los servicios dependen de los repositorios y del Service Locator, los repositorios dependen de la unidad de trabajo y del Service Locator. ¿Qué pasa si quiero reutilizar los repositorios? ¿O si quiero reutilizar los servicios? ¿O si quiero reutilizar mi unidad de trabajo? Pues que en todo momento dependeré del Service Locator…

Sad smile No seguí buscando… mi objetivo era estar desacoplado del Framework de IoC y terminé atando toda la arquitectura.

¿Cómo soluciono esto entonces?

-Constructor Inyection
-Property Injection
-…

Si mis controladores recibieran los servicios que necesitan para trabajar mediante el constructor, no necesitaría una referencia al Service Locator… y lo mismo pasa en toda la cadena de inyección.

¿Cómo funciona esto? Imaginen que tengo…

Controller(IService srv) – Service(IRepository repo) – Repository(IUnitofWork uow) – UnitOfWork()

1- Un controlador necesita una instancia de un servicio, se intenta crear una instancia de ese servicio.
2- Para crear el servicio se necesita un repositorio, se intenta crear una instancia del repositorio.
3- Para crear el repositorio se necesita una unidad de trabajo, se intenta crear la unidad de trabajo.
4- Se crea la unidad de trabajo (no depende de nadie).
5- A partir de aquí, se inyecta la unidad de trabajo al repositorio, el repositorio al servicio y el servicio al controlador.

Este algoritmo me dice que todo empieza desde un punto único. A este punto Mark lo llama Composition Root. “A COMPOSITION ROOT is a (preferably) unique location in an application where modules are composed together.”

Un DI Container es quien me dice quién es el Container utilizado en mi aplicación y el encargado de componer todo el grafo de objetos. Este debe ser referenciado únicamente desde el Composition root (De aquí que Eduard y Unai no vean la necesidad de abstraer el Container) y se inicializa solo una vez en todo el ciclo de vida de la aplicación.

Conociendo un poco más que ayer, decidí hacer “refactoring” a todo lo visto ayer (Por llamarle de una forma menos dura al hecho de borrar todas las interfaces e implementaciones de mi Service Locator). Después de un rato, me quedó esto:

Mi DI Container. …

public static class UnityContainerFactory
{
    private static readonly IUnityContainer _container;

    static UnityContainerFactory()
    {
        _container = new UnityContainer();
        Configure();
    }

    private static void Configure()
    {
        var section = (UnityConfigurationSection)ConfigurationManager.GetSection("unity");
        section.Configure(_container);

        // Aditional Configuration
        // Container.RegisterType<IBaseType, ModuleAType>("moduleA")
        // Container.RegisterType<IBaseType, ModuleBType>("moduleB")
    }

    public static IUnityContainer GetContainer()
    {
        return _container;
    }

}

¿Quién sería mi Composition Root? Pues ya esto depende del tipo de aplicación que se vaya a crear, ya que cada aplicación puede tener una definición diferente para su “único punto de entrada”. Por ejemplo, para una aplicación MVC, Mark aconseja un IControllerFactory, aunque si es para MVC3, yo prefiero el IDependencyResolver.

Mi Composition Root para MVC3 sería:

public class UnityDependencyResolver : IDependencyResolver
{
        private readonly IUnityContainer _container;

        #region Implementation of IDependencyResolver

        public UnityDependencyResolver(IUnityContainer container)
        {
            _container = container;
        }

        public object GetService(Type serviceType)
        {
            return _container.IsRegistered(serviceType) ? _container.Resolve(serviceType) : null;
        }

        public IEnumerable<object> GetServices(Type serviceType)
        {
            return _container.ResolveAll<object>().Where(s => s.GetType() == serviceType);
        }
}

Aquí puedes encontrar un pequeño post de Steve explicando la implementación anterior.

Para el caso de un servicio WCF me gustó la forma en que lo implementaron en la guía de arquitectura N Layer donde se implementa la interfaz IInstanceProvider:

public class UnityDependencyProvider : IInstanceProvider
{
    private readonly IUnityContainer _container;
    private readonly Type _serviceType;

    public UnityDependencyProvider(Type serviceType)
    {
        if (serviceType == null) throw new ArgumentNullException("serviceType");

        _serviceType = serviceType;
        _container = UnityContainerFactory.GetContainer();          
    }

    #region Implementation of IInstanceProvider

    public object GetInstance(InstanceContext instanceContext)
    {
        return GetInstance(instanceContext, null);
    }

    public object GetInstance(InstanceContext instanceContext, Message message)
    {
        return _container.Resolve(_serviceType);
    }

    public void ReleaseInstance(InstanceContext instanceContext, object instance)
    {
        if (instance is IDisposable) ((IDisposable)instance).Dispose();
    }

    #endregion
}

Y luego creamos el atributo con el que marcaremos los servicios WCF que necesiten inyección de dependencias…

public class UnityDependencyProviderServiceBehavior : Attribute, IServiceBehavior
{
    #region Implementation of IServiceBehavior

    public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
    {
    }

    public void AddBindingParameters(ServiceDescription serviceDescription,
                                                     ServiceHostBase serviceHostBase,
                                                     Collection<ServiceEndpoint> endpoints,
                                                     BindingParameterCollection bindingParameters)
    {
    }

    public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
    {
        foreach (var dispatcher in serviceHostBase.ChannelDispatchers.OfType<ChannelDispatcher>())
        {
            dispatcher.Endpoints.ToList().
                ForEach(endpoint =>
                {
                    endpoint.DispatchRuntime.InstanceProvider = new UnityDependencyProvider(serviceDescription.ServiceType);
                });
        }
    }

    #endregion
}

«As you can see, it took me a couple of years of intense use to realize the shortcomings of SERVICE LOCATOR and that better alternatives existed. For this reason, I find it easy to understand why so many developers find it attractive…” (Gracias Mark) Smile

Los test…

El problema de los test está en que no tenemos un evento al cual nos podamos subscribir ni interfaz que implementar… Entonces, ¿Cómo creo los test sobre el IoC Container? by Scott…

Basados en las interfaces IA, IB y las clases A y B que escribimos en el artículo anterior, tendríamos los siguientes test:

[TestClass]
public class IocTest
{
    private readonly IUnityContainer _ioc;

    /// <summary>
    /// En los test, este es mi punto de entrada (Composition root)
    /// </summary>
    public IocTest()
    {
        _ioc = UnityContainerFactory.GetContainer();
    }

    [TestMethod]
    public void TestCreateObjetWithoutConstructorParameters()
    {
        var a = _ioc.Resolve<IA>();

        Assert.IsNotNull(a);
        Assert.AreEqual(1, a.ObjectId);
    }

    [TestMethod]
    public void TestCreateObjetWithConstructorParameters()
    {
        //var a = new A();  Ya no necesitamos hacer esto...
        //el framework de IoC se encarga de construir IA

        var b = _ioc.Resolve<IB>();

        Assert.IsNotNull(b);
        Assert.AreEqual(1, b.ParamInjector.ObjectId);
    }
}

Los elementos de configuración, ya podemos inyectarlos tal y como nos pedía Juanma:

[TestClass]
public class ConfigTest
{
    private readonly IUnityContainer _ioc;

    public ConfigTest()
    {
        _ioc = UnityContainerFactory.GetContainer();
    }

    [TestMethod]
    public void TestConfiguration()
    {
        var global = new Global(new AppSettingsHelper());
        var settings = global.Settings;

        Assert.AreEqual("My Project DDD", settings.Name);
        Assert.AreEqual("es-ES", settings.LanguageDefault);
        Assert.AreEqual("dd-MM-yyyy HH:mm", settings.DateTimeFormat);
        Assert.AreEqual(1, settings.TimeZoneOffset);

        Assert.IsInstanceOfType(global.SettingsHelper.GetBoolean("bool"), typeof(bool));
    }

    [TestMethod]
    public void TestIocConfiguration()
    {
        var global = _ioc.Resolve<IGlobalSettings>();

        Assert.IsNotNull(global);
        Assert.IsNotNull(global.Settings);
        Assert.IsNotNull(global.SettingsHelper);

        Assert.IsInstanceOfType(global.Settings, typeof(AppConfigurationElement));
        Assert.IsInstanceOfType(global.SettingsHelper, typeof(AppSettingsHelper));
    }
}

test-config

Gracias a Unai y a Eduard por hacer posible esta mejora…

PD: Aún no he probado los módulos implementados para MVC3 o para WCF… ya os contaré Winking smile

Salu2

DDD: 2- Framework de IoC (parte 2)

En el artículo anterior implementamos todas las interfaces necesarias para usar algunos elementos de configuración a nivel de aplicación. Entre estos elementos estaba el Framework de IoC.

En ese mismo artículo explicábamos por qué decidimos inyectar al Framework de dependecia, así que hoy nos dedicaremos a implementar todas las interfaces y realizar algunos test.

Antes de empezar, deciros que he realizado una pequeña modificación a la interfaz IContainerConfiguration que vimos en el artículo anterior. Soy de los que cree que cuando algún código (mio o no) queda digno de “admirar” (lo cual no quiere decir “correcto” Smile with tongue out), me quedo rato mirándolo aún días o semanas después de haberlo implementado. Esto, además de parecer que pierdo el tiempo, me  ayuda a ver posibles refactoring que en su momento no vi.

En uno de esos momentos de “bobería” me di cuenta que la interfaz IContainerConfiguration no necesita saber el QulifiedName para nada y que con el tipo era suficiente. Es verdad que de alguna forma debo recuperar el tipo, pero de eso que se encargue quien implemente la interfaz.

IContainerConfiguration ahora quedaría así:

public interface IContainerConfiguration
{
    Type IocObjectType { get; }
}

Después de hecho el cambio, entramos en materia.

Pensando con el corazón y no en el performance, voy a utilizar como Framework de inyección de dependencia el Unity de Microsoft, pero recuerden, de la forma que lo hemos implementado podríamos usar cualquiera siempre que implementemos la interfaz IContainer.

Para temas de configuración, usaré el archivo de configuración de la aplicación. Al igual que el framework de IoC, podríamos obtener la configuración de cualquier otro lado tan solo implementando las distintas interfaces.

Empezamos con la implementación del UnityContainer, nuestro único requerimiento es implementar la interfaz IContainer.

public sealed class UnityContainer : IContainer, IDisposable
{
    private readonly Microsoft.Practices.Unity.UnityContainer _container;

    public UnityContainer()
    {
        _container = new Microsoft.Practices.Unity.UnityContainer();
    }

    #region Miembros de IContainer

    public void InitializeContainer()
    {
        var section = (UnityConfigurationSection)ConfigurationManager.GetSection("unity");
        section.Configure(_container);
    }

    /// <summary>
    /// Retorna una nueva instancia del tipo T usando IoC
    /// </summary>
    /// <typeparam name="T">Tipo del nuevo objeto a instanciar</typeparam>
    /// <returns>Instancia del tipo generico T</returns>
    public T GetInstanceOf<T>()
    {
        return _container.Resolve<T>();
    }

    /// <summary>
    /// Retorna una nueva instancia del tipo T usando IoC
    /// </summary>
    /// <typeparam name="T">Tipo del nuevo objeto a instanciar</typeparam>
    /// <typeparam name="TParamType">
    /// Un parámetro de tipo TParamType que se le pasa al construnctor de T
    /// </typeparam>
    /// <returns>Instancia del tipo generico T</returns>
    public T GetInstanceOf<T, TParamType>(TParamType paramInjection)
    {
        _container.RegisterInstance(typeof(TParamType), paramInjection);
        return _container.Resolve<T>();
    }

    #endregion

    #region Miembros de IDisposable

    /// <summary>
    /// El Objeto UnityContainer del EnterpriseLibrary implementa IDisposable.
    /// Al construir una instancia de este objeto dentro de nuestra clase, necesitamos
    /// implementar dicha interfaz.
    /// </summary>
    public void Dispose()
    {
        _container.Dispose();
    }

    #endregion
}

La idea no es entrar a analizar el UnityContainer de Microsoft, sino me gusta, uso otro y nada cambia en toda mi aplicación. De cualquier forma, por detallar un poco la implementación de la interfaz, vemos la inicialización de Unity en el método que provee la interfaz (InitializeContainer), luego usamos el Container para satisfacer los dos métodos de la interfaz que retornan una instancia de un objeto basado en su interfaz (con o sin parámetro) y todo listo.

¿Hacemos entonces unos Test a ver qué tal? Ah no, que no puedo, primero tengo que implementar todo el tema de configuración. Pues lo que adoro de esta arquitectura es precisamente esto, sí, tengo que implementar el tema de configuración, pero como la misma sale de una interfaz, puedo hacerlo sin tener que llegar a implementar todo lo que se refiere al archivo de configuración. Smile

class UnityConfiguration : IContainerConfiguration
{
    #region Implementation of IContainerConfiguration

    public Type IocObjectType
    {
        get { return typeof(Project.IoC.EnterpriseLibrary.UnityContainer); }
    }

    #endregion
}

Aquí implemento la interfaz de configuración para el IoC y retorno directamente el tipo que implementa el IContainer. (Nota: El tipo UnityContainer que retorno aquí no es el de Microsoft, es el mío que implementa la interfaz IContainer).

Voy a crearme unos objetos bien simples para realizar los test

public interface IA
{
    int ObjectID { get; }
}

public interface IB
{
    IA ObjectInjection { get; }
}

public class A : IA
{
    public A()
    {
        ObjectID = 1;
    }

    #region Implementation of IA

    public int ObjectID { get; private set; }

    #endregion
}

public class B : IB
{
    public B(IA paramInjection)
    {
        ObjectInjection = paramInjection;
    }

    #region Implementation of IB

    public IA ObjectInjection { get; private set; }

    #endregion
}

 

Configuramos el Unity de Microsft para crear los Alias y los mapeos y vamos por los test.

<configSections>
  <section name=»unity»
            type=»Microsoft.Practices.Unity.Configuration.UnityConfigurationSection,
            Microsoft.Practices.Unity.Configuration» />
</configSections>

<unity>
  <typeAliases>
    <typeAlias alias=»IA» type=»Solution.Test.Infrastructure.IoC.IA, Solution.Test» />
    <typeAlias alias=»IB» type=»Solution.Test.Infrastructure.IoC.IB, Solution.Test» />
    <typeAlias alias=»A» type=»Solution.Test.Infrastructure.IoC.A, Solution.Test» />
    <typeAlias alias=»B» type=»Solution.Test.Infrastructure.IoC.B, Solution.Test» />
  </typeAliases>
  <containers>
    <container>
      <register type=»IA» mapTo=»A» />
      <register type=»IB» mapTo=»B» />
    </container>
  </containers>
</unity>

Los test:

[TestClass]
public class IocTest
{
    private readonly IContainer _ioc;

    public IocTest()
    {
        _ioc = new IocFactory().Create(new UnityConfiguration());
    }

    [TestMethod]
    public void TestCreateObjetWithoutConstructorParameters()
    {
        var a = _ioc.GetInstanceOf<IA>();

        Assert.IsNotNull(a);
        Assert.AreEqual(1, a.ObjectID);
    }

    [TestMethod]
    public void TestCreateObjetWithConstructorParameters()
    {
        var a = new A();
        var b = _ioc.GetInstanceOf<IB, IA>(a);

        Assert.IsNotNull(b);
        Assert.AreEqual(1, b.ObjectInjection.ObjectID);
    }
}

Flirt male Me encanta este momento…

test-ioc

Bien, pasemos del sentimentalismo y la adoración del color verde del Success Open-mouthed smile y vayamos a la configuración. La implementación de la configuración del framework de IoC desde el archivo de configuración quedaría de la siguiente forma:

public class ContainerConfigurationElement : ConfigurationElement, IContainerConfiguration
{
    [ConfigurationProperty("unityType", IsRequired = true)]
    public string IocQualifiedName
    {
        get { return (string)this["unityType"]; }
        set { this["unityType"] = value; }
    }

    public Type IocObjectType
    {
        get { return Type.GetType(IocQualifiedName); }
    }
}

Recuerden que ya la propiedad que nos da el QualifiedName no pertenece a la interfaz, sin embargo sí que la implementamos cuando queremos obtener quién será nuestro  Framework de IoC desde la configuración.

Hagamos lo mismo para los Settings de mi aplicación:

public class AppConfigurationElement : ConfigurationElement, IAppConfigurationElement
{
    #region Implementation of IAppConfigurationElement

    [ConfigurationProperty("name", IsRequired = true)]
    public string Name
    {
        get
        {
            return (string)this["name"];
        }
        set
        {
            this["name"] = value;
        }
    }

    [ConfigurationProperty("datetimeFormat", IsRequired = false, DefaultValue = null)]
    public string DateTimeFormat
    {
        get
        {
            var dtFormat = (string)this["datetimeFormat"] ??
                  new CultureInfo(LanguageDefault, false).DateTimeFormat.ToString();

            return dtFormat;
        }
        set
        {
            this["datetimeFormat"] = value;
        }
    }

    [ConfigurationProperty("languageDefault", IsRequired = true)]
    public string LanguageDefault
    {
        get
        {
            return (string)this["languageDefault"];
        }
        set
        {
            this["languageDefault"] = value;
        }
    }

    [ConfigurationProperty("timeZoneOffset", IsRequired = false, DefaultValue = 0D)]
    public double TimeZoneOffset
    {
        get
        {
            return (double)this["timeZoneOffset"];
        }
        set
        {
            this["timeZoneOffset"] = value;
        }
    }

    #endregion
}

Ahora ya podemos  implementar la interfaz que agrupa los elementos de configuración.

public class AppConfigurationSection : ConfigurationSection, IAppConfigurationSection
{
    [ConfigurationProperty("Setting")]
    private AppConfigurationElement ConfigSettings
    {
        get
        {
            return (AppConfigurationElement)this["Setting"];
        }
        set
        {
            this["Setting"] = value;
        }
    }

    [ConfigurationProperty("IocConfiguration")] 
    private ContainerConfigurationElement ConfigIocConfiguration
    {
        get { return (ContainerConfigurationElement)this["IocConfiguration"]; }
        set { this["IocConfiguration"] = value; }
    }

    #region Implementation of IAppConfigurationSection

    public IContainerConfiguration IocConfiguration
    {
        get { return ConfigIocConfiguration; }
        set { ConfigIocConfiguration = (ContainerConfigurationElement) value; }
    }

    public IAppConfigurationElement Settings
    {
        get { return ConfigSettings; }
        set { ConfigSettings = (AppConfigurationElement) value; }
    }

    #endregion
}

Vean que hemos tenido que definir propiedades que retornen un ConfigurationElement. Esto es requerido para poder leer las configuraciones del archivo de configuración, pero yo en ningún momento deseo que esos tipos sean conocidos por mi aplicación (recuerden que trabajamos ajenos a la tecnología que usemos). Es por eso que esta clase crea las propiedades concretas para la configuración como privadas y, las que usará mi aplicación (públicas) retornan la interfaz del tipo creado.

Por último, implementamos IGlobalSettings. Aquí me implemento un Singleton a nivel de aplicación para acceder a mi configuración. Dos razones, tengo un único punto de acceso (por eso el síngleton) y los datos que guarda mi configuración no cambian durante todo el ciclo de vida de la aplicación (por eso digo que es a nivel de aplicación)

public sealed class Global : IGlobalSettings
{
    /// <summary>
    /// Singleton. Thread safe.
    /// </summary>
    private static readonly Lazy<Global> _instance = new Lazy<Global>(() => new Global());

    /// <summary>
    /// IocFactory.
    /// </summary>
    private readonly IContainer _ioc;

    private Global()
    {
        var cfg = (IAppConfigurationSection)ConfigurationManager.GetSection("Project");

        _ioc = new IocFactory().Create(cfg.IocConfiguration);
        Settings = cfg.Settings;
    }

    public static Global Application
    {
        get { return _instance.Value; }
    }

    #region IAppConfigurationSection Members

    public IContainer Ioc { get { return _ioc; } }
    public IAppConfigurationElement Settings { get; private set; }

    #endregion
}

Ya podemos ir a por los Test de configuración. El IoC ya lo probamos, por lo que con saber que el tipo retornado por la configuración es correcto (implementa IContainer), tengo suficiente

Antes de escribir los test, creamos la configuración en el archivo de configuración de la aplicación.

<configSections>
  <section name=»Project»
        type=»Project.Settings.Config.AppConfigurationSection, Project.Settings.Config»
        requirePermission=»false» />
</configSections>

<Project>

  <Setting name=»My Project DDD»
                languageDefault=»es-ES»
                datetimeFormat=»dd-MM-yyyy HH:mm»
                timeZoneOffset=»1″  />

  <IocConfiguration unityType=»Project.IoC.EnterpriseLibrary.UnityContainer,
                                                                        Project.IoC.EnterpriseLibrary» />

</Project>

y ahora sí…

[TestClass]
public class ConfigTest

    [TestMethod]
    public void TestConfiguration()
    {
        var settings = Global.Application.Settings;

        Assert.AreEqual("My Project DDD", settings.Name);
        Assert.AreEqual("es-ES", settings.LanguageDefault);
        Assert.AreEqual("dd-MM-yyyy HH:mm", settings.DateTimeFormat);
        Assert.AreEqual(1, settings.TimeZoneOffset);
    }

    [TestMethod]
    public void TestIocConfiguration()
    {
        var ioc = Global.Application.Ioc;
        Assert.IsInstanceOfType(ioc, typeof(Project.IoC.EnterpriseLibrary.UnityContainer));
    }
}

Result:

test-config

y Chirrin-chirran…. Smile

DDD: 2- Framework de IoC (parte 1)

¿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…

 

DDD: 1- Introducción a un esquema genérico…

Me ha costado trabajo decidirme, hay tantos ejemplos de aplicaciones con arquitectura DDD publicados en internet en el que cada uno desarrolla un esquema distinto que uno se piensa una y otra vez si lo que está haciendo estará bien o será un simple disparate.

Partiendo de esta duda, el objetivo de esta serie no es crear una guía para orquestar una arquitectura DDD, ni siquiera pretendo que sea un modelo a seguir. Mi objetivo es más bien ir compartiendo por aquí las cosas que se me van ocurriendo y de ser posible, generar un debate que nos ayude a todos a tener puntos de vista diferentes.

Sin más, empiezo por donde se empieza cualquier arquitectura  El diagrama de capas:

Esta parte es la que casi siempre tengo clara… La distribución de las capas en Dominio, Aplicación, Infraestructura, la capa de servicios WCF (opcional) y las interfaces de usuario, cada una con su flujo de información.

No quiero entrar a analizar qué va dentro de cada capa porque precisamente la idea es ir comentando el desarrollo que vayamos realizando paso a paso. Solo aclarar que en muchas arquitecturas DDD, puede existir un flujo de información entre la interfaz de usuario y el dominio.  Este flujo se ve en muchas arquitecturas que muestran inyección de dependencia de los repositorios dentro de los controladores de un proyecto MVC (incluso ASP.NET MVC está preparado para inyectar dependencias a los controladores). En este caso, no vamos a tener ese flujo y es por eso que no lo represento.

¿Por qué? Hoy en día es poco habitual que desarrollemos una sola aplicación, normalmente nuestros proyectos requieren que para un mismo dominio tengamos varios frentes por el que lo atacamos (UI para móviles, UI para desktop, servicios que expongan funcionalidad a terceros, etc.). Con el objetivo de centralizar la lógica de aplicación (servicios en la capa aplicación) y permitir la reutilización de código, es que ninguna interfaz de usuario llega al dominio si no es mediante la capa de aplicación.

En Visual Studio cada capa está definida como un “Solution Folder”, por lo que la estructura de mi arquitectura queda más o menos así…

Creo que se ve que existen 12 proyectos dentro de la solución, por lo que el desarrollo va mucho más adelantado que esta serie de artículos. Espero a medida de que el tiempo me lo permita, ir poniéndome al día…  pero sobre todo, espero que se diviertan tanto como yo…

Salu2

 

Es la hora del cambio…

Primero que todo disculparme si alguien entra en este post pensando que voy a hablar de política 😛 siento que no sea así. Ya me sobra con el regaño que me dieron ayer por decir que “insidiar” era un verbo. 😉

Entrando en la materia que nos ocupa… Muchas veces cuando escuchamos hablar de arquitecturas del tipo DDD, TDD o N capas orientadas al dominio pensamos que todo eso es cosa de unos cuantos frikis que se pasan el día sin nada que hacer e intentando complicarnos la vida y, nada más lejos de la realidad. La arquitectura de un proyecto puede muchas veces llevarnos a escribir un mal código.

Ayer a un colega le pasó algo curioso respecto a eso. Introducir una arquitectura orientada al dominio en un grupo de trabajo con apenas experiencia es complicado, la curva de aprendizaje cuando se parte de cero es realmente alta y son muchos los conceptos y paradigmas que nos vemos obligados a cambiar. Entidades, DTO, Inversión de control, Inyección de dependencias, etc… todo esto puede ocasionar un retraso en el proyecto que nadie está de acuerdo en asumir.

Para evitar todo esto, diseñó una arquitectura N capas de toda la vida con posibilidades de dividirla en niveles, pero a su vez fue insertando conceptos como: Dominio, entidades, DTO, capas, niveles, servicios del dominio, repositorios, etc. toda una base que le permitiera en un momento dado, dar el cambio definitivo a arquitecturas verdaderamente orientadas al dominio.

Ayer se le presentó una problemática, necesitaba mandar a encender desde un panel de administración un conjunto de dispositivos por un tiempo determinado. Ya tenía funcionando toda la lógica de encendido y solo debía insertar el nuevo requerimiento de definir el tiempo que dicho dispositivo iba a permanecer encendido.  La secuencia para encender dispositivos era la siguiente:

Con el nuevo requerimiento la secuencia quedó de la siguiente manera:

La solución dada no me gustó porque rompe con la naturaleza propia del método, se está actualizando estados en un método destinado a seleccionar. Esto evita que dicho método pueda ser reutilizado para lo que fue pensado, traer un listado de dispositivos.

Cuando le dije cómo lo hubiera hecho yo, el diagrama de secuencia quedó de la siguiente forma:

Ummm… ¿Qué pasa aquí? Yo viajo al dominio mediante los servicios WCF dos veces para realizar una acción. Al final, él pensó una solución que desde el punto de vista de arquitectura está mal, pero es mucho más eficiente que la mía.

¿Por qué nos pasa esto? Si miramos el último diagrama de secuencia vemos como si algo faltara en la arquitectura que permita hacerlo bien y además que sea eficiente. Si me llevo esto a DDD ¿cómo queda?

Diagrama de secuencia:

Feliz y contento… toda la lógica que estaba en el UI ahora pasa a mi capa de aplicación, por lo que solo viajaría una vez por la capa de servicios WCF y todo lo que está dentro del ApplicationLayer, podría ser reutilizado desde otros UI.

Nada, que llegamos a la conclusión que… es la hora del cambio J

Salu2

El Daily Stand-Ups (Scrum) ¿Insuficiente?

En el proyecto en el que me encuentro actualmente (equipo de 4 personas) hemos logrado poner en práctica toda la teoría conocida sobre SCRUM. Algunas aplicadas 100% según la documentación, otras, adaptadas a los requerimientos del proyecto en sí.

Esto no es nuevo, todos sabemos que la guía para el desarrollo ágil existe, podemos aprender y usar de ella todo lo que enseña, pero al final… cada proyecto es un libro aparte que se escribe a su forma y bajo sus propios requerimientos.

Uno de los puntos que no puede faltar (adaptado o no) en un desarrollo ágil es el Daily Stand-Ups. Esas reuniones de 15 minutos en las que intercambiamos qué hacemos, qué hemos hecho y qué problemas tenemos.

Este tipo de reunión está definida en el desarrollo SCRUM de la siguiente manera:

Daily Stand-Ups (Scrums)

During a sprint, the team, the ScrumMaster, and the product owner (mejor no invitarle a todas 😛 ) commit to meeting once daily in the same place and at the same time to discuss any issues that are preventing work from being done. Meetings are held with everyone standing and time boxed to no longer than 15 minutes. Anyone interested is invited to attend these meetings; however, only the people classified as Pigs are allowed to speak at these meetings.

 At the meeting, each team member answers the following three questions:

• What have you done since yesterday?
• What are you planning to do today?
• Do you have any problems preventing you from accomplishing your goal? What progress has been made on existing impediments? Can the blockage be removed or must it be escalated? (The ScrumMaster looks after this area.)

La aplicación de este tipo de reuniones dentro de un proyecto crea un entorno de trabajo sumamente favorable. Todos conocemos qué ha hecho o qué está haciendo cada miembro del equipo, todos aportamos solución a los posibles problemas y todos estamos capacitados en un momento dado de asumir una tarea determinada. Los cuellos de botella en un entorno así, son detectados muy pronto y permite a su vez, darle una pronta solución.

A grandes rasgos, el problema sobre qué hace cada miembro del equipo estaba resuelto. Todos éramos capaces, sin pérdida alguna de tiempo, de asumir o colaborar con la tarea de otro. Pero… (Grrrrrr!!!… siempre hay peros)

Nos dimos cuenta que algo más detallado se nos estaba escapando. Cada tarea asignada a un miembro del equipo normalmente está compuesta por Bugs, Tasks, o Issues. La solución a nivel de código que se daba a cada elemento muchas veces no contaba con la calidad suficiente, o simplemente no se aplicaba una solución que pudiera ser reutilizable. A este nivel de detalle en los Daily Stand-ups, no llegábamos.

Una primera solución fue enviarnos un correo al final del día en el que cada uno contábamos  qué había hecho (a nivel de Bugs, Tasks o Issues) hablando un poco de la solución implementada en cada caso, pero ( y más peros…) Somos informáticos, odiamos trabajar de más 😀  y, escribir este correo a final del día iba a terminar perdiéndose. 

Pensando un poco en el correo y la información que recogíamos nos dimos cuenta que esto al final era lo mismo que mirar toda la actividad realizada durante el día en el TFS (Team Fundation Server) ¿Por qué entonces no preguntarle al TFS lo que cada miembro del equipo había hecho durante el día? Incluso, ¿Por qué no preguntarle al TFS lo que había hecho por sí solo durante el día? (Builds de integración continua fallidos, Works Items creados, etc.)

Si pudiéramos tener acceso al TFS desde internet, la solución hubiera sido más simple, pero en la mayoría de los casos esto no es así. Al final, desarrollamos una tarea que recoge toda la información del TFS realizada en el día y nos envía un resumen por correo 🙂

La solución nos pareció interesante y por si pudiera ser reutilizada por alguien más, la publicaremos acá en cuanto le apliquemos un poco de Refactoring y le pongamos una cara bonita.