The Dot Sharper

Los Requerimentos en Arquitecturas SOA

Todo el mundo sabe la importacia de los requerimientos en cualquier tipo de desarrollo, por no decir que es fundamental para saber que tenemos que hacer. Es por esto, que nadie empedrería un desarrollo sin hablar antes con los clientes para determinar los “user stories”, y a partir de estos los requerimientos del sistema.

A pesar de que todos sabemos esto, es bastante habitual el hecho de empezar a tirar hormigoneras de código sin tener ni un solo requerimiento, ya sea por la dificultad de obtener la información relevante sobre el negocio de la aplicación, la falta de planificación, o simplemente que nos gustan los deportes de riesgo.

Así que sin requerimientos, y con poca o ninguna información, nos armamos de valor, le echamos imaginación y nos inventamos los modelos de dominio, los requerimientos, un par de cuentos para niños, escribimos unos documentos funcionales, que ni el Señor de lo Anillos, y nos liamos a hacer aplicaciones haciendo “CRUD” de todas la entidades de dominio. Con un poco de suerte el cliente no se da cuenta de la “mi…erda” que hemos hecho y la implementación de la lógica de negocio la hacemos durante el mantenimiento de la aplicación,… el negocio perfecto.

Las arquitecturas tradicionales N-Capas son magnificas para “el negocio perfecto”, los continuos cambios en la lógica de negocio son implementados con mayor o menor dificultad, los cambios implican modificaciones de la arquitectura muchas veces son inaplicables. Con el tiempo cada vez la lógica está más dispersa y cada vez resulta más difícil adaptarse a los cambios.

En aplicaciones con arquitecturas SOA no podemos empezar a desarrollar sin los requerimientos, ya que de ellos se extraen los servicios y su composición.

Sin los requerimientos o inventándonoslos (lo que viene a ser lo mismo), si aplicamos SOA, podemos implementar servicios que en un futuro no servirán para nada, cuando el cliente nos de los requerimientos a modo de bugs, nos dedicaremos a hacer y deshacer servicios y composiciones. Sin unos buenos requerimientos de inicio, una arquitectura SOA es mucho más costosa que no una tradicional N-Capas, ya que se rehace mucho más código y se tira mucho más. Además la aplicación de los nuevos cambios en el negocio, son mucho más difíciles de aplicar que en una tradicional.

Sin embargo, si aplicamos SOA bien desde el principio con los requerimientos de negocio, cualquier cambio en el negocio o corrección de errores, es infinitamente menos costosa e increíblemente más fácil de realizar que en una arquitectura tradicional N-Capas, a pesar de que los cambios afecten al número de servicios y a la composición entre ellos.

 

Generación de Scripts SQL con NHibernate

Uno de los problemas más frecuentes con lo que nos encontramos a la hora de utilizar NHibernate, son las diferencias entre el modelo de domino y el modelo relacional de la base de datos, de forma que a veces es muy difícil relacionar algunas entidades del modelo de dominio con las tablas de la base de datos. Estas diferencias, se convierten con mucha facilidad en problemas de rendimiento, ya que las consultas que se generan no son todo lo optimas que deberían ser. En muchas ocasiones estas diferencias se vuelven insalvables, y se pierde mucho tiempo (dinero) en intentar solucionar algo que sencillamente no tiene arreglo.

Mi recomendación, siempre es la misma, primero se debe construir el dominio, siguiendo siempre los principios del Domain Driven Design, y luego a partir del dominio generar la base de datos, de forma que esas diferencias entre el domino la base de datos sean lo menor posible.

En este aspecto, NHibernate nos puede ayudar a generar la base de datos a partir de los ficheros de mapeo de la siguiente forma:

    var configuration = new Configuration();
    configuration.Configure(fileConfiguration);

    using (var sessionFactory = configuration.BuildSessionFactory())
    using (var session = sessionFactory.OpenSession())
    {
        var generateSchemaCreationScript = configuration.GenerateSchemaCreationScript(new MsSql2008Dialect());
        foreach (var script in generateSchemaCreationScript)
        {
            var sqlQuery = session.CreateSQLQuery(script);
            sqlQuery.ExecuteUpdate();
        }
    }

Por otro lado, durante el ciclo de vida de un proyecto, el modelo de dominio va evolucionando en el tiempo y el espacio, y normalmente resulta bastante tedioso la creación de los scripts SQL de creación y modificación de la base de datos. Con NHibernate también podemos generar los scripts diferenciales entre la base de datos y el modelo de dominio de la siguiente forma:

    var configuration = new Configuration();
    configuration.Configure(fileConfiguration);

    using (var sessionFactory = configuration.BuildSessionFactory())
    using (var session = sessionFactory.OpenSession())
    {
        var meta = new DatabaseMetadata((DbConnection)session.Connection, new MsSql2008Dialect());
        var generateSchemaCreationScript = configuration.GenerateSchemaUpdateScript(new MsSql2008Dialect(), meta);
        foreach (var script in generateSchemaCreationScript)
        {
            var sqlQuery = session.CreateSQLQuery(script);
            sqlQuery.ExecuteUpdate();
        }
    }

Si nos encontramos que tenemos un problema de diferencia entre el modelo de domino y la base de datos, es un buen ejercicio generar los scripts diferenciales, para poder ver que lejos (o cerca) estamos de lo que deberíamos tener. Si las diferencias son muy grandes, es muy posible que este script no nos sea de mucha ayuda.

La implementación que uso para la generación del esquema de la base de datos es la siguiente:

    using System;
    using System.Collections.Generic;
    using System.Data.Common;
    using NHibernate;
    using NHibernate.Cfg;
    using NHibernate.Dialect;
    using NHibernate.Tool.hbm2ddl;

    public class NHibernateSchemaHelper : INHibernateSchemaHelper
    {
        private readonly ISessionFactory _sessionFactory;
        private readonly ISession _session;
        private readonly Configuration _configuration;

        public NHibernateSchemaHelper()
        {
            _configuration = new Configuration();
            _configuration.Configure();

            _sessionFactory = _configuration.BuildSessionFactory();
            _session = _sessionFactory.OpenSession();
        }

        public NHibernateSchemaHelper(string fileConfiguration)
        {
            _configuration = new Configuration();
            _configuration.Configure(fileConfiguration);

            _sessionFactory = _configuration.BuildSessionFactory();
            _session = _sessionFactory.OpenSession();
        }

        public void Create()
        {
            Drop();
            var generateSchemaCreationScript = _configuration.GenerateSchemaCreationScript(new MsSql2008Dialect());

            ExecuteSchemaScript(generateSchemaCreationScript);
        }

        public void Update()
        {
            var meta = new DatabaseMetadata((DbConnection)_session.Connection, new MsSql2008Dialect());
            var generateSchemaCreationScript = _configuration.GenerateSchemaUpdateScript(new MsSql2008Dialect(), meta);

            ExecuteSchemaScript(generateSchemaCreationScript);
        }

        public void Drop()
        {
            var generateSchemaCreationScript = _configuration.GenerateDropSchemaScript(new MsSql2008Dialect());

            ExecuteSchemaScript(generateSchemaCreationScript);
        }

        private void ExecuteSchemaScript(IEnumerable generateSchemaCreationScript)
        {
            foreach (var script in generateSchemaCreationScript)
            {
                var sqlQuery = _session.CreateSQLQuery(script);
                sqlQuery.ExecuteUpdate();
            }
        }

        public void Dispose()
        {
            GC.SuppressFinalize(this);
            Dispose(true);
        }

        private void Dispose(bool disposing)
        {
            if (disposing)
            {
                _session.Dispose();
                _sessionFactory.Dispose();
            }
        }
    }

    public interface INHibernateSchemaHelper : IDisposable
    {
        void Create();
        void Update();
        void Drop();
    }

Como podéis ver, Nhibernate nos ayuda a generar el schema de la base de datos, y a que las diferencias entre el dominio y la base de datos sean las menores posibles, lo que significa que nuestro dominio está replicado en al base de datos, y que los problemas ocasionados por los intentos de adaptación del dominio a la base de datos no los vamos a tener.

Esto no nos va a eliminar los problemas de rendimiento ocasionados por un mal dominio, esos lamentablemente los seguiremos teniendo, NHibernate no es tan listo, como decía Botines: “La programasión es un arte,… sino programarían los roboses”.

Dependency Injection on ASP.Net MVC Controllers

Al trabajar con ASP.Net MVC podríamos pensar que no podemos utilizar la inyección de dependencias, ya que cuando se produce una petición web, ASP.Net MVC crea automáticamente las instancias de los controladores. Y que la única forma de poder utilizar la inyección de dependencias sería, llamar al contenedor directamente en el constructor por defecto del controlador.

Por defecto, ASP.Net MVC para crear los controladores utiliza una instancia de la clase DefaultControllerFactory, y esta necesita que los controladores tengan el constructor por defecto. Por suerte, podemos crear nuestra propia factory, especificarle al MVC que factory queremos que utilice, siempre y cuando herede de DefaultControllerFactory .

Así que lo primero que tenemos que hacer es crear nuestra clase ControllerFactory:

public class WindsorControllerFactory : DefaultControllerFactory
    {
        /// <summary>
        /// Gets the controller instance.
        /// </summary>
        /// <param name="requestContext">The request context</param>
        /// <param name="controllerType">Type of the controller.</param>
        /// <returns>A reference to the controller.</returns>
        protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
        {
            if (controllerType == null)
            {
                throw new HttpException(404, string.Format("The controller for path '{0}' could not be found or it does not implement IController.",
                    requestContext.HttpContext.Request.Path));
            }
            return (IController)WindsorContainerHelper.Instance.Resolve(controllerType);
        }

        /// <summary>
        /// Releases the controller.
        /// </summary>
        /// <param name="controller">The controller.</param>
        public override void ReleaseController(IController controller)
        {
            var disposableController = controller as IDisposable;
            if (disposableController != null)
            {
                disposableController.Dispose();
            }
            WindsorContainerHelper.Instance.Release(controller);
        }
    }

Como podéis ver, estoy utilizando un helper para acceder a Windsor Container, que yo mismo es creado, y que me permite cargar la configuración y utilizar el contenedor de forma mas fácil. Pero esto será un tema para otro post.

Lo realmente importante de esta clase son los dos métodos que tenemos que sobrescribir, GetControllerInstance y ReleaseController, el primero es que al que llama MVC para crear una instancia del controlador a partir del tipo, nosotros hemos sobrescrito el método para delegar la creación de la instancia al Windsor Container. El segundo se producirá cuando acabe la petición Web, y es el método al que llama el MVC para liberar el controlador, en este caso sobrescribimos el método para eliminar la instancia del contenedor.

Por último, necesitamos que el MVC utilice nuestro ControllerFactory, para esto lo que tenemos que hacer es especificarlo cuando se inicie la aplicación, es decir, en el Global.asax pondremos la siguiente linea:

protected void Application_Start()
        {
            ...
            ControllerBuilder.Current.SetControllerFactory(new WindsorControllerFactory());
            ...
        }

Come veis es muy fácil inyectar las dependencias directamente en el controlador MVC.

Diseño por Contrato

Durante el desarrollo siempre intento que el código sea lo más robusto posible, y no hay nada que oide más, que el ver que alguien se ha dejado, por descuido (dejemoslo ahí), las comprobaciones que hacen que el código pete de forma impredecible. Bueno eso y ver comentarios de más de 200 líneas, pero esto último es más propio de “El Perla” y tampoco es el tema artículo.

Pues si lo reconozco, me da muchísima rabia hacer una llamada a un método, y que en vez de un objeto me devuelva un null, porque ha dado error y nadie se ha enterado. Lo tipico de esto cuando vas a mirar el código es encontrarte algo de este tipo:

public Customer FindById(int id)
{
    try
    {
        return repository.FindById(id);
    }
    catch()
    {
        return null;
    }
}
… ole tus huevos, bueno, hubiera sido todo un detalle haber puesto un logger dentro del catch, pero como nuestro compañero no es que estuviera muy generoso, pues la cosa se ha quedado en un return null y vas que te matas.

Lo que a mí me indica el contrato de ese método, es que me va a devolver un objeto Customer o sí o sí, lo que no espero es que me devuelva un nulo, si tiene que petar pues que lance una excepción, pero no que captura la excepción y luego me devuelva un nulo.
Luego tu código peta con un maravilloso error: “object reference not set to an instance of an object”.

Cuando hablas con el amigo que hizo el código, te dice que él programa “Fault Tolerant”, y claro a tí lo único que te viene a la cabeza es:

“Tú código es fault tolerant y tú eres un piiiiiiiiiiii, así programa hasta mi abuela” (Mierda de censura)

Pero en realidad lo que dices es:

“Claro, claro” (mejor dicho “Ok, Ok”, para hablar en su lengua: el españolconpalabros)

“No te preocupes que ya arreglo yo la incidencia” (perdón el “bug”)

Si no se cumplen las exceptativas para realizar la operación, o bien aunque cumplidas los resultados no son los esperados, el método deberia lanzar un excepción. Pero parece ser que esto ya es programación “high level”.

A priori, y sin pensarlo mucho, se me ocurren unas cuantas comprobaciones que se prodrían hacer como:

  • El “id” no sea negativo
  • El “repository” no sea nulo
  • El objeto retornado no sea nulo

Para empezar por algún sitio y como primera aproximación, podríamos dejar el código de esta forma:

/// <summary>Devuelve el cliente con el identificador especificado.
/// Si el identificador no existe devuelve null.</summary>
/// <param name="id">Debe ser > 0</param>
public Customer FindById(int id)
{
    return repository.FindById(id);
}
… y rezar, para que él que llame al método, se lea los comentarios y haga la comprobaciones pertinentes.
Ya sé, esto tampoco es que sea nada del otro mundo, pero por lo menos puedo recoger la excepción en el código que llama al método.

Esta decisión de poner este “contrato” en los cometarios, o el algún otro lugar como en el documento de diseño (ubicado en algún lugar de la red, del que no se acuerda ni el que lo redactó), tiene sus incovenintes:

Hay que mantener al día los comentarios de los métodos y/o el documento de marras,
y todos sabemos que pasa con los documentos y los cometarios, una vez hechos ya nadie se acuerda, son para cubrir expediente.

Un cambio en las condiciones de ejecución del método, puede provocar errores dificiles de detectar en otras parte de la aplicación.

El que realiza la llamada al método tiene que:

leerse los comentarios (se que parece absurdo, pero al final no se los lee ni Dios) y ya no digo la documentación, y además realizar las comprobaciones pertinentes antes y despues de cada llamada (y esto ya es una utopía)

La solución a este tipo de problemas es el Diseño por Contrato.

Diseño por Contrato

Esta técnica de desarrollo es una caraterística nativa de muchos lenguages de programación, lamentablemente para C# no es así.

Se basa en aplicar una serie condiciones (precondiciones, invariates y postcondiciones), a las que llamaremos “contrato”, que garantizan el correcto funcionamiento del método.

  • Precondiciones: Imponen unas ciertas obligaciones para garantizar la ejecución del método.
  • Invariantes: Condiciones que deben cumplirse siempre, tanto a la entrada como a la salida, como por ejemplo una edad siempre es positiva.
  • Postcondiciones: Son las garantias que debe cumplir el método a la salida.

Siguiendo con nuestro ejemplo anterior tendríamos:

  • Precondiciones: El “id” no sea negativo
  • Invariantes: El “repository” no sea nulo
  • Postcondiciones: El objeto retornado no sea nulo

Si el contrato no se cumple lanzaremos un excepción. El cumplimiento del contrato garantiza el resultado obtenido.

public Customer FindById(int id)
{
    if(repository == null)
        throw new Exception("Error en el repositorio");

    if(id <= 0)
        throw new ArgumentOutOfRangeException("El id debe ser mayor que 0");

    var customer = repository.FindById(id);

    if(customer == null)
        throw new KeyNotFoundException(string.Format("No se ha encontrado un cliente con el ID: {0}", id));

    return customer;
}
La primera ventaja que vemos, es que no tenemos que realizar las comprobaciones en cada llamada al método, ya que es el propio método es que las realiza. Otra ventaja, es que no hace falta matener al día los comentarios, ya que con un simple vistazo vemos lo que hace el método. Y por último, el que realiza la llamada al método, si algo no va bien, tan solo tiene que esperar una excepción.

Aunque esto es muy correcto, aun lo podemos hacer mucho más sencillo y mucho más limpio, ¿cómo? Con la validación por aspectos.

Validación por Aspectos

Esta validación se declara vía atributos, y nos permite definir validaciones para propiedades, parametros, etc.
Con este tipo de validación el código podría quedar de esta forma:
[NotNull]
public Customer FindById([GreaterThan(0)]int id)
{
    return repository.FindById(id);
}
Con esto podemos definir las precondiciones y las postcondiciones de una forma fácil, sencilla y mucho más legible que la anterior, que al final es lo que importa.
El framework de validación que uso es el ValidationFX, este para funcionar automáticamente necesita tener instalado el PostSharp.

Unit Test y Rhino Mocks

Introducción

Normalmente en las pruebas unitarias no es factible usar objetos reales porque es muy dificil o imposible incorporarlos al test unitario, por ejemplo que el estado de un objeto sea dificil de reproducir como un error de red, o que sea lento como es el caso de una base de datos que primero tiene que ser inicializada para realizar el test, o que desde donde se ejecuta el juego de pruebas no haya acceso.
En estos casos es mejor utilizar “Mocks Objects”, los Mocks son objetos que simulan el comportamiento de objetos reales. Un objeto mock tiene la misma interfaz que un objeto real, así que un objeto puede usar de forma indistinta un objeto mock o un objeto real. La importancia de utilizar mocks es poder probar un trozo de código aisladamente, que lo que se pretende con un test unitario.
Rhino Mocks es un Mock Object Framework, que permite realizar estos objetos simulados de una forma automática y crear test unitarios más efectivos.

Creado Test Unitarios

Supogamos el siguiente ejemplo, la clase de negocio CutomerBusiness de la que queremos realizar el test unitario del método HasSpecialFare, que devuelve cierto en el caso que el cliente que le pasamos poseea una tarifa especial.
Este método utiliza objeto de acceso a datos (customerDao) que se conecta con la base de datos y obtiene la tarifa del cliente, y una vez obtenida la tarifa compara el código de la tarifa con el código de tarifa especial.
public class CustomerBusiness
{
    private const string SPECIAL_FARE = "SPC";

    private readonly ICustomerDao customerDao;

    public CustomerBusiness(ICustomerDao customerDao)
    {
        this.customerDao = customerDao;
    }

    public bool HasSpecialFare(Customer customer)
    {
        return customerDao.GetFareType(customer).Type
                             == SPECIAL_FARE;
    }
}

public interface ICustomerDao
{
    FareType GetFareType(Customer customer);
}
...
Queremos realizar el test unitario de este método aisladamente, no nos interesa saber si el objeto CustomerDao es capaz de extraer correctamente o no la tarifa, de eso ya se encargará el test unitario que hagamos sobre el objeto dao, lo único que en este caso nos interesa es saber si este código es capaz de funcionar o no. Por esto ni siquiera nos hemos molestado en codificar el objeto CustomerDao, tan solo hemos codificado la parte de la interfaz necesaria para este ejemplo.
Si no utilizamos RhinoMocks deberiamos primero implementar el objeto CustomerDao para que se conectara a la base de datos, comprobar que se conecta correctamente y que obtenga los datos correctos, además de tener acceso a la base de datos desde donde se ejecuten los test. Por otro lado si lo hacemos así, primero se debería pasar las pruebas de los DAO antes de pasar las pruebas de los business, esto implica que hay pruebas que dependen las unas de las otras, esto no debería pasar nunca ya que la definición de test unitario pierde todo su sentido.
Para evitar este problema podriamos crear un objeto Dao dummy, que devolviera unos resultados ficticios en función de las necesidades, esta solución sería muy costosa ya que deberíamos hacerlo para todos los objetos DAO de nuestra solución, y la realización de test unitarios sería interminable, y esto es justamente lo que hace RhinoMocks. Además de la creación automática de objeto dummy, RhinoMocks nos permite llegar a testear si se llama a ciertos métodos o no.

Ahora crearemos un test unitario con RhinoMocks para probar el método HasSpecialFareType de la clase CustomerBusiness. Para realización de los test unitarios utilizaremos NUnit.

[TestFixture]
public class CustomerBusinessTest
{
    [Test]
    public void HasSpecialFareTest()
    {
        //Creación de los objetos mocks
        var mockRepository = new MockRepository();
        var customerDaoMock =
              mockRepository.CreateMock<ICustomerDao>();

        //Establecimiento de las llamadas esperadas
        //y de los objetos de retorno
        var customer = new Customer();
        var fareType = new FareType
                 {Type = CustomerBusiness.SPECIAL_FARE};
        Expect.Call(customerDaoMock.GetFareType(customer))
                                 .Return(fareType);

        mockRepository.ReplayAll();

        var customerBusiness =
                 new CustomerBusiness(customerDaoMock);
        var specialFare =
                 customerBusiness.HasSpecialFare(customer);
        mockRepository.VerifyAll();
        Assert.IsTrue(specialFare);
    }
}
Lo primero que hacemos es crear el repositorio de Mocks, a este objeto repositorio le pedimos que cree un Mock que implemente la interfaz ICustomerDao, el repositorio nos devolverá un objeto dummy que de momento lo único que hará será implementar esa interfaz sin ninguna acción en particular.
Ahora le diremos al mock que esperamos que se realice una llamada al método GetFareType, al que se le pasará un objeto customer y queremos que devuelva el objeto fareType especificado. Si tuvieramos más llamadas lo hariamos con cada una de ellas, como si fuera una macro en la que no importa el orden.
Una vez hecho esto, le decimos al repositorio que guarde la macro que hasta ahora hemos introducido, y codificamos lo que vamos a probar, creamos un objeto customerBusiness y llamamos al metodo HasSpecialFare, que a su vez llamara al metodo GetFareType del dao, y le devolverá el objeto fareType.
Por último, le decimos al repositorio que verifique todas que todo ha ido bien, si durante la ejecución del test no se hubiera llamado al método GetFareType, o se hubiera llamado a otro hubiera dado error.

Windsor Container II

Introducción

En este artículo veremos como afectan los cambios en el código a la configuración de Windsor Container y veremos como afectarían en el caso de no utilizar WC.

Interfaces

Las primeras modificaciones que haremos será crear una interfaz para la clase sumador.
public interface ISumador
{
   decimal Suma(decimal num1, decimal num2);
}

public class Sumador : ISumador
{
    public decimal Suma(decimal num1, decimal num2)
    {
        return num1 + num2;
    }
}
...
public static WindsorContainer miContenedor;
public static void Main(string[] args)
{
    //Creamos el contenedor
    miContenedor = new WindsorContainer
                (new XmlInterpreter("MiContenedor.xml"));

    //Pedimos un objeto de tipo sumador al contenedor
    var sumador = miContenedor.Resolve<ISumador>();

    var result = sumador.Suma(1,1);
}
...
Al generar la interfaz en vez pedirle al contenedor que nos devuelva un objeto de tipo Sumador, le pedimos un objeto que implemente la interfaz sumador. Para esto debemos modificar el fichero de configuración de WC, añadiendo el atributo service al componente Sumador.
<configuration>
    <components>
        <component id="Sumador" type="IoC.Tutoriales.Part2.Sumador, IoC.Tutoriales.Part2"
            service="IoC.Tutoriales.Part2.ISumador, IoC.Tutoriales.Part2" />
    </components>
</configuration>
Con esto al pedir un objeto que implemente la interfaz ISumador, el contendor buscará el primer componente que implemente esta interfaz y devolverá un objeto de la clase de ese componente. En nuestro caso buscará un componente que implemente la interfaz ISumador, el componente con el id “Sumador”, y generará un objeto del tipo “IoC.Tutoriales.Part2.Sumador”. Al realizar estos cambios si ahora al contendor le pedimos un objeto Sumador se producirá un error ya que los tipos de service prevalecen sobre los tipos de atributo type.

Dependencias entre componentes

Supogamos que cada vez que realizamos una suma queremos que se guarde un log en un fichero. Primero escribiremos nuestra clase que graba el log:
public interface ILogger
{
    void Debug(string text);
}

public class FileLogger : ILogger
{
    private string fileName;

    public FileLogger(string fileName)
    {
        this.fileName = fileName;
    }

    public void Debug(string text)
    {
        //Graba el texto en el fichero fileName
        ....
    }
}
Los cambios en la clase Sumador serían de tipo:
public class Sumador
{
    private ILogger logger;

    public Sumador(ILogger logger)
    {
        this.logger = logger;
    }
    public decimal Suma(decimal num1, decimal num2)
    {
        logger.Debug(string.Format("Sumando {0} + {1}",
                                        num1, num2));
        return num1 + num2;
    }
}
Para una arquitectura de este tipo sin utilizar WC deberimos pirmero crear un objeto de tipo FileLogger y pasarlo al constructor del objeto Sumador.
public static void Main(string[] args)
{
    var logger = new FileLogger("log.txt");
    var sumador = new Sumador(logger);
    var result = sumador.Suma(1,1);
}
Al utilizar Windsor Container lo único que tenemos que cambiar es el fichero de configuración de la siguiente forma:
<configuration>
    <components>
        <component id="Sumador" type="IoC.Tutoriales.Part2.Sumador, IoC.Tutoriales.Part2"
            service="IoC.Tutoriales.Part2.ISumador, IoC.Tutoriales.Part2" />
        <component id="Logger" type="IoC.Tutoriales.Part2.FileLogger, IoC.Tutoriales.Part2"
            service="IoC.Tutoriales.Part2.ILogger, IoC.Tutoriales.Part2">
           <parameters>
               <fileName>C:\log.txt</fileName>
           </parameters>
        </component>
    </components>
</configuration>
El metodo Main no habría que modificarlo y quedaría como lo teniamos:
public static void Main(string[] args)
{
    //Creamos el contenedor
    miContenedor = new WindsorContainer(
                 new XmlInterpreter("MiContenedor.xml"));

    //Pedimos un objeto de tipo sumador al contenedor
    var sumador = miContenedor.Resolve<ISumador>();

    var result = sumador.Suma(1,1);
}
Al realizar una petición, Windsor Container busca en el contendor el componente que cumpla esa petición, una vez encontrado buscará las dependencias de ese componente en el contenedor, y así sucesivamente, si alguna de las dependencias no pueden ser satisfechas Windsor Container devolverá una excepción. En nuestro caso encontaría el componente con id “Sumador” que es del tipo “IoC.Tutoriales.Part2.Sumador”, este clase tiene una dependecia con la clase “IoC.Tutoriales.Part2.ILogger”, así que buscará dentro del contenedor si existe algún componente que satisfaga esta dependecia, y encontraría el comoponente con id “Logger”. De forma que para crear un objeto de tipo “IoC.Tutoriales.Part2.Sumador” primero creará un objecto de tipo “IoC.Tutoriales.Part2.FileLogger”.

Un pequeño refactoring

Supongamos ahora que en vez de guardar el log en un fichero lo debemos guardar en base de datos. Lo primero sería generar las clases necesarias para guardar el log en base de datos:
public class DBLogger : ILogger
{
    private string connectionString;

    public DBLogger(string connectionString)
    {
        this.connectionString = connectionString;
    }

    public void Debug(string text)
    {
        //Graba el texto en la base de datos
        ....
    }
}
Ahora lo único que tenemos que hacer es cambiar el fichero de configuración de Windsor Container para que tenga en cuenta el nuevo logger:
<configuration>
    <components>
        <component id="Sumador" type="IoC.Tutoriales.Part2.Sumador, IoC.Tutoriales.Part2"
            service="IoC.Tutoriales.Part2.ISumador, IoC.Tutoriales.Part2"/>
        <component id="Logger" type="IoC.Tutoriales.Part2.DBLogger, IoC.Tutoriales.Part2"
            service="IoC.Tutoriales.Part2.ILogger, IoC.Tutoriales.Part2">
           <parameters>
               <connectionString>...</connectionString>
           </parameters>
       </component>
    </components>
</configuration>
Con estos pequeños cambios todo lo demás funcionaría de la misma forma, lo único que cambiará sería que al satisfacer la interfaz ILogger en vez de crear un objeto FileLogger creará un objeto DBLogger.
Como podemos ver el hecho de trabajar contra interfaces y utilizar Windsor Container facilita enormemente cualquier tipo de refactoring.

Windsor Container I

Introducción.

Windsor Container es un “Inversion of Control Container” que forma parte del conjunto de soluciones open source de Castle Project junto a Monorail, Active Record y MicroKernel.
Pero vayamos por partes. Antes de explicar que es Windsor Container deberiamos saber que es la “Inversion of Control” (IoC). Este es un concepto muy poco extendido en el mundo .NET, y a aún menos utilizado, debido principalmente a la elevada curva de aprendizaje para su utilización en un desarrollo.
La idea básica de la IoC es que sea el framework quien realice la invocación a los objectos hechos por los programadores y no al revés, lo que implica que es el framework quien tiene el control de los objectos que se invocan y no nosotros.
Windsor Container es un contenedor de objectos que utiliza el principio IoC para crear los objectos de las clases y sus dependencias. Esto reduce el acoplamiento del sistema, facilita el reuso de los objetos, el testeo y la realización de refactoring.

Como utilizar Windsor Container.

Como toma de contacto con Windsor Container escribiremos una clase muy sencilla, la clase Sumador, que como su nombre indica su objectivo es sumar dos números:
public class Sumador
{
    public decimal Suma(decimal num1, decimal num2)
    {
        return num1 + num2;
    }
}
Sin Windsor Container(WC) para utilizar esta clase escribiriamos código de este tipo:
...
public static void Main(string[] args)
{
    var sumador = new Sumador();
    var result = sumador.Suma(1,1);
}
...
Al utilizar WC ya que los objetos se encuentran en un contenedor, no debemos instanciar nosotros los objectos sino que debemos pedirselos al contenedor. Primero debemos construir el contenedor, este se creará a partir de un fichero xml de configuración, que explicaremos más abajo.
Una vez nuestro contenedor ya ha sido creado, pedimos al contenedor un objeto de tipo Sumador y por último lo utilizamos.
...
public static WindsorContainer miContenedor;
public static void Main(string[] args)
{
    //Creamos el contenedor
    miContenedor = new WindsorContainer
               (new XmlInterpreter("MiContenedor.xml"));

    //Pedimos un objeto de tipo sumador al contenedor
    var sumador = miContenedor.Resolve<Sumador>();

    var result = sumador.Suma(1,1);
}
...
Como vemos el contenedor debe ser una variable estática con el fin de utilizar siempre el mismo contenedor durante todo el ciclo de vida de la aplición. No tendría sentido ir creado un contenedor cada vez que tenemos que crear un objeto.

El fichero de configuración de WC es un fichero xml en el que se especifican todos los objetos que están incluidos en el contenedor. Este fichero tiene el siguiente formato:

<configuration>
    <components>
        <component id="Sumador"
            type="IoC.Tutoriales.Part1.Sumador,
                       IoC.Tutoriales.Part1" />
    </components>
</configuration>
Los objectos a incluir se especifican mediante el tag “component” (incluido dentro de components), para cada componente hay que definir un identificador único (id) dentro del contenedor y el tipo de clase del objeto a la que pertenece (type =”nombre de clase, nombre del assembly”).

Esta configuración se puede incluir dentro del App.config, aunque mi consejo es que esté en un fichero a parte, ya que lo ficheros de configuración xml de windsor son suceptibles de hacerse muy grandes y de ser modifcados habitualmente.

Espero que os sirva de ayuda esta pequeña introducción al mundo IoC, en los siguientes artículos sobre IoC explicaremos cosas más interesantes que seguro serán de más utilidad.