lunes, 23 de abril de 2012

Trabajando con AOP de la mano de PostSharp

En esta ocasión vamos a estar mostrando cuestiones relacionadas a la modularidad en en diseño y desarrollo de software y es la utilización del paradigma de orientación a aspectos con la utilización del framework PostSharp para .NET.

Primeramente debemos contar con el Visual Studio .NET, en esta ocasión, trabajaremos con la versión 2010 y para trabajar con aspectos, también podríamos llamar en este caso programación orientada a atributos, haremos uso del framework PostSharp.

Para las personas provenientes del mundo Java, los atributos vendrían a ser los annotations.

Mostraré un ejemplo sencillo con dos fragmentos de código, el primero sin el enfoque orientado a aspectos y el otro adoptando aspectos propiamente:


A continuación exponemos un método como fragmento de código en C# .net, que intenta realizar una división entre dos números enteros, en caso de haber alguna excepción o error, se registra el error en un archivo de texto:

Ejemplo de Logging sin PostSharp

static double Divide(int num1, int num2)
{
        try
       {
               return num1 / num2;
       }
       catch (Exception ex)
      {
              File.WriteAllText("logFile.txt", ex.ToString());
              return 0;
      }
}

La idea de la exposición del código anterior es observar las ventajas que ya de por sí nos brinda el paradigma de orientación a objetos a la hora de codificar (encapsulamiento, herencia y polimorfismo) y poder además realizar una comparación con la programación orientada a aspectos. Podemos fijarnos, sin embargo, que una de las cosas que la programación orientada a objetos no consigue manejar de forma adecuada es el comportamiento relacionado a las incumbencias transversales en un sistema, como lo es en este caso el campo de aplicación de Logging.

Ahondando detalladamente el código anterior podemos establecer que este mecanismo de bloques try-catch se repetirá en todos los métodos, ya sean funciones y procedimientos de módulos y clases que posea el código fuente en toda la aplicación y por ello obtendremos mucho código repetido, desperdigado y esparcido, por este motivo urge la necesidad de mejorar el diseño de lo anterior, inclusive aún si contamos con una abstracción a nivel de clases de la lógica de Logging nos veremos forzados a no olvidar nunca la llamada al método que realiza la tarea de Logging propiamente.

A continuación, exponemos el código fuente en C# .net resultante ya aplicando el paradigma de programación orientada a aspectos, utilizando parte del framework PostSharp, con el objetivo de comparar las dos implementaciones en ambos paradigmas o técnicas de programación:

Ejemplo de Logging AOP con PostSharp


[Logging]
static double Divide(int num1, int num2)
{
        return num1 / num2;
}

Podemos fijarnos que mediante una anotación o atributo (annotation/attribute) [Logging] expresada en la primera línea, estamos “llamando”, por decir de alguna forma, a la tarea de Logging en el caso de que surja una excepción y de manera con este atributo implementado como aspecto se separan y distinguen el código de la funcionalidad básica y el atributo perteneciente al aspecto de Logging. Cabe destacar que las anotaciones y atributos son unos mecanismos que sirven para añadir metadatos a las clases, métodos, campos, parámetros, variables locales y paquetes que se utilizan en tiempo de ejecución y su utilidad radica en interactuar con los elementos de programa y en cierta manera modificar su comportamiento dependiendo de determinados factores.

A continuación un código de ejemplo en el lenguaje C# .net con el framework PostSharp, donde se implementa el Logging como aspecto de la siguiente manera:

Definición de Aspecto de Logging en PostSharp

[Serializable]
public class LoggingAttribute : OnExceptionAspect
{
         public static void Log(object ex)
        {
                   File.WriteAllText("logFile.txt", ex.ToString());
        }

        public override void OnException(MethodExecution eventArgs)
       {
                  Log(eventArgs.Exception);
       }
}

Resumiendo lo anterior podemos concluir que la utilidad que nos proporciona esta nueva forma de encarar este problema consiste en separar las incumbencias de la funcionalidad básica perteneciente a la lógica del negocio (business logic) y las características no funcionales que en este caso se implementan como aspecto. La manera como se logra separar esto es mediante la implementación del aspecto como una unidad separada del código de la funcionalidad de tal forma a que estos no se mezclen y que esto pueda ser más legible, mantenible y escalable con bajo acoplamiento.

2 comentarios:

  1. Buenisimo Diego, ahora en lugar de utilizar directamente el objeto File, que no manejaria concurrencia de escritura y tendria problemas si se utiliza multithreading con las clases con AOP, estaria genial utilizar log4net, que es facilmente configurable, todo se puede colocar en el .config de la aplicacion y luego utilizar un singleton estatico haciendo referencia al objeto logger dentro del "void Log()" Logger.Log.Error(ex); y listo, con el log4net podes tener rotacion de archivos por dia y control del tamaño de los mismos y muchas otras ventajas. logging.apache.org/log4net/ :)

    ResponderEliminar
  2. Claro, esa sería otra perspectiva más todavía por lo que decis estando en un contexto de concurrencia que puede ocasionar problemas con los famosos temas de "Race Condition" y exclusión mutua, con PostSharp se tiene peor acoplamiento por decir así que con los esquemas basados en entornos configurables XML como son log4net, Entreprise Library, entre otros.

    Lo bueno de los entornos basados en XML para AOP es que son más mantenibles y adaptables, pero quizás en performance son un poco menos efectivos de aquellos en los que se realizan con entretejido estático, entiéndase compilado o postcompilado que es el caso de PostSharp o los que poseen esquemas de entretejido en tiempo de carga.

    Pero bueno para esa comparación se debería ver trabajos investigativos de Benchmarking entre los frameworks de AOP basados en XML o aquellos que no utilizan XML.

    ResponderEliminar