OCP – Principio Open/Close

Continuando con el desarrollo de los principios de diseño SOLID, hoy vamos a ver en profundidad el principio OCP (principio abierto/cerrado).

Básicamente lo que nos dice este principio es que “las entidades de software (clases, módulos, funciones…) deben estar abiertas para extenderse, pero cerradas para modificación”.

Qué significa esto?

Que una entidad tiene que ser extendida sin necesidad de ser modificada internamente. Por ejemplo, deberíamos poder ampliar la funcionalidad de una clase sin necesidad de tener que modificar su comportamiento interno.

Parece simple, no?… sin embargo es uno de los principios que menos se respetamos a la hora de sentarnos a programar. Para entender este principio de una forma más clara, veamos un ejemplo que le puede resultar familiar. La idea es filtrar una lista de clientes por una serie de atributos: por localidad, nombre y deudores.

Primero  crearemos las entidades que vamos a utilizar en el ejemplo: vamos a representar las localidades en un enumerado, para simplificar la cosa, y vamos a crear una clase para representar a los clientes:

public enum Localidad
{
    Rafaela = 1,
    SantaFe = 2,
    Esperanza = 3,
    Sunchales = 4
}

public class Cliente
{
    public string Nombre { get; set; }
    public Localidad Localidad { get; set; }
    public decimal Saldo { get; set; }
}

Supongamos que en primer lugar, nos piden que necesitan filtrar la lista de clientes por la localidad a la que pertenecen. Para esto vamos a necesitar una clase que se encargue de hacer el filtro de los clientes (recuerden el principio SRP), a la cual llamaremos FiltroClientes.

El aspecto de la clase podría ser algo así:

public class FiltroClientes
{
    public IEnumerable FiltroPorLocalidad(IList clientes, Localidad localidad)
    {
        return clientes.Where(c => c.Localidad == localidad);
    }
}

Como podemos ver, el “filtrador” por localidades recibe como parámetros la lista de clientes, y la localidad por la cual filtrarlos y devuelve la lista de clientes que pertenecen a dicha localidad. Hasta acá todo perfecto, pero habitualmente lo que pasa es que el usuario comienza a pedir nuevos requerimientos. Imaginemos que ahora también quiere filtrar por el nombre y los que tienen deudas… qué es lo que habitualmente haríamos? Crear un método nuevo por cada filtro solicitado:

public class FiltroClientes
{
    public IEnumerable FiltroPorLocalidad(IList clientes, Localidad localidad)
    {
        return clientes.Where(c => c.Localidad == localidad);
    }

    public IEnumerable FiltroPorNombre(IList clientes, string nombre)
    {
        return clientes.Where(c => c.Nombre == nombre);
    }

    public IEnumerable FiltroPorSaldoNegativo(IList clientes)
    {
        return clientes.Where(c => c.Saldo < 0);
    }
}

Esto está perfecto, pero estamos violando el principio OCP. En primer lugar cada vez que tengamos que agregar nuevos filtros debemos modificar la clase FiltroClientes y por lo tanto NO está cerrado para modificación. En segundo lugar, la única forma de extender la funcionalidad de FiltroClientes es abriendo el archivo y modificarlo, por lo tanto NO está abierto a la extensión.

Entonces, como podemos hacer para respetar este principio?

Una solución es crear las especificaciones de los filtros en clases separadas, en donde internamente cada una va a implementar la forma de filtrar la información (nuevamente recuerden el principio SRP).  A su vez también para representar estas especificaciones podemos crear un template o patrón que tenga definida la estructura y el comportamiento que deben respetar dichas especificaciones. Nuestro template podría tener la siguiente forma:

public abstract class EspecificacionFiltroCliente
{
    public IEnumerable Filtrar(IList clientes)
    {
        return AplicarFiltro(clientes);
    }

    protected abstract IEnumerable AplicarFiltro(IList clientes);
}

En este caso el template es una clase abstracta que tiene definido dos métodos: el primero público que es sencillamente la acción filtrar y que es la que utilizará nuestro filtro de clientes. La acción filtrar internamente llamará a un segundo método que es el que nos encargaremos de sobre-escribir y ponerle la lógica de comportamiento correspondiente a cada especificación.

Ahora ya estamos listos para crear nuestras propias especificaciones de filtros de clientes. Por ejemplo para filtrar las localidades vamos a crear la clase FiltroLocalidad:

public class FiltroLocalidad : EspecificacionFiltroCliente
{
    private Localidad Localidad;

    public FiltroLocalidad(Localidad localidad)
    {
        this.Localidad = localidad;
    }

    protected override IEnumerable AplicarFiltro(IList clientes)
    {
       return clientes.Where(c => c.Localidad == this.Localidad);
    }
}

También vamos a reescribimos FiltroClientes:

public class FiltroClientes
{
   public IEnumerable FiltrarPor(IList clientes, EspecificacionFiltroCliente filtro)
   {
      return filtro.Filtrar(clientes);
   }
}

Finalmente veamos en un ejemplosu implementación mediante un ejemplo:

var clientes = new Cliente[] { new Cliente() { Localidad = Localidad.Rafaela, Nombre = "Sebis" },
                               new Cliente() { Localidad = Localidad.Rafaela, Nombre = "Sil" },
                               new Cliente() { Localidad = Localidad.SantaFe, Nombre = "Nico" },
                               new Cliente() { Localidad = Localidad.Sunchales, Nombre = "Fer" }
                             };

var filtrador = new FiltroClientes();
var clientesFiltrados = filtrador.FiltrarPor(clientes, new FiltroLocalidad(Localidad.Rafaela));

Ahora sí estamos respetando OCP. Como verán podemos extender la funcionalidad de FiltroClientes sin tener que modificar internamente su estructura, entonces esta cerrada para modifcación. Y podemos extenderla cuantas veces querramos simplemente creando nuevas especificaciones de filtros, entonces esta abierta para extensión.

Creo que este es uno de los principios más poderos de SOLID, pero requiere de un buen análisis por nuestra parte antes de ponernos a diseñar y crear las entidades.

Próximamente continuaremos con los restantes principios.

Conociendo a C# 4.0: Programación dinámica

Tengo que contarles que desde hace tiempo vengo programando en C# y la verdad es uno de mis lenguajes preferidos, el que más conozco y con el que me siento más cómodo. Recientemente salió la versión 4.0 y trajo algunas novedades que son más que interesantes.

Uno de los cambios principales en C# 4.0 radica en la programación dinámica, es por eso que en este primer post nos vamos a centrar en esta nueva característica.

Pero qué es un lenguaje dinámico?  Un lenguaje dinámico realiza ciertos tipos de tareas en tiempo de ejecución que a diferencia de los lenguajes estáticos se hacen en tiempo de compilación, algunas de estas tareas son re-definir o alterar tipos de datos, analizar expresiones…

Algunos ejemplos de lenguajes dinámicos son:

– Python (antes que diga algo Ariel :))
–  Ruby
–  Visual Basic y COM con su capacidad para hacer late binding

Comencemos con C# 4.0 ahora!

Tipo dynamic

En esta versión surge un nuevo tipo de datos llamado dynamic, que es la forma en que .NET le dice al compilador que no verifique los datos en tiempo de compilación y si lo haga en tiempo de ejecución, que queremos decir con esto, que errores como validaciones de tipo de datos, solo aparecerán cuando estemos ejecutando nuestro programa.

Vayamos al grano, supongamos que tenemos definido lo siguiente:

dynamic dinamico = "hola";

El compilador hasta que no ejecutemos esa porción de código, no sabe que tipo de objeto es la variable dinamico. Por lo tanto podríamos tener lo siguiente sin que nos de error en tiempo de compilación:

dynamic dinamico = "hola";
int suma = 1 + dinamico;

Ahora en tiempo de ejecución cuando lleguemos a dicha línea nos dará un error de tipo de conversión de datos, lo cual es lógico 🙂 .

Veamos otro ejemplo, supongamos que tenemos la clase definida de la siguiente manera:

public class Cuenta
{
    public Cuenta()
    {
        this.Saldo = 0;
    }

    decimal Saldo { get; set; }

    public void Depositar(decimal monto)
    {
        this.Saldo += monto;
    }
}

Ahora veamos cómo funciona nuestro tipo de datos dinámico:

Cuenta cuentaEstatica = new Cuenta();
cuentaEstatica.Depositar(1000, 100); // Error en tiempo de compilación: cantidad de parámetros incorrectos

dynamic cuentaDinamica = new Cuenta();
cuentaDinamica.Depositar(1000, 100);

Como podremos ver, la cuenta estática no nos permitirá compilar nuestra aplicación, ya que el método Depositar no acepta dos argumentos, a diferencia de nuestra cuenta dinámica que “sí” nos permite poner dos parámetros al método Depositar y compilar nuestra aplicación, pero porqué? … porque dicha expresión recién será resuelta en tiempo de ejecución.

Dynamic no es var

Leyendo lo anterior, alguien podría preguntarse, el tipo de datos dynamic no es lo mismo que var?, la respuesta es no.

Vemos el siguiente ejemplo:

dynamic tipoDinamico = "1";
var tipoVar = "1";

int sumaDinamica = 1 + tipoDinamico;
int sumaVar = 1 + tipoVar; // Error de tipo en tiempo de compilación

Si probamos compilar esta porción de código, vamos a ver que la línea 4 nos va a dar error de tipos. En este caso para el tipo var es el compilador el que infiere el tipo de datos, por lo tanto ya lo conoce antes de ejecutarlo (tipoVar sigue siendo un valor tipeado estático).

Dynamic no es object

Actualmente cuando algún método recibía o devolvía algún objeto del cual desconocíamos su tipo, utilizábamos el tipo object. Un método que retorna un tipo object pone a disposición del desarrollador la transformación al tipo que verdaderamente necesita.

Veamos el siguiente ejemplo:

public static class AdministradorDeCuentas
{
    public static object DevolverCuentaUsuario(int id)
    {
         Cuenta cuenta = new Cuenta();
         …
        return cuenta;
    }
}

Supongamos que tenemos una clase que se encarga de administrar cuentas, y un método que nos retorna un object que en este caso representaría una cuenta (no tiene demasiado sentido que devuelva un tipo object, pero a fines del ejemplo nos sirve).

Ahora supongamos que obtenemos dos “cuentas” de la siguiente forma:

dynamic cuentaDinamica = AdministradorDeCuentas.DevolverCuentaUsuario(1);
cuentaDinamica.Depositar(1000);

object cuentaObject = AdministradorDeCuentas.DevolverCuentaUsuario(1);
cuentaObject.Depositar(1000); // Error en tiempo de compilación

Como podemos ver, la cuenta dinámica si nos permite invocar al método Deposito, ya la misma será evaluada en tiempo de ejecución. En cambio, la cuenta object no se ejecutará ya que el compilador no sabe de qué tipo se trata, por lo tanto para poder hacer el depósito deberíamos tener que hacer una conversión de tipos previamente.

Espero que le sea de utilidad. Les dejos el enlace a 2 post con muy buena informaci[on sobre el tema: Miguel Angel Morán y  C# LifeStyle .

ValueProviders en ASP.NET MVC

Voy a comentarles en esta oportunidad sobre una característica de ASP.NET MVC 2 que son los ValueProviders. La documentación en MSDN es bastante pobre en este caso, pero los dejo el link para quienes quieran investigar un poco más.

Antes de comenzar recomiendo el post de Eduard Tomàs i Avellana del cual me inspiré para escribir este post.

Para hacer más fácil la explicación vamos a trabajar con un ejemplo, para ello vamos a crear una aplicación web ASP.NET MVC 2 y en primer lugar vamos a definir la clase Cliente de la siguiente manera:

public class Cliente
{
    public int Id { get; set; }
    public string Nombre { get; set; }
    public string Email { get; set; }
    public int Saldo { get; set; }
}

Seguido a esto vamos a crear un controlador, en este ejemplo lo llamaremos ClienteController y vamos a definir la acción Create (podemos utilizar la que nos crea por default Visual Studio):

[HttpPost]
public ActionResult Create(Cliente cliente)
{
    return View();
}

Por último vamos a definir la vista de la siguiente forma:

<h2>Create</h2>
<% using (Html.BeginForm()) {%>
    Nombre: <%= Html.TextBoxFor(model => model.Nombre) %>
    E-mail: <%= Html.TextBoxFor(model => model.Email)%>
    Saldo: <%= Html.TextBoxFor(model => model.Saldo) %>
    <input type="submit" value="Create" />
<% } %>

Ahora detengámonos un poco en este punto, y analicemos lo que pasa cuando hacemos un submit del formulario. Al clickear sobre el botón Create, MVC envía el formulario en una request generando los siguientes datos:

Datos de la request

Datos de la request

Podemos ver claramente que los datos que cargamos del cliente en el formulario viajan como parámetros POST, y los mismos son identificados a partir del atributo name de los controles que los contienen.  Ahora es ASP.NET MVC el responsable de hacer el binding de esos campos POST con las propiedades de nuestra clase Cliente, y de esta manera instanciar un nuevo cliente que será enviado a nuestro controlador. Para ser más precisos, quien se encarga de generar el cliente a partir de los valores de la petición es el ModelBinder (en otro post hablaremos de él) quien a su vez hace uso de los Value Providers.

Los ValueProviders son los encargados de  inspeccionar y obtener los valores de la petición y “guardarlos” hasta que sean solicitados por el ModelBinder.

Pero vayamos por parte, veamos una gráfica para que se entienda un poco mejor este proceso:

ModelBinder

ModelBinder

A grandes rasgos el proceso es el siguiente, el ModelBinder es el encargado de hacer el binding entre los valores de la request al objeto que corresponda – en nuestro ejemplo un Cliente – para luego enviárselo al controlador. Estos valores los deberá obtener de una lista de ValueProviders los cuales tienen guardarlos la información de los campos recuperados en la petición (el acceso a estos valores no es de forma directa, sino que cada ValueProvider tendrá una factoría que será la encargada de proporcionarlos al MoldelBinder, veremos esto con más detalle más adelante).

Vale aclarar que no existe un único ValueProvider, sino que pueden existir diferentes tipos, por ejemplo algunos que inspecciones los valores de los parametros POST, otros los valores de los parámetros de la URL, otros los valores de las cooquies… Además es importante tener en cuenta que el ModelBinder irá buscando los valores de cada campo que necesite por orden, y a medida que los vaya encontrando, dejará de buscarlos en los siguiente value providers (por ejemplo, si el campo Saldo esta presente en los values provider que inspeccionan los campos POST y también en el value provider que inspecciona los parámetros de la URL, el ModelBinder solamente se quedará con uno de ellos, y este valor será del primer value provider que inspeccionó).

Ahora vamos a lo interesante, crear nuestro propio value provider!. Para ello solo debemos crear y extender nuestra clase DefaultValueProvider de IValueProvider. Este tendrá como finalidad obtener un valor default para el parámetro Saldo leyéndolo desde el archivo de configuración web.config utilizando nuestra propia clase personalizada para poder accederlos:

public class DefaultValueProvider : IValueProvider
{
    private Dictionary<string, ValueProviderResult> values;

    public DefaultValueProvider()
    {
        values = new Dictionary<string, ValueProviderResult>();

        var configuracion = (ValoresDefaultConfigurationSection)ConfigurationManager.GetSection("valoresDefault");
        int saldo = configuracion.Saldo;

        values.Add("Saldo", new ValueProviderResult(saldo, saldo.ToString(), CultureInfo.InvariantCulture));
    }

    public bool ContainsPrefix(string prefix)
    {
        return values.ContainsKey(prefix);
    }

    public ValueProviderResult GetValue(string key)
    {
        ValueProviderResult value;
        values.TryGetValue(key, out value);
        return value;
    }
}

Lo primero que podemos observar es que de IValueProvider vamos a implementar los siguientes  métodos:

ConstainsPrefix: el cual nos permite saber si existe algun valor para el campo pedido.
GetValue: retorna el valor solicitado para una clave.

En el constructor de la clase, vamos a leer el valor del saldo que tenemos definido en nuestro web.config y una vez obtenido lo agregaremos a nuestro diccionario de valores, poniéndole como clave el nombre del campo y como valor un objeto del tipo ValueProviderResult el cual tiene como parámetros: el valor en sí, el valor expresado como string y por último el tipo de cultura (este objeto es el que le retornamos a ModelBinder cuando solicita el valor de un campo, como verán no es un simple valor).

Finalizado nuestro value provider deberemos crear su factory, ya que como dijimos anteriormente, el ModelBinder no accede directamente a los valores, sino que lo hace por medio de sus factories (esto entre otras cosas permite hacer más extensible nuestro código).

Las factories tendrán la responsabilidad de devolver los valores en cada petición:

public class DefaultValueProviderFactory : ValueProviderFactory
{
    public override IValueProvider GetValueProvider(ControllerContext controllerContext)
    {
        return new DefaultValueProvider();
    }
}

Es bastante simple su construcción, deberemos heredar de ValueProviderFactory y sobreescribir el método GetValueProvider, que el que vamos a utilizar para retornar nuestro DefaultValueProvider. Es interensante aclarar que desde la factory tenemos acceso al ControllerContext, por lo tanto podríamos pasarselo al constructor del ValueProvider para obterner datos del contexto actual (por ejemplo valores de la request, de las cooquies…).

Finalmente le avisamos a ASP.NET MVC que tenga presente nuestra factory, y para eso en el archivo Global.asax registramos la misma:

protected void Application_Start()
{
    ...
    ValueProviderFactories.Factories.Add(new DefaultValueProviderFactory());
 }

Ahora, solo resta eliminar del formulario el campo Saldo, para que no sea recuperado por las factories anteriores a la nuestra (es decir, las que obtienen los valores de los parámetros POST en este caso). Ahora al hacer el submit del formulario veremos que el valor de Saldo del cliente será el que hayamos definido en nuestro archivo de configuración:

Campo saldo recuperado por nuestro Value Provider

Campo saldo recuperado por nuestro Value Provider

Próximamente vamos a ver un poco más en profundidad el ModelBinder.

Minipost : formateando TimeSpan como “hh:mm:ss”

Hoy me preguntaron como podía formatear el resultado de una “resta” de la siguiente manera: “hh:mm:ss”. Una forma que encontré y me pareció práctica fue la siguiente:

public string FormatearDiferenciaFechas(DateTime fechaDesde, DateTime fechaHasta)
{
    TimeSpan resta = fechaHasta.Subtract(fechaDesde);
    return string.Format("{0:00}:{1:00}:{2:00}", (int)resta.TotalHours, resta.Minutes, resta.Seconds);
}

Espero que les sea de utilidad!

Configuraciones personalizadas en .NET

Estuve leyendo el post de Cristian Prieto y me parecio más que interesante comentarles sobre las configuraciones en .NET y como personalizarlas. Lo primero que debemos hacer es crear nuestra clase de “configuración” y que herede de ConfigurationSection, esto nos va a permitir tener un acceso directo a secciones en particular de nuestro archivo de configuración por medio de clases.

Veamos la definición de que nos proporciona MSDN sobre ConfigurationSection

La clase ConfigurationSection se utiliza para implementar un tipo de sección personalizado. Extienda la clase ConfigurationSection para proporcionar control personalizado y acceso mediante programación a las secciones de configuración personalizadas.

Ahora veamos un ejemplo simple, supongamos que tenemos en nuestro archivo de configuración una sección en particular para las configuraciones generales del sitio, por lo tanto vamos a crear nuestra clase GeneralConfigurationSection que nos permitirá tener acceso a dichas configuraciones:

public class GeneralConfigurationSection : ConfigurationSection
{
    [ConfigurationProperty("titulo")]
    public string Titulo
    {
        get { return this["titulo"].ToString(); }
        set { this["titulo"] = value; }
    }

    [ConfigurationProperty("cantidadMaximoUsuarios")]
    public int CantidadMaximoUsuarios
    {
        get { return (int)this["cantidadMaximoUsuarios"]; }
        set { this["cantidadMaximoUsuarios"] = value; }
    }
}

En el post de Cristian también explica que puede decorarse las ConfigurationProperty con otros atributos, así que les recomiendo que le peguen una mirada.

Lo siguiente será configurar dichas secciones en nuestro web.config, cada una de las secciones registran su tipo de control con una entrada en configSections:

<configSections>
    <section name="general" type="GeneralConfigurationSection, Sebis.UI.Config" />
</configSections>
<general titulo="Mi sitio web" cantidadMaximoUsuarios="100"/>

Ahora simplemente en nuestro código podremos acceder a las mismas de la siguiente manera:

var configuracion = (GeneralConfigurationSection)ConfigurationManager.GetSection("general");
string titulo = configuracion.Titulo;

Sencillo, no?