miércoles, mayo 21, 2014

Interfaces, algunas ideas en paralelo

Tengo que darme el tiempo para continuar con el post de Mercurial, y al mismo tiempo, para comenzar a dar algunas vueltas sobre el desarrollo basado en interfaces... modelo de desarrollo que cada día me acomoda más...

Al desarrollar con interfaces tiendo a pensar en tomar un elemento, en este caso una clase, e ir decorándolo con atributos y/o características, sobrecargándolo semánticamente, viendo el problema que la clase ataca desde diferentes perspectivas, pero siempre dentro un modelo existente.

Esto significa que al contar con un conjunto pre-existente de interfaces, que ha ido evolucionando con el resto del proyecto, se han ido definiendo formas de enfrentar problemas diversos, pero de forma consistente.

Es quizás, ese grado de consistencia, y en muchos casos, elegancia en el resultado, el que me atrae de esta forma de programar, aún considerando las dificultades que este modelo y su curva de aprendizaje (uno debe entender la filosofía de las interfaces definidas para utilizar adecuadamente los concepto, en cierta forma, es como aprender una técnica para pintar un cuadro, digamos pintar con acuarela, en que se debe saber como difuminar los colores, el efecto de un poco más de agua, y las diferentes capas que interactuan o el orden en que se despliegan).

Un ejemplo práctico de este tipo de enfoque, si tenemos una interfaz para validar un elemento de un tipo dado, algo del estilo:

IValidacion:  bool Check(T value);
  string Message {get; }


Y se quiere procesar un Xml de nodos con data, en que se validarán el contenido de sus atributos.

Podemos definir algunos test generales, por ejemplo:
1) Test para verificar si un string es el path para un archivo que existe
2) Test para verificar si un valor es parte de un dominio

Las implementaciones de tales tests, sobre el modelo ya existente, es bastante simple, pero lo interesante es el siguiente paso, pues al analizar el procesamiento del archivo indicado, uno ve que es posible considerar una clase CheckConstraint que implementa IValidation y que tiene como propiedad una instancia de un test específico (Test), y el atributo dentro del nodo que debe ser validado, en este caso el método Check es algo de este estilo:

bool Check(XmlNode value)
{
  return (value!=null && Test.Check(value.Attributes[Field].Value));
}

y CheckConstraints es una colección de CheckConstraints que a su vez implementa la misma interfaz de IValidation, por lo que su método Check sería algo como:

bool Check(XmlNode value)
{
  bool retorno = true;  // Si la colección de Tests es vacía, entonces check da true

  foreach (IValidation test in Tests)
    retorno = retorno && test.Check(value);

  return retorno;
}

Luego tenemos una clase XmlConstraints que implementa IValidation y tiene una propiedad Test de tipo CheckConstraints, y por lo tanto sirve para aplicaa, a todos los nodos de una lista, las reglas de validación definidas, es decir, algo como:

bool Check(XmlNodeList value)
{
  bool retorno = true;
  foreach (XmlNode item in value)
    retorno = retorno && Test.Check(item);

  return retorno;
}

Como puede ver, la gracia de este modelo es que el código resultante es simple, mantenible y consistente, y fácilmente generalizable (que sería otra técnica que me gusta, el refactoring, que me recuerda a mi profesor de Algebra e Introducción al Cálculo... pero esa es otra historia de los tiempos anteriores a Noe).

Voy a escribir más de estas cosas cuando resuelva un dilema que tengo... y que dejo para explicar otro día...

No hay comentarios.: