Una forma de reducir clases que crecen en métodos

En el proyecto en el que estamos trabajando teníamos una interfaz ISettingsManager que manejaba el acceso al archivo de configuración y se encargaba de devolver una setting por default si no estaba definida. También nos permitía usar un stub mientras no teníamos loa valores definidos y para hacer pruebas.

App.config

ISettingsManager y Stub

El problema con esta implementación es que la clase estaba creciendo mucho. Olía cada vez más a una violación de SRP.

La solución que se nos ocurrió fue hacer que la clase deje de crecer en métodos y crezca en clases de la siguiente forma:

  • Cambiamos ISettingsManager a ISetting para manejar cada una individualmente.
  • Creamos una clase por cada setting.

App.config nuevo

ISettingManager = ISetting - Google Chrome_2013-02-15_12-13-46

ISettingManager = ISetting - 2

De esta forma logramos:

  • Desacoplar las clases clientes de la implementación de ISettingsManager. Antes casi todas las clases tenían una dependencia con esta, ahora sólo dependen de la setting que usan.
  • Nos permite armar clases abstractas entre ISetting y su implementación concreta de manera de agregar funcionalidad sin afectar las clases concretas. Por ejemplo podemos hacer que en lugar de ISetting hereden de BaseDatabaseSetting, en la que tenemos algunos métodos auxiliares para acceso a la base de datos (como Error404DescriptionSetting en el ejemplo).
  • Podemos implementar una funcionalidad completamente distinta para una setting que tenga un comportamiento distinto sin afectar las demás.
  • Todavía tenemos la flexibilidad del stub, podemos usar el mismo SettingStub para cualquier setting que necesitemos.

Aprovechando el default model binder de MVC con ajax

Necesitaba hacer post de propiedades (que forman un objeto de mi dominio C#) desde la vista hacia mi controlador de manera asincrónica.
Una forma de realizarlo podría haber sido la de hacer el submit de un formulario que estaría formado por los datos de mi objeto y luego desde el controlador parsear los mismos del Request. Como resultado del parseo podría armar el objeto de mi dominio “a mano”.
No satisfecho con la solución anterior decidí investigar y encontre la siguiente forma de hacer lo mismo pero aprovechando el default model binder para que me construya mi objeto directamente. Veamos como se hace en detalle: 

El objeto que quiero bindear que es

post

y la acción del controlador que usaré es la siguiente

post2

Ahora veamos qué código necesito para armar mi objeto en la vista y realizar el posteo

post3

Tal como se vió recién hay que armar el objeto en la vista, cargar sus propiedades con los valores que quiero que tengan y hacer la llamada a ajax.
La solución reusulto ser más sencilla de lo que me esperaba.
Sin embargo, hay quen n
otar que:

  • Los nombres de las propiedades deben coincidir con los del objeto del dominio (sino el model binder no los bindeará).
  • Bindear colecciones no es tan directo ya que para que el model binder las reconozca es necesario que las mismas sean de tipo array y que la opción traditional (de ajax) tenga true como valor.

Finalmente podemos ver que el resultado es el esperado

post-5

Este ejemplo fue realizado conASP.NET MVC 3  y ajax utilizando jQuery 1.4.2.

Espero que mi experiencia le sea útil a alguien más.
Saludos!

Publish automáticos por ambiente

Estábamos teniendo varios problemas al hacer deploy en los distintos ambientes porque siempre nos quedaba alguna setting sin modificar. Así que pensé que sería bueno automatizar esa tarea para evitar problemas.

La idea es simple. Uso web.config transformations para cambiar el archivo al ambiente que corresponda. En realidad sólo cambio a dónde apunta el web.config.

Armé la siguiente estructura del proyecto:

web.configs

configs por ambiente

 

 

La configuración de QA la armé como una nueva build configuration.

La carpeta Configs está en el root del proyecto. Vean que tengo una configuración distinta por cada ambiente.

El Web.config me quedó así:

Web.config base

Y los Web.*.config así:

Web.debug.config

Web.qa.config

Noten la diferencia en los configSource, ahí está la magia.

A partir de esta estructura podemos obtener publish automáticos simplemente compilando para el ambiente que lo necesitemos. También se puede automatizar con una tarea de compilación de MSBuild y se puede armar un .bat para tener builds de un click por ambiente =D.

Referencias:

AOP con WCF

Para un servicio WCF me encontré con la necesidad de atrapar y loggear excepciones en el nivel más alto de ejecución. Es decir algo así:

servicio web viejo

Mucho código repetido, además me estiraba mucho la clase. Pensé, este es el ejemplo de libro de AOP. Aproveché la oportunidad para probar DynamicProxy de Castle.

Me bajé y agregué la library al proyecto. Ví que crear una clase con un Interceptor era bastante fácil:

Interceptor

Excelente. Pero resulta que en una aplicación WCF el encargado de crear la clase es el svc y no hay un código asociado a eso por defecto. Por suerte a los muchachos se les ocurrió que uno puede llegar a necesitar crear sus propios servicios y permiten agregar una Factory.

Hay que indicar en el svc cuál es la Factory y agregarla extendiendo ServiceHostFactoryBase.

ServiceHostFactory

Un detalle más. Para que DynamicProxy funcione, los métodos deben ser virtuales. La clase finalmente me quedó así:

servicio web final

¡Mucho más breve y claro!

Dos comentarios.

  1. En el ServiceHostFactory tuve que agregar la línea 13 para que funciones. Debe haber una forma más elegante de resolver la excepción que me lanzaba, pero no me pareció muy grave.
  2. Teniendo esta configuración en la Factory en código ya no la tengo en el web.config. Pero sí tengo la de la metadata (IMetadataExchange).

Inyeccion de dependencias con Unity en un Action Filter

Buenas!

Quiero aprovechar para contarles un problema que tuve al querer resolver una dependencia con Unity en un action filter, en un proyecto MVC3.

La cuestión surgió cuando quise resolver la dependencia a un servicio de la misma manera que lo hacía en los controladores:

public class LockFilter : ActionFilterAttribute
{
     [Dependency]
     public IBloqueoServicioWrapper BloqueoServicio { get; set; }

     public override void OnActionExecuting(ActionExecutingContext filterContext)
     {
          //Hago cosas... obtengo un id por ejemplo...

          this.BloqueoServicio.Bloquear(id);

          //Mas cosas que no interesan...
     }
}

Pero esto asi no funcionaba, mi BloqueoServicio quedaba en null, y yo sabía que estaba todo bien configurado en el Unity.config… Luego de investigar un poco, llegué a esta solución:

 

public class LockFilter : ActionFilterAttribute
{
     public LockFilter()
     {
          var resolver = new Unity.Mvc3.UnityDependencyResolver(new UnityContainer());
          this.BloqueoServicio = resolver.GetService();
     }

     public IBloqueoServicioWrapper BloqueoServicio { get; set; }

     public override void OnActionExecuting(ActionExecutingContext filterContext)
     {
          //Hago cosas... obtengo un id por ejemplo...

          this.BloqueoServicio.Bloquear(id);

          //Mas cosas que no interesan...
     }
}

Al fin y al cabo, lo que termino haciendo es resolviendo la dependencia “a mano” en el constructor del filter en vez de usar el flag “[Dependency]“.

Es una solución que funciona (sin recurrir a suciedades extremas) y eso no es poca cosa, pero me quedó picando en la cabeza que esto se debería poder resolver en el Global.asax “registrando” los filters y resolviéndolos ahí mismo, como sucede con las dependencias en los controllers. Investigué un rato y no llegué a nada que funcionara o que mantuviera la generalidad que me gustaría que tuviera, pero la idea sigue picando…

Saludos!

Resolviendo dependencias circulares

Algunas pobres almas habrán visto el siguiente error:

Dependencia circular

Duro. Decidí escribir un ejemplo sencillo que muestre el problema y cómo resolverlo.

Tengo una aplicación muy sencilla con un proyecto web que muestra algo que se obtiene de otro proyecto de persistencia. O sea, el proyecto web tiene una referencia al proyecto persistencia. Aquí el problema: el proyecto de persistencia necesita también una referencia al web porque este sabe serializar el objeto a persistir. El proyecto web tiene este método porque lo usa para enviarlo por JSON.

public class Controlador // proyecto web
{
    public Persistidor Persistidor { get; set; }

    public string EmpresaJSON()
    {
        Empresa principal = this.Persistidor.EmpresaPrincipal();
        return EmpresaSerializada(principal);
    }

    public string EmpresaSerializada(Empresa empresa)
    {
        return string.Format("{0} en {1} {2}", empresa.Nombre, empresa.Direccion, empresa.Altura);
    }
}
public class Empresa // proyecto de persistencia
{
    public string Nombre { get; set; }

    public string Direccion { get; set; }

    public int Altura { get; set; }
}
public class Persistidor // proyecto de persistencia
{
    public Controlador Controlador { get; set; }

    public void GuardarEmpresaPrincipal(Empresa empresa)
    {
        this.Guardar(this.Controlador.EmpresaComoString(empresa));
    }

    public Empresa EmpresaPrincipal()
    {
        return this.ObtenerEmpresa();
    }

    // implementación de ObtenerEmpresa y Guardar.
}

La solución trivial es duplicar el código. Otra solución sería mover el método EmpresaSerializada del proyecto web al de persistencia. Pero esa solución no es la que me interesa (*).

La raíz del problema es que no estamos respetando SRP para los proyectos. La empresa no está directamente relacionada con su persistencia por lo que podríamos moverla a un proyecto aparte donde existan las entidades de nuestro proyecto.

public class Empresa // proyecto nuevo (entidades, modelo de dominio, etc.)
{
    public string Nombre { get; set; }

    public string Direccion { get; set; }

    public int Altura { get; set; }
}

Hemos puesto un poco de orden, pero el problema persiste. El método EmpresaSerializada todavía tiene que ser usado por ambos proyectos.

Si lo miramos fuerte, el método tiene bastante de la entidad Empresa, por lo que podríamos moverlo a la misma entidad.

public class Empresa // proyecto nuevo (entidades, modelo de dominio, etc.)
{
    public string Nombre { get; set; }

    public string Direccion { get; set; }

    public int Altura { get; set; }

    public string Serializar() // ex EmpresaSerializada
    {
        return string.Format("{0} en {1} {2}", this.Nombre, this.Direccion, this.Altura);
    }
}

El método era un típico ejemplo de Feature Envy. Veamos que las clases que lo usaban también han quedado más simples.

public class Controlador
{
    public Persistidor Persistidor { get; set; }

    public string EmpresaJSON()
    {
        Empresa principal = this.Persistidor.EmpresaPrincipal();
        return principal.Serializar();
    }
}
public class Persistidor
{
    public void GuardarEmpresaPrincipal(Empresa empresa)
    {
        this.Guardar(empresa.Serializar());
    }

    public Empresa EmpresaPrincipal()
    {
        return this.ObtenerEmpresa();
    }

    // implementación de ObtenerEmpresa y Guardar.
}

Finalmente tenemos 3 proyectos muy sencillos y resolvimos el problema de las dependencias circulares. En general se puede pensar en que hay que buscar el factor común entre las librerías y extraerlo. Es una buena práctica incluso antes de tener este problema.

¡Saludos!

(*) Caer en esta solución nos hace entrar en un círculo vicioso de poner todo en el proyecto de persistencia.

Link interesante: Code smell

Generalizando

Estaba escribiendo unos DAOs y noté que tenía mucho código repetido. Y como soy un gran creyente del principio DRY. Me puse a buscarle la vuelta.

Este es mi código original.

public class PacienteDAO : BaseDAO<Paciente>, IPacienteDAO
{
  private const string QUERY_SELECT = "SELECT * FROM [dbo].[Paciente]";

  public Paciente Load(int id)
  {
    string query = QUERY_SELECT + " WHERE Id = @Id";
    IDbParametersBuilder builder = CreateDbParametersBuilder();
    builder.Create().Name("Id").Type(DbType.Int32).Value(id);
    return LoadOne(query, new PacienteRowMapper(), builder.GetParameters());
  }

  public IList<Paciente> LoadAll()
  {
    this.Log.Debug("Getting all from Paciente");
    return LoadList(QUERY_SELECT, new PacienteRowMapper(), null);
  }

  // (...)
}

public class HospitalDAO : BaseDAO<Hospital>, IHospitalDAO
{
  private const string QUERY_SELECT = "SELECT * FROM [dbo].[Hospital]";

  public Hospital Load(int id)
  {
    string query = QUERY_SELECT + " WHERE id = @Id";
    IDbParametersBuilder builder = CreateDbParametersBuilder();
    builder.Create().Name("Id").Type(DbType.Int32).Value(id);
    return LoadOne(query, new HospitalRowMapper(), builder.GetParameters());
  }

  public IList<Hospital> LoadAll()
  {
    this.Log.Debug("Getting all from Hospital");
    return LoadList(QUERY_SELECT, new HospitalRowMapper(), null);
  }

  // (...)
}

Estás 2 clases tienen mucho código en común. Además, si después tengo que agregar un DAO para otra entidad tendré que volver a copiar y pegar todo. Lo ideal sería que yo sólo diga la entidad de la que quiero tener un DAO.

Se me ocurrió generalizar un poco el caso haciendo un DAO que trate con una entidad genérica. Para eso necesito:

  1. Una clase entidad. Porque no quiero persistir cualquier clase. Además me permite agrupar las entidades y manejarlas con polimorfismo si lo necesito.
  2. Escribir un DAO genérico que sirva para cualquier entidad.
  3. Escribir un DAO particular para cada entidad. Este sólo definirá cosas particulares de esa clase.

Paso 1

Es fácil, sólo debo agrupar las características de las entidades en una clase. En mi caso es que tengan un Id.

public abstract class Entity
{
  public int Id { get; set; }
}

La hago abstracta porque me parece que no tiene sentido instanciar una entidad genérica.

Luego, las entidades particulares quedan así.

public class Hospital : Entity
{
  public string Direccion { get; set; }
}

// (...)

public class Investigador : Entity
{
  public string Nombre { get; set; }
}

Paso 2

Esta es la parte donde tuve que pensar. Lo que hice fue recorrer uno de los DAOs originales e ir cambiando todas las apariciones de la entidad concreta por la entidad genérica.

public abstract class EntityDAO<EntityType> : BaseDAO<EntityType> where EntityType : Entity
{
  public EntityType Load(int id)
  {
    string query = this.BuildSelectQuery() + " WHERE id = @Id";
    IDbParametersBuilder builder = CreateDbParametersBuilder();
    builder.Create().Name("Id").Type(DbType.Int32).Value(id);
    return LoadOne(query, this.GetRowMapper(), builder.GetParameters());
  }

  public IList<EntityType> LoadAll()
  {
    this.Log.Debug(string.Format("Getting all from {0}", this.GetEntityName()));
    return LoadList(this.BuildSelectQuery(), this.GetRowMapper(), null);
  }

  protected abstract string GetEntityName();

  protected abstract IRowMapper<EntityType> GetRowMapper();

  protected virtual string BuildSelectQuery()
  {
    return string.Format("SELECT * FROM [dbo].[{0}]", this.GetEntityName());
  }
}

Acá hay varias cosas que me gustaría que se noten.

  • Estoy usando una clase genérica EntityType, la costumbre es llamar a la clase con nombres como T o Type. Yo prefiero llamarla así porque me parece que ayuda a que el código se lea mejor.
  • EntityType no es cualquier clase. Con poner where EntityType : Entity la fuerzo a que sea una entidad.
  • Agregué 2 métodos abstractos que representan la información que es particular de cada entidad. Es responsabilidad de cada implementación de EntityDAO definirlos.
  • El método BuildSelectQuery es virtual, lo que me permite cambiarlo si hay algún caso particular.

Paso 3

Ahora se puede ver dónde está el beneficio. Crear los DAOs particulares es fácil y muy extensible.

public class HospitalDAO : EntityDAO<Hospital>, IHospitalDAO
{
  protected override string GetEntityName()
  {
    return "Hospital";
  }

  protected override IRowMapper<Hospital> GetRowMapper()
  {
    return new HospitalRowMapper();
  }

  protected override void CreateParameters(Hospital hospital, IDbParametersBuilder builder)
  {
    builder.Create().Name("Direccion").Type(DbType.String).Value(hospital.Direccion);
  }
}

Algunas notas finales

En el ejemplo tengo un RowMapper para cada entidad, pero podría armar algún mecanismo con reflection para tener uno genérico que sirva para todos.

Una de las ventajas de tener este esquema es que; es menos probable que yo me equivoque creando un nuevo DAO e implementando 3 métodos, que copiando una clase más grande y modificando los nombres de cada entidad.

En realidad no lo comenté, pero esto funciona porque mi entidad se llama igual que la tabla. Si bien es normal, puede no ser el caso. Si no lo es, podemos separa el método GetEntityName en GetEntityName y GetTableName. Luego usamos cada uno donde corresponda en el EntitiDAO.

La mejor ventaja para mi es que si tenemos algún comportamiento particular del DAO de una entidad, como por ejemplo buscar hospitales por dirección, podemos agregarla al DAO particular y no se mezcla con otro código común de persistencia de cualquier entidad.

En realidad este ejemplo está simplificado. En el ejemplo real no sólo hay una consulta SELECT, también tengo INSERT y UPDATE pero es análogo a lo que hice acá.

Saludos.

Enviando por POST objetos polimórficos

Buenas.
Me parece que con ese título ya no lo va a leer nadie.

Estoy trabajando en una aplicación web que sirve para completar varios tipos formularios. Tengo un controlador que se llama FormController y no quiero escribir una acción diferente para cada formulario, me da fiaca.

Bueno, fácil. Creo un parámetro idFormulario en una acción genérica y listo.

[HttpGet]
public ActionResult Show(int idFormulario)
{
    FormModel formData = this.FormularioService.GetFormulario(idFormulario);

    //...
}

FormModel es una clase abstracta que me sirve para manejar los formularios.

Primer problema: ¿qué vista muestro?
Eso fue fácil, cada formulario tiene una vista que se llama justo igual que el formulario. Entonces puedo hacer:

[HttpGet]
public ActionResult Show(int idFormulario)
{
    FormModel formData = this.FormularioService.GetFormulario(idFormulario);

    return View(formData.Nombre, formData);
}

Ahora el gran problema: enviar el formulario por POST.

Yo deseo hacer esto:

[HttpPost]
public ActionResult Show(int idFormulario, FormModel formData)
{
    this.FormularioService.GuardarFormulario(formData);
    return RedirectToAction("Index", "Form");
}

Simple y sencillo. Pero lamentablemente no funciona. Si yo lleno y envío por POST una clase BigForm (que hereda de FormModel) me lanzará una excepción al no poder instanciar FormModel.

Esto sucede porque MVC intenta bindear la data submiteada a FormModel en lugar de a BigForm.

Mi solución, después de leer mucho en StackOverflow, fue crear un CustomBinder para mis formularios. El binder que uso quedó más o menos así:

public class FormsBinder : DefaultModelBinder
{
    // Contructor y definición de la property Service

    public Type BindingType { get; set; }

    protected override object CreateModel(ControllerContext controllerContext, ModelBindingContext bindingContext, Type modelType)
    {
        int formularioId = int.Parse(controllerContext.RouteData.Values["idFormulario"].ToString());
        FormModel formulario = this.Service.GetFormulario(formularioId);
        this.BindingType = modelType.Assembly.GetTypes().SingleOrDefault(x => x.IsSubclassOf(modelType) && x.Name == formulario.Nombre);
        return base.CreateModel(controllerContext, bindingContext, this.BindingType);
    }

    protected override PropertyDescriptorCollection GetModelProperties(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        return TypeDescriptor.GetProperties(this.BindingType);
    }
}

Paso a explicar. El binder es el encargado de construir el objeto que recibimos por parámetro en el controlador. ASP.NET MVC ya tiene uno por defecto, DefaultModelBinder. La idea es extender el comportamiento de este para que también construya las clases que heredan de la original.

Por suerte es todo muy extensible y nos permite sobrecargar el método CreateModel. En este hago 4 cosas (una por línea del método).

  1. Recupero el id del formulario, que forma parte de la url.
  2. Uso mi servicio para recuperar el objeto formulario, lo voy a necesitar para el siguiente paso.
  3. Determino, por reflection, la clase concreta que debo construir y la guardo en una variable.
  4. Dejo que el DefaultBinder haga su trabajo construyendo el objeto.

Imporatante. Con esta clase como la describí no me realizaba el bindeo. Después de mucho buscar encontré que también hay que sobrecargar el método GetModelProperies para que funcione. Es lógico, este método seguía devolviendo las propiedades de FormModel en lugar de las de nuestro formulario concreto.

Registrar nuestro Binder customizado es muy simple, basta con agregarlo al Global.asax.cs. Aprovecho para mostrar el routeo que tengo para el controlador.

protected void Application_Start()
{
    // ...
    ModelBinders.Binders.Add(new KeyValuePair(typeof(FormModel), new FormsBinder()));
    // ...
}

public static void RegisterRoutes(RouteCollection routes)
{
    // ...
    routes.MapRoute("Forms", "Form/Show/{idFormulario}", new { controller = "Form", action = "Show", idFormulario = 1 });
    // ...
}

Nótese que el registro del Binder es para un tipo el particular, la clase abstracta en nuestro caso.

Espero no sea muy largo de leer.

Chain of responsability Design Pattern – Un paso más allá

Basándonos en el post que surgió del Code & Beer, y después de una interesante charla, vimos que podíamos ir un poco más lejos con la implementación de este patrón de diseño y agregarle otros para conseguir funcionalidad automatizada.

Uno de los primeros puntos se centra en la necesidad de colocar una condición para cada uno de los elementos de la cadena, para que verifique si existe un siguiente elemento y luego ejecutarlo. Si bien esto no es un problema, sí fuerza al desarrollador a tener que colocar esta condición una y otra vez, copiando y pegando código. Si aplicamos un patrón adicional, como Null Object, podríamos omitir esta condición.

Primero, modifiquemos un poco la clase base (Para este post se modifican los diferentes objetos para poder validar contraseñas, pero conceptualmente respeta los patrones implementados en el post anterior):

public abstract class PasswordValidatorBase
{
    private PasswordValidatorBase nextValidator;

    public PasswordValidatorBase()
    { }

    public PasswordValidatorBase NextValidator
    {
        get
        {
            return nextValidator ?? new NullValidator();
        }
        set
        {
            nextValidator = value;
        }
    }

    public abstract void Validate(string password);
}

Como podemos ver en el código, la propiedad que almacena el siguiente elemento de la cadena retornará un objeto del tipo NullValidator si no se hubiera definido ningún elemento. Este objeto es un elemento inerte, el cual no ejecutará ningún código y finalizará la ejecución de la cadena.

public class NullValidator : PasswordValidatorBase
{
    public override void Validate(string password)
    { }
}

El siguiente paso será, entonces, crear un elemento para la cadena que realice una validación.

public class MaxLength : PasswordValidatorBase
{
    public override void Validate(string password)
    {
        if (password.Trim().Length >= 20)
            throw new Exception("Too long");

        this.NextValidator.Validate(password);
    }
}

La clase MaxLength se encargará, entonces, de verificar que la contraseña enviada no supere los 20 caracteres, si fuese así, arrojaría una excepción. Vale aclarar que el arrojar o no un error dependerá de cómo implementemos nuestro código y está sujeto a cambios. Finalmente, vemos que no requerimos una validación adicional para verificar la existencia de un siguiente elemento en la cadena, simplemente con realizar la llamada estaremos asegurándonos que, si existiera un elemento, este sea invocado, y si no, el objeto que representa el patrón Null Object se invocará.

A pesar de lo anterior, podemos llevar esto un poco más lejos, siendo que una cadena de validación de contraseñas puede no importar el orden de ejecución de cada validación, podríamos utilizar otro patrón, como un Factory para generar y enlazar cada elemento de la cadena automáticamente.

El siguiente código aplica este concepto y además hace uso de métodos extendidos de C# para encapsular toda la lógica y ejecución para el tipo String.

public static class StaticExtendedFactory
{
    private static PasswordValidatorBase startingChain = null;

    static StaticExtendedFactory()
    {
        startingChain = null;

        var allTypes = from t in Assembly.GetEntryAssembly().GetTypes()
                       where t.IsSubclassOf(typeof(PasswordValidatorBase))
                       && t != typeof(NullValidator)
                       select t;

        PasswordValidatorBase nextChain = null;

        foreach (var type in allTypes)
        {
            if (startingChain == null)
            {
                startingChain =
                    (PasswordValidatorBase)Activator.CreateInstance(type);
                nextChain = startingChain;
            }
            else
            {
                nextChain.NextValidator =
                    (PasswordValidatorBase)Activator.CreateInstance(type);
                nextChain = nextChain.NextValidator;
            }
        }
    }

    public static bool IsValidPassword(this string password)
    {
        try
        {
            startingChain.Validate(password);
        }
        catch (Exception)
        {
            return false;
        }

        return true;
    }
}

Nuestra factoría posee un constructor estático, el que nos asegura su ejecución en el momento en el que cualquiera de sus métodos es invocado. Dentro del constructor obtendremos todos los tipos que hereden de nuestra clase base para la cadena de responsabilidad, y se irán adicionando cada uno de ellos a la cadena.

Luego, la función IsValidPassword ejecutará toda la cadena pasándole la contraseña a validar. Por supuesto, y aquí es necesario aclarar que el manejo de excepciones puede ser tratado de forma diferente y dependerá del tipo de implementación que estemos buscando.

Finalmente, podremos llamar a nuestro validador de la siguiente manera.

if("MiPassword".IsValidPassword())
{
  //...
  //Algo de código
}

Code&Beer: Chain of responsability Design Pattern

¡Hola!

La semana pasada en Kinetica celebramos nuevamente un Code&Beer. En esta oportunidad quisimos probar un Coding Dojo al estilo Randori.

La actividad consistía en agregar funcionalidad a un código sencillo existente. Este contaba con varios tests sobre la funcionalidad que ya había y se pretendía agregar muchos más usando TDD.

La aplicación modelaba una aprobación de la orden de un ítem a través de una cadena jerárquica de empleados. Cada empleado tenía la chance de rechazar el pedido por algún motivo y si lo aprobaba era evaluado por el siguiente en la cadena jerárquica.

El código original era más o menos así (C#):

public void ProcesarCompra(Compra compra)
{
	if (compra.Costo > 500)
	{
		compra.Estado = Compra.EstadoCompra.Rechazada;
		compra.Razón = "Lean: El costo unitario es muy alto";
	}

	if (compra.Costo * compra.Cantidad > 10000)
	{
		compra.Estado = Compra.EstadoCompra.Rechazada;
		compra.Razón = "Fer: Demasiado dinero";
	}

	// Más reglas...
}

Arrancamos con 2 personas, cuando pasaban 6 minutos yo daba una señal, una salía y otra ocupaba su lugar. Les fui agregando nuevo requerimientos de a uno para que notaran cómo se complicaba el diseño:

  • Se contrata una persona en el nivel más bajo de la cadena: Luís. Luís no acepta compras de más de 15 unidades.
  • Parece que el desempeño de Luís ha sido excepcional por lo que es promovido a CEO. Ahora es el primero en juzgar las compras.
  • Luís nos recomienda –y, como es el CEO, lo obedecemos- que contratemos a Adriana. Ella acepta solo algunos pedidos, como máximo 3.

IMG_2406

Los chicos se dieron cuenta rápido que no era bueno tener todo en el mismo método y crearon un modelo con personas y reglas. Cambiando el código a algo así:

Persona lean = new Persona(new CostoUnitarioMayorA500());
Persona fer = new Persona(new CostoMayorA1000());
Persona luis = new Persona(new CantidadMayorA15());

(...)

public void ProcesarCompra(Compra compra)
{

    if (!lean.ProcesarCompra(compra)) return;

    if (!fer.ProcesarCompra(compra)) return;

    if (!luis.ProcesarCompra(compra)) return;
}

La implementación estaba bastante bien y me dejó con pocos motivos para cambiarlo por la implementación con el patrón Chain of responsability. Lo que yo tenía en mente era algo así:

public abstract class PersonaJerarquica
{
    public PersonaJerarquica SiguienteEnMando { get; set; }

    public abstract void ProcesarCompra(Compra compra);
}

public class Lean : PersonaJerarquica
{
    public Lean(PersonaJerarquica subdito)
    {
        this.SiguienteEnMando = subdito;
    }

    public override void ProcesarCompra(Compra compra)
    {
        if (compra.Costo > 500)
        {
            compra.Estado = Compra.EstadoCompra.Rechazada;
            compra.Razón = "Lean: El costo unitario es muy alto";
        }

        if (this.SiguienteEnMando != null)
        {
            this.SiguienteEnMando.ProcesarCompra(compra);
        }
    }
}

(...)

PersonaJerarquica lean = new Lean(new Fernando(new Luis(null)));

public void ProcesarCompra(Compra compra)
{
	lean.ProcesarCompra(compra);
}

La clave de esta implementación es el SiguienteEnMando y la construcción de la cadena de mando. El SiguienteEnMando desentiende un ProcesarCompra de otro. Es decir, encapsula cada persona.

Pero para mi es clave que la construcción de la cadena sea simple. En el ejemplo yo iba agregando reglas para que entendiera que es una parte del sistema flexible. Esta implementación hace muy fácil cambiar el orden de ejecución de la cadena de mando. Incluso, si lo deseáramos podemos hacerlo por configuración.

Resumiendo ventajas de esta implementación con el patrón:

  1. Encapsula las reglas.
  2. Es muy flexible ante cambios en la cadena.

¡Saludos!