martes, junio 28, 2011

AspectJ y Scala (II)

En la entrada anterior analizamos algunas de las similitudes y diferencias existentes entre Scala y AspectJ, llevando a cabo una implementación de una caché extremadamente simple en ambos lenguajes, describiendo las ventajas y desventajas presentes en cada una de las aproximaciones. Durante esta entrada analizaremos un ejemplo de aplicación de una funcionalidad transversal como la gestión de transacciones. 

El ejemplo que aquí nos ocupa no persigue realizar una implementación detallada de control de transacciones sino simplemente ilustrar como podríamos aplicar una funcionalidad transversal mediante el uso de AspectJ o Scala.

Del mismo modo que en el post anterior, comenzamos por la aproximación basada en AspectJ. Para ello en primer lugar definimos una simple anotación que nos sirva como elemento de marcado de aquellas clases y/o métodos que se deben ejecutar bajo un contexto transaccional.

Una vez definida la anotación anterior definiremos un aspecto que sea capaz de detectar aquellos joint point en los que deseamos establecer un contexto transaccional. 

pointcut transactionalOperation() : execution(@Transactional * * (..) );

Con el pointcut anterior estaremos capturando las llamadas realizadas sobre cualquier método anotado con nuestra anotación @Transactional. Ahora necesitaremos definir un advice en el que llevamos a cabo la gestión de la transacción (nótese que este gestor de transacciones es completamente absurdo y simplemente imprime por pantalla la funcionalidad real que debería ser llevada a cabo por un gestor de transacciones operativo)


En muchas ocasiones todos los métodos de una clase necesitarán ser transaccionales, y no querremos anotar todos los métodos de dicha clase. En este supuesto podríamos utilizar anotaciones a nivel de clase que nos permitan seleccionar aquellos métodos que deseemos (por ejemplo, todos los métodos públicos).

Adicionalmente, podríamos hacer uso de los ITD y establecer la transaccionalidad a todas aquellas clases  que nosotros deseemos. Por ejemplo, supongamos que todos los nombres de nuestros servicios, los cuales deseamos que sean transaccionales, terminan con el sufijo Service. Podríamos, mediante el uso de un aspecto, añadir la anotación @Transactional a todos nuestros servicios.

declare @type : *Service : @Transactional ;

Dicho aspecto, en conjunción con el anterior, provocaría que todos nuestros servicios fueran transaccionales

En Scala, de nuevo, haremos uso de funciones de alto nivel (high order functions) de manera muy similar a la solución de la caché descrita en la entrada anterior:

Si deseamos que un método de uno de nuestros servicios sea transaccional no tendremos más que extender de la clase abstracta y utilizar la HOF anterior:

Si comparamos las soluciones aportadas por cada una de las dos alternativas tendremos que
  • En el caso de AspectJ no necesitamos anotar cada método de manera independiente puesto que podríamos hacer uso de anotaciones a nivel de clase. El nivel de granularidad que podemos alcanzar está definido a nivel de método (aunque tampoco es un problema excesivamente grande puesto que podríamos utilizar el patrón Extract Method para extraer la funcionalidad transaccional a un método sobre el cual podríamos aplicar nuestro aspecto).
  • En el caso de Scala necesitaremos recubrir nuestra lógica con la HOF definida en nuestro ejemplo anterior. En esta situación, el nivel de granularidad es notablemente superior puesto que podemos recubrir una simple parte de nuestro método
Durante esta segunda entrada hemos vuelto a confrontar Scala y AspectJ a la hora de aplicar una funcionalidad transversal, intentando plasmar las ventajas y desventajas de cada uno de ellos.

En la siguiente y última entrada de esta serie analizaremos cómo aunar lo mejor de ambos mundos en un ejemplo práctico que nos sirva como base para futuros ejemplos.

Como siempre podéis encontrar el código fuente de todos los ejemplos del blog (o casi todos :) ) en mi cuenta de GitHub, bajo el proyecto blog-examples.

Hasta pronto!

PD: perdón por el ladrillo de entrada :(.

No hay comentarios: