PROGRAMACIÓN ORIENTADA A ASPECTOS.
CONCEPTOS CLAVES
CONCEPTO (Concern):
Es un requerimiento específico que debe ser implementado para satisfacer las necesidades del sistema [1].
Así como en la ingeniería de software se propone una clasificación para los requerimientos (funcionales y no funcionales), la POA también propone que los conceptos o concerns se pueden clasificar en componentes y aspectos.
COMPONENTE (Component):
Son las partes del código que pueden ser encapsuladas claramente. Estas partes suelen estar relacionadas con las funcionalidades del sistema [2].
ASPECTO (Aspect):
“Un aspecto es una unidad modular que se disemina por la estructura de otras unidades funcionales. Un aspecto de diseño es una unidad modular del diseño que se entremezcla en la estructura de otras partes del diseño. (G. Kiczales).“
Por lo general, los aspectos no suelen hacer parte de las funcionalidades del sistema, sino más bien a propiedades que afectan el desempeño del mismo [2].
Ejemplos de aspectos:
- Uso de memoria
- Persistencia de datos
- Seguridad
- Sistemas de registros (logger)
- Manejo de errores
SEPARACIÓN DE CONCEPTOS (separation of concerns):
A pesar de que la separación de conceptos no es exclusiva de la POA (y aunque ya se haya hablado del tema en la filosofía del paradigma), la POA hace uso de este término y señala la importancia de encapsular, abstraer y separar los componentes de los aspectos. Esto con el objetivo de hacer el código más mantenible y evitar el código enmarañado.
La separación entre aspectos y componentes es tan evidente que usualmente se utilizan lenguajes diferentes para programar los aspectos y los componentes [2]. Por lo general se usan lenguajes orientados a objetos como Java para implementar los componentes [1].
Cualquier lenguaje que quiera aplicar este paradigma, debe proporcionar herramientas suficientes para permitirle al programador implementar de buena forma esta separación de componentes.
PUNTO DE UNIÓN/ENLACE (Joint point):
Punto de ejecución dentro del sistema donde un aspecto puede ser conectado:
- Llamada a un método
- Lanzamiento de una excepción
- Modificación de un campo.
CONSEJO(Advice):
Es la implementación del aspecto, es decir, contiene el código que implementa la nueva funcionalidad. Se insertan en la aplicación en los puntos de unión. Dentro de ellos podemos encontrar:
- before : Esta anotación ejecuta un advice antes de la ejecución del punto de corte especificado. Ej: justo antes de entrar al getter, o al constructor, etc.
- after returning: Esta anotación ejecuta un advice después de la ejecución del punto de corte especificado, siempre que el método del punto de corte retorne de forma correcta (sin generar errores).
- after throwing: Esta anotación ejecuta un advice después de la ejecución del punto de corte especificado, si el método del punto de corte genera una excepción. Podemos tanto acceder a la excepción generada como restringir el tipo de las excepciones que nos interesan.
- after: Esta anotación ejecuta un advice tras la ejecución de un método, sin importar si fue por exception o por flujo normal (return)
- around: Cuando el flujo llega a ejecutar el join-point, permite que nuestra lógica pueda determinar si proceder o no mediante el llamado al método proceed().
A continuación se muestra un Consejo que fue declarado de manera anónima. Esto significa que no se declaró un Pointcut o punto de corte antes del Consejo.
PUNTOS DE CORTE (Pointcut):
Define los consejos que se aplicarán a cada punto de cruce. Un pointcut es un predicado o condición para la aplicación de un aspecto.
Se puede entender más claramente en la siguiente imagen, en la que el programa hace un llamado a un advice, este advice se definirá a través de un pointcut que contará con diferentes joinpoints del cual podrá escoger uno o varios aspectos para ser ejecutados (Algo enredado, pero más adelante se explica mejor esa diferenciación entre pointcut y joinpoint).
A continuación un ejemplo de un Punto de Corte (Pointcut) y también un consejo declarado por un pointcut.
Joinpoints por Categoría:
Algunos Pointcuts importantes:
PUNTOS DE CORTE VS PUNTOS DE ENLACE. VAMOS CON EL EJEMPLO...
Cuando sales a comer a un restaurante, estando en él, miras el menú y hay varias opciones que se pueden escoger de platos fuertes, ensaladas, postres, etc. Después de ver que hay en el menú escoges uno o más de estos platos, pero hasta que estos no sean ordenados y el mesero no te los traiga son solo "oportunidades para cenar".
Los joinpoints son las opciones que hay en el menu y los pointcuts son los platos que se ordenan. Hablando dentro del ámbito de la programación, un joinpoint es una oportunidad dentro del código para la aplicación de un ASPECTO; Una vez se toma esa oportunidad y se selecciona uno o más joinpoints, al aplicar un ASPECTO de ellos se tendrá un pointcut.
De manera resumida:
Un Joinpoint es un lugar individual en donde se puede ejecutar el código. P.ej. "Cuando un método arroja una excepción".
Un punto de corte es una colección o conjunto de Joinpoints. P.ej. "Cuando un método en la clase Foo arroja una excepción".
Pero bueno, a nosotros nos gusta ver como se verían todos estos conceptos aplicados ya en un programa. Supongamos que tenemos una tienda, la cual tendrá diferentes empleados. El administrador de la tienda va a tener todo el manejo de los empleados, incluyendo todas las operaciones CRUD (Create, Read, Update, Delete), hasta cómo será el inicio de sesión a la aplicación por parte de los empleados. Este inicio de sesión o Loggin será el Aspecto que tendrá nuestra aplicación.
La imagen a continuación explicará claramente donde estarían cada uno de los conceptos anteriormente mencionados dentro de un programa. Este programa fue implementado utilizando Spring AOP + AspectJ.
Tal vez aun no queden claros estos conceptos mencionados anteriormente, pero en secciones posteriores encontrarán más ejemplos que ayudarán a entender mejor el paradigma de Programación Orientada a Aspectos.
INTRODUCCIÓN (Introduction):
Permite añadir métodos o atributos a clases ya existentes. Un ejemplo en el que resultaría útil es la creación de un Consejo de Auditoría que mantenga la fecha de la última modificación de un objeto, mediante una variable y un método setUltimaModificacion(fecha), que podrían ser introducidos en todas las clases (o sólo en algunas) para proporcionarles esta nueva funcionalidad.
DESTINATARIO (Target):
Es la clase aconsejada, la clase que es objeto de un consejo.
RESULTANTE (Proxy):
Es el objeto creado después de aplicar el Consejo al Objeto Destinatario.
Estas definiciones de Target y proxy se entienden mejor en la siguiente imagen, donde claramente se ve que la clase aconsejada o Target es la clase FooService y el objeto creado Proxy después de aplicar ese Consejo es FooServiceProxy
TEJEDOR (Weaver):
El tejedor tiene un papel similar al del compilador en otros paradigmas, se encarga de mezclar los diferentes componentes con los aspectos, ayudándose de las reglas de recomposición que proporcionan los puntos de enlace [1].
El resultado de este proceso de tejido (o weaving) es un código ejecutable de todo el sistema [1].
Este proceso puede ocurrir a lo largo del ciclo de vida del programa:
- Aspectos en Tiempo de Compilación.
- Aspectos en Tiempo de Carga, los Aspectos se implementan cuando el Objeto Destinatario es cargado.
- Aspectos en Tiempo de Ejecución.
Tipos de Entrelazado:
-
Entrelazado Estático:
El entrelazado estático implica modificar el código fuente de una clase insertando sentencias en estos puntos de enlace. Es decir, que el código del aspecto se introduce en el de la clase. Un ejemplo de este tipo de tejedor es el Tejedor de Aspectos de AspectJ.
La principal ventaja de esta forma de entrelazado es que se evita que el nivel de abstracción que se introduce con la programación orientada a aspectos se derive en un impacto negativo en el rendimiento de la aplicación. Pero, por el contrario, es bastante difícil identificar los aspectos en el código una vez que éste ya se ha tejido. -
Entrelazado Dinámico:
Una pre condición o requisito para que se pueda realizar un entrelazado dinámico es que los aspectos existan de forma explícita, tanto en tiempo de compilación como en tiempo de ejecución.
Para conseguir esto, tanto los aspectos como las estructuras entrelazadas se deben modelar como objetos y deben mantenerse en el ejecutable. Dado un interfaz de reflexión, el tejedor es capaz de añadir, adaptar y borrar aspectos de forma dinámica, si así se desea, durante la ejecución.
Este tejedor también tiene en cuenta el orden en el que se entremezclan los aspectos. Esto lo resuelve asignando una prioridad al aspecto. El aspecto que tenga asignado un número menor es el que se teje primero, y por lo tanto, aparecerá antes en la jerarquía de herencia.
El principal inconveniente subyacente bajo este enfoque es el rendimiento y que se utiliza más memoria con la generación de todas estas subclases.
Una de las primeras clasificaciones de las formas de combinar el comportamiento de los componentes y los aspectos fue dada por John Lamping:- Yuxtaposición: Consiste en la intercalación del código de los aspectos con los componentes. La estructura del código mezclado quedaría como el código base con el código de los aspectos añadidos en los puntos de enlace. En este caso, el tejedor sería bastante simple.
- Mezcla: Es lo opuesto a la yuxtaposición, todo el código queda mezclado con una combinación de descripciones de componentes y aspectos.
- Fusión: En este caso, los puntos de enlace no se tratan de manera independiente, se fusionan varios niveles de componentes y de descripciones de aspectos en una acción simple.
VIENDO TODOS ESTOS CONCEPTOS ANTERIORMENTE MENCIONADOS, SE PUEDE VER LA DIFERENCIA EN LA ESTRUCTURA DE LA IMPLEMENTACIÓN ENTRE LOS LENGUAJES TRADICIONALES Y LOS LENGUAJES DE ASPECTOS.
COMO SE VE, EL CONCEPTO DEL TEJEDOR SE VUELVE FUNDAMENTAL EN LA PROGRAMACIÓN ORIENTADA A ASPECTOS. ADEMÁS QUE LA IMPLEMENTACIÓN DEJA DE SER UNA IMPLEMENTACIÓN SECUENCIAL Y PASA A SER UNA IMPLEMENTACIÓN MODULARIZADA.
En la anterior imagen se puede observar gráficamente cómo funciona el tejedor. El tejedor tendría las siguientes repercusiones dentro del código final:
Programación orientada a aspectos Ilustrada:
Sabemos que puede resultar un poco difícil comprender todos estos conceptos de la programación orientada a aspectos. Por eso, a continuación, vamos a mostrar de manera gráfica los elementos mencionados anteriormente.
Imágenes tomadas de [3]
Referencias:
- [1]R. Laddad, AspectJ in action. Greenwich, CT: Manning, 2004.
- [2]G. Kiczales et al., "Aspect-oriented programming", 1997. Available: https://www.cs.ubc.ca/~gregor/papers/kiczales-ECOOP1997-AOP.pdf. [Accessed 7 June 2020].
- [3]M. Jonathan., "Aspect Oriented Programming for Babies", 2023. Available: https://manerajona.medium.com/aspect-oriented-programming-for-babies-cb567cc85035. [Accessed 20 November 2023].