Antonio Damigo

La Programación Orientada a Aspectos (POA)

por 10 de febrero de 2013, 2417 visitas
La Programación Orientada a Aspectos (POA).? Lo que a principios de los ochenta no era más que una novedad y un planeamiento poco más que teórico para los desarrolladores, a finales de esa misma década y durante la siguiente fueron pocos los que no se rindieron ante la evidencia, el Diseño Orientado a Objetos (DOO) presentaba grandes ventajas sobre la programación procedural estructurada anterior: mejor diseño, menor complejidad, más comodidad y menos errores.? ?Desde esas fechas casi todos los proyectos se han desarrollado bajo esta técnica, pero ha sido el uso de la misma el que ha puesto de manifiesto la necesidad de dar un apretón de tuerca más y salvar las limitaciones e inconvenientes que este diseño presenta. Con este ánimo surge un nuevo paradigma, la Programación Orientada a Aspectos (POA) y como consecuencia el Diseño Orientado a Aspectos(DOA). Aunque es relativamente reciente, cada vez cuenta con más adeptos y terminará por imponerse, ya que supone un considerable avance, tanto como su en día lo fue la POO.
Introducción al Diseño Orientado a Aspectos.

1)  Inconvenientes encontrados en la POO.

Con la POO se consigue un diseño y una implementación que satisface la funcionalidad básica, y con una calidad suficiente.  Sin embargo, existen conceptos que no pueden encapsularse dentro de una unidad funcional debido a que atraviesan todo el sistema o parte de él (crosscutting concerns).  De estos conceptos podemos exponer algunos: sincronización, chequeo de errores, manejo de memoria, seguridad, entre otros.

Veamos esto en un ejemplo práctico sobre el diseño de una aplicación.

   Consideremos un ejemplo: muchos de vosotros habréis desarrollado una sencilla aplicación Web que utilice servlets como punto de entrada, donde un servlet acepta los valores de un formulario HTML, los une a un objeto, lo pasa a la aplicación para procesarlo y luego devuelve una respuesta al usuario. La primera versión del servlet podría ser muy simple, con la cantidad de código mínima necesaria para cumplir el papel que va a desempeñar. Sin embargo, el código se infla tres o cuatro veces su tamaño original debido a los requerimientos secundarios como el manejo de excepciones, la seguridad, y el logging que se han implementado. Utilizo el término requerimientos secundarios porque un servlet no debería saber nada sobre el loggin o los mecanismos de seguridad que se van a utilizar; su función principal es aceptar una entrada y procesarla.

   Si esta incluye conceptos de seguridad y sincronización,  como por ejemplo, asegurarnos que los usuarios no intenten acceder al mismo dato a la vez. Ambos conceptos necesitan que los programadores escriban un código funcional para evitar este problema a lo largo de toda o parte de la aplicación.  A la hora de efectuar un cambio o una modificación en la aplicación obligará a los programadores a recordar todas las partes del código en las que se escribieron estas funcionalidades.

   Pensemos como ejemplo, en una aplicación que requiere del registro (logging) de las acciones que realiza. Bien, estos registros "alguien" tiene que llevarlos a cabo, y es normal cargar a muchas clases con la responsabilidad de hacerlo cuando, seguramente, no sea la función principal de esas clases hacer dicha tarea. Como vemos, se trata de una misma funcionalidad (registrar acciones) que se encuentra entrecruzada en varias clases, pero que a la vez no es parte de ninguna.

   Otro ejemplo, simple de entender, es el manejo de errores. Los errores hay que tratarlos sí o si en una aplicación. Pero, desde un punto de vista "purista" de objetos, no tenemos clases que traten los errores por sí solos. Siempre las clases que definen la funcionalidad de la aplicación van a tener que lidiar con los errores, y esa no es su función principal. En cierta forma, esto hace a dichas clases menos cohesivas..
   Todos  los códigos relacionados con estas funcionalidades quedarán esparcidos a lo largo de toda la aplicación.

Las técnicas de implementación actuales tienen a implementar los requerimientos usando metodologías de una sola dimensión, formando los requerimientos a ser expresado en es única dimensión. Esta dimensión resulta adecuada para la funcionalidad básica y no para los requerimientos restantes, los cuales quedan diseminados a lo cargo de la dimensión dominante. Es decir, que mientras que el espacio de requerimientos es de n-dimensiones, el espacio de la implementación es de una sola dimensión.

2) Propuestas de la Programación Orientada a Aspectos (POA).

La Programación Orientada a Aspectos es un estilo de programación cuyo principal objetivo es lograr una adecuada modularización de las conceptos involucrados en una aplicación, es se traduce en lograr la separación entre los requerimientos funcionales de los no funcionales para obtener un mejor entendimiento de los conceptos, eliminando la dispersión del código y haciendo que las implementaciones resulten más comprensibles, adaptables y reutilizables.

La POA no es un estilo de programación distinto a las técnicas de programación anteriores, sino que es un estilo de programación que agrega nuevos elementos para permitir la modularización de los asuntos transversales. Desde las perspectiva de la POA una aplicación consiste en un conjunto de requerimientos funcionales modulares (componente base o funcionalidad básica), más un conjunto de asuntos transversales de difícil modularización (aspectos).

La POA es un tecnología que se base principalmente en la POO para la implementación de los componentes base, esto no quiere decir que no pueda utilizarse con otros estilos de programación, dado que POA también soporta programación estructural funcional.

3) Conceptos de la Programación Orientada Aspectos (POA).

-Definición de una aspecto.
Un aspecto es una unidad modular que se disemina por la estructura de otras unidades funcionales. Los aspectos existen tanto en la etapa de diseño como en la etapa de implementación. Un aspecto de diseño es una unidad modular que se entremezcla en la estructura de otras partes del diseño. Un aspecto de programa o de código es una unidad modular del programa que aparece en otras unidades del programa. [G.Kiczales, 1997].
Esta definición nos lleva a determinar que un aspecto es la unidad básica de la POA, debido a que permite modularizar los asuntos transversales presentes en una aplicación. En otras palabras, un aspecto puede ser como: “La encapsulación y la modularización de un asunto transversal”.

Los aspectos, para ser considerado como tales, deben de reunir una serie de características, entre las que caben destacar las siguientes:

   Un aspecto no debe interferir con otro.

   Cada aspecto debe ser claramente identificable.

   Los aspectos deben ser fácilmente intercambiables.

-Elementos que combina un Aspecto.

La implementación y manejo de un aspecto se basas en: Puntos de Enlace (Join Point), Puntos de Corte (Cut Point) y Avisos (Advices).

El Punto de Enlace puede ser definido como un punto en la ejecución de una aplicación,  como por ejemplo: la creación de una instancia, el manejo de una excepción, una llamada a un método, el retorno de un método, la asignación de un valor a una variable, etc.

Un Punto de Corte hace referencia a un conjunto de puntos de enlace que cumplen cierta condición, es decir, permiten exponer el contexto de ejecución de dichos puntos.

Los Avisos se definen como acciones que se ejecutan en cada punto de enlace dentro de un mismo punto de corte; estas acciones se traducen en rutinas o fragmentos de código.

Se han definido diversos tipos de avisos, la principal diferencia radica en el momento en que son ejecutados, es decir, existen avisos para ser ejecutados antes de un punto de enlace, en la misma ocurrencia del punto de enlace y después del punto de enlace.

4) Programas Orientados a Aspectos.

- Desarrollo de un Programa Orientado a Aspectos.

Las etapas explicadas con un alto nivel de abstracción para desarrollar una Aplicación Orientada a Aspectos son las siguientes:

   Descomposición de aspectos: consiste en desmenuzar los requerimientos para distinguir aquellos que son requerimientos funcionales de los que son aspectos.

   Implementación de requerimientos: consiste en implementar cada requerimiento por separado. Los requerimientos funcionales serán implementados en un lenguaje base y los aspectos en un lenguaje de aspecto.

   Recomposición: consiste en dar las reglas de recomposición que permitan combinar el lenguaje base con el o los lenguajes de aspectos a través de los puntos de enlace.

- Generar un ejecutable con un Lenguaje Orientado a Aspectos (LOA).

En los lenguajes tradicionales es suficiente disponer de un compilador o intérprete (o máquina virtual) que, partiendo del lenguaje escrito en alto nivel, genere código entendible por la máquina.

En los lenguajes orientados a aspectos, los componentes necesarios para la generación de un ejecutable son los siguientes:

1.Un lenguaje base o de componentes, que proveerá la forma de implementar la funcionalidad básica. Este puede ser un Lenguaje Orientado a Objetos o un programación estructural funcional.
2. Uno o más lenguajes de aspectos, para especificar el comportamiento de los aspectos. Estos tienen que proveer los medios para implementar los aspectos deseados de una manera intuitiva, natural y concisa.
3.Un tejedor () de aspectos que establecerá los mecanismos necesarios para enlazar o tejer los aspectos en el código base guiado por los puntos de enlace, esto lo realiza de forma transparente al programador.

Los tejedores se definen según el momento en el que se introducen los mecanismos para decidir sobre la aplicación de los aspectos, para esto existen dos formas de entrelazar el lenguaje base o de componente con el lenguaje de aspectos.

   Entrelazado o Tejido Estático.

   Entrelazado o Tejido Dinámico.

- Entrelazado Estático.

Este tipo de tejido modifica el código fuente escrito en lenguaje base en tiempo de compilación. El tejido estático introduce en el código del lenguaje base o de componentes el código de los aspectos y el código de componentes. En el tejido estático todo el trabajo se realiza en tiempo de compilación. Implica modificar el código fuente en una clase insertando sentencias en estos puntos de enlace. Es decir, el código fuente del aspecto se introduce en el de la clase.  Un ejemplo de este tipo de tejedor es el Tejedor de Aspectos de AspectJ.

Algunas de sus ventajas son:

   Disminuir la posibilidad de errores, ya que efectúa controles durante la compilación evitando el surgimiento de errores durante la ejecución.

   Evitar la sobrecarga en la ejecución, ya que todo el trabajo se realiza durante la compilación.

Las desventajas de utilizar tejido estático son:

   Aspectos menos flexibles, ya que no pueden ser creado modificados o eliminados en tiempo de ejecución.

   Difícil identificar los aspectos en el código una vez que ha tejido (código ejecutable).

La principal ventaja de esta forma de entrelazado es que se evita que el nivel de abstracción que se introduce en el 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, lo cual implica que si  se desea adaptar o reemplazar los aspectos de forma dinámica en tiempo de ejecución nos encontraremos con el problema de eficiencia, e incluso imposible de resolver a veces.

- Entrelazado Dinámico.

El tejido dinámico requiere que los aspectos existan y estén presentes explícitamente tanto en el tiempo de compilación como en el tiempo de ejecución. Para conseguir esto los aspectos se deben modelar como objetos y deben mantenerse en el código ejecutable.

Un tejedor dinámico es capaz de añadir, adaptar y remover aspectos de forma dinámica durante la ejecución. Un ejemplo de LOA que utilice un tejedor dinámico es AOP/ST, este lenguaje no modifica el código fuente ya que utiliza la herencia para añadir el código específico del aspecto a las clases. En el tejido dinámico el proceso de tejido se realiza en tiempo de ejecución.

La ventaja más importante es:

   Brindar mayo flexibilidad al programador, ya que cuenta con la posibilidad de introducir, modificar o remover un aspecto dinámicamente, es decir, en tiempo de ejecución.

La desventaja es:

   Los aspectos, al ser dinámicos, colocan en riesgo la seguridad de la aplicación, por ejemplo, se puede remover el comportamiento de una aspecto que se pueda requerir después o remover un aspecto en su totalidad y luego hacer mención a una aspecto que ya no existe.

También existen tejedores que soportan tanto entrelazado estático como dinámico, para ello deben seguir las siguientes pautas:

   Deben separarse claramente los aspectos estáticos de los dinámicos.
   Debe ser opcional la especificación de la naturaleza del aspecto.

5) Diseño Orientado a Aspectos.

La orientación a aspectos se centra en separar los componentes base de los aspectos. Esta separación inicialmente sólo se realizaba en las fases de implementación y codificación, pero a medida que este paradigma se ha hecho más conocido y aceptado han surgido propuestas que también llevan esta separación a un nivel de diseño.

Los trabajos surgidos hasta el momento proponen utilizar el lenguaje unificado de modelado (UML), el cual es un lenguaje gráfico que permite visualizar, especificar y documentar el diseño de una aplicación software.

- Ventajas de utilizar UML en el diseño Orientado a Aspectos.
Las principales ventajas de utilizar UML para el diseño de un software orientado a aspectos son [Quintero, 2000]:  

   Facilita la creación de documentación y el aprendizaje. Al tener los aspectos representados en la etapa de diseño permite que los desarrolladores tengan una visión de más alto nivel de éstos, y ayuda a que los diseñadores puedan aprender y documentar los modelos de aspectos de un modo más intuitivo.
   Facilita la reutilización de los aspectos. La facilidad de documentación y aprendizaje influye en la reutilización de la información de los aspectos. Al saber cómo se diseña y cómo afecta a otras clases resulta más fácil reutilizarlos en otras aplicaciones.

La propuesta seleccionada para ser estudiada en el presente proyecto de titulo es la confeccionada por los autores Suzuki & Yamamoto [Suzuki & Yamamoto, 1999], quienes como se dijo anteriormente se basan en extender  la  semántica de UML y de ésta forma representar los componentes base separados de los aspectos. Para entender la propuesta de estos autores es necesario conocer cómo esta construida la arquitectura del Lenguaje Unificado de Modelado (UML).

- Arquitectura de UML

La arquitectura de UML se basa en cuatro niveles de abstracción que permiten distinguir entre los cuatro niveles conceptuales que intervienen en el modelado de un sistema. Se representan por las iniciales M0, M1, M2 y M3 [Fuentes & Vallecillo, 2000].

En el nivel M0 se encuentra el modelado del sistema real. Aquí los elementos del nivel M0 son las instancias.

Ejemplo de estos elementos son:

El producto  “Peluche” pertenece a la categoría “Regalos”, en este ejemplo “Peluche” es instancia de producto y “Regalo” es instancia de categoría.

Si subimos un escalafón en el nivel de abstracción encontramos el nivel M1 en donde se representa el modelo del sistema, los elementos que conforman este nivel son los conceptos insertos en una aplicación.

Ejemplo de estos elementos son:  

“Producto”, “Categoría”, “Cliente”.  

En el nivel M2 se encuentra el modelo del modelo, es decir, el metamodelo  y los elementos del nivel M2  son las clasificaciones de los elementos del nivel M1.

Ejemplo de estos elementos son:

“Clases”,  “Atributos”,  “Métodos”,  “Asociaciones” y otros.

Dado lo anteriormente mencionado es posible concluir que existe una relación entre los diferentes niveles de UML, por ejemplo los conceptos del nivel M1 son clasificaciones de los elementos del nivel M0 y los elementos del nivel M0 son instancias del nivel M1. Esta relación se da de misma forma en los niveles superiores.  

En la propuesta de los autores Suzuki & Yamamoto los aspectos se ubican en el nivel M2 de UML de manera que un aspecto se añade como un nuevo elemento  del nivel M2.

En este nivel un aspecto posee un comportamiento similar al de una clase, es decir, pueden tener atributos, operaciones y relaciones.  

6) Representación de un aspecto con UML

Según la propuesta de Suzuki & Yamamoto, un aspecto se representa igual que una clase pero con el estereotipo
--aspecto--.

--Aspecto--
Nombre Aspecto
Atributos del Aspecto
Operaciones del Aspecto

Donde las operaciones muestran las declaraciones tejidas y cada tejido representa una operación con el estereotipo
--tejido-- [Quintero, 2000].

Una forma simple de visualizar una declaración tejida es como: la representación de los elementos que se ven afectados por el aspecto (clases, métodos o variables). Para esto es necesario hacer alusión al elemento, colocando el nombre de la clase a la que afecta el aspecto, los métodos del aspecto que se tejerán, y el valor de retorno que se obtendrá.

--Aspecto--
Nombre Aspecto                                                              
Atributos del Aspecto                                                --->            
--tejido--NombreClaseGlobal.metodo()                        
                                                                                                                                                                                             
NombreClaseGlobal
 {
    Clase 1
    Clase 2
    Clase 3
}

Dada la situación anterior se hace uso de una nota en donde se listan todas las clases a las que un aspecto determinado afecta y se llamará con un nombre general para todas las clases, de esta forma se consigue una mejor comprensión del aspecto [Chuico et al, 2004].

Por su parte los atributos son utilizados por el conjunto de declaraciones tejidas u operaciones.

7) Relación existente entre un aspecto y las clases afectadas por éste.

Como segundo punto a revisar en esta propuesta se verá qué tipo de relación es la que posee un aspecto con las clases afectadas.  En UML se definen tres relaciones básicas: Asociación, Generalización y Dependencia derivadas del  metamodelo de UML.

La relación que se da entre un aspecto y cada clase afectada  es una relación de dependencia, esta relación indica que: Para la implementación o el funcionamiento de un determinado objeto es necesario utilizar o incluir otro u otros objetos o llamadas a métodos de otros objetos. En los elementos derivados de la relación de dependencia encontramos: Abstracción, Ligadura, Permiso y Uso. Esta descomposición se muestra  de forma gráfica  en la figura siguiente.

Relación
Asociación  - Dependencia - Generalización
Abastración - Ligadura - Uso - Permiso


Dependencia de Uso: Es una declaración de que el comportamiento o la implementación de un elemento, afectan al comportamiento o a la implementación de otro elemento.

Dependencia de Acceso o Permiso: Permiso de un paquete para acceder a los contenidos de otro paquete.

Una relación de dependencia de abstracción relaciona dos elementos que se refieren al mismo concepto pero desde diferentes puntos de vista, o aplicando diferentes niveles de abstracción, es por esto que es posible determinar que los aspectos poseen una relación de dependencia de abstracción.

Para modelar esta relación en UML se ha definido un estereotipo denominado  << realiza >> [Quintero, 2000], el cual especifica una realización entre un elemento del modelo de especificación y un elemento del modelo que lo implementa.

Para definir de una forma sencilla la idea que engloba el estereotipo     << realiza >>, se puede decir que dentro del aspecto deben ubicarse las operaciones que afecten a las clases, de forma que utilizando esta relación, todos estos métodos sean parte de una forma lógica de la clase, aunque físicamente estén definidos dentro del aspecto.

En la figura siguiente se muestra gráficamente la relación de dependencia de abstracción que existe entre un aspecto y una clase afectada por el aspecto.

--Aspecto--

Nombre Aspecto
Atributos del Aspecto
Operaciones del Aspecto

--realiza--

Nombre Clase
Atributos de la Clase
Operaciones de la Clase


8) Tipos de Lenguajes POA.

COOL

COOrdination Language (COOL) es un lenguaje de dominio específico, desarrollado por Xerox, cuya finalidad es tratar los aspectos de sincronismo entre hilos concurrentes. El lenguaje base que utiliza es Java, pero en una versión modificada, en la que se eliminan los métodos “wait”, “notify” , “notifyAll” y la palabra clave “synchronized” para evitar que se produzcan inconsistencias al intentar sincronizar los hijos en el aspecto y en los componentes (clases en este caso)

En COOL, la sincronización de los hilos se especifica de forma declarativa y, por lo tanto, más abstracta que la correspondiente codificación en Java.

RIDL

Remote Interaction and Data transfers aspect Language (RIDL) en un LOA de dominio específico que maneja la transferencia de datos entre diferentes espacios de ejecución.

Un programa RIDL consiste en un conjunto de módulos de “portales”. Un portal es un encargado de manejar la interacción remota y la transferencia de datos de la clase asociada a él, y puede asociarse como máximo a una clase.

MALAJ

Multi Aspect LAnguage for Java (MALAJ) es un LOA de dominio específico focalizado en la sincronización y reubicación.

Sigue la filosofía del COOL y RIDL, indicando que la flexibilidad ganada con los LOA de propósito general, pueden potencialmente llevar a conflictos con los principios básicos de la POO. Por esta razón MALAJ propone un LOA de dominio específico, donde varios aspectos puedan ser resueltos, cada uno especializado en su propia “incumbencia”.

Tal como lo indica su nombre, el lenguaje base es Java pero en una versión restringida en la que se han eliminado los métodos “wait”, “notify” , “notifyAll” y la palabra clave “synchronized” , como sucede en COOL.

El propósito final de los creadores de MALAJ es cubrir un gran espectro de aspectos específicos, más allá de las dos mencionados anteriormente.

AspectC

Es un LOA de propósito general que extiende C. Es similar a AspectJ, pero sin soporte para la programación orientada a objetos.

El código de aspectos interactúa con la funcionalidad básica en los límites de una llamada a una función, y puede ejecutarse antes, después, o durante dicha llamada.

Como el lenguaje C es estático, el tejedor de AspectC es también estático. Dado que C es utilizado en un gran número de aplicaciones, es muy interesante poder disponer de un LOA que lo tengo como lenguaje base.

AspectC++

Es un LOA de propósito general que extiende el lenguaje C++ para soportar el manejo de aspectos. Sintácticamente, un aspecto en este lenguaje es muy similar a una clase, sin embargo, además de funciones, un aspecto puede definir “avisos” (“advice”). Después de la palabra clave “advice”, una expresión de corte (“pointcut expresión”) define el punto donde el aspecto modificará el programa,  es decir, los puntos de enlace o “join point”.  Pueden utilizarse expresiones de corte para identificar un conjunto de puntos de enlaces. Se componen a partir de expresiones de corte y un conjunto de operadores algebraicos. La declaración de los avisos es utilizada para especificar código que debe ejecutarse en los puntos de enlace determinados por la expresión de corte. Los avisos pueden insertarse antes, después o durante la ejecución de los métodos donde se insertan.

AspectJ

AspectJ es un LOA de propósito general que extiende Java con una nueva clase de módulos que implementan los aspectos. Los aspectos cortan las clases, las interfaces y a otros aspectos.

En AspectJ, un aspecto es una clase, exactamente igual que las clases Java, pero con una particularidad, que pueden contener unos constructores de corte, que no existen en Java. Los cortes de AspectJ capturan colecciones de eventos en la ejecución de un programa. Estos eventos pueden ser invocaciones de métodos, invocaciones de constructores, y excepciones de señales y gestión. Los cortes no definen acciones, sino que describen eventos. En forma similar a AspectC++, en AspectJ se definen cortes (“pointcuts”), avisos y puntos de enlace.

                                                                           por Antonio Damigo

Referencias
Rodrigo Almonacid Arismendi.
Susan Hernández Venegas.
José Joskowicz

Añadir comentario