Poa 01

40
Programación orientada a aspectos Abdiel E. Cáceres González Centro de Investigación y de Estudios Avanzados - IPN México D.F., México. 2004

Transcript of Poa 01

Page 1: Poa 01

Programación orientada a aspectos

Abdiel E. Cáceres GonzálezCentro de Investigación y de Estudios Avanzados - IPN

México D.F., México.2004

Page 2: Poa 01

Introducción

Page 3: Poa 01

Introducción

Los conceptos y tecnologías reunidos bajo el nombre "programación orientada a aspectos" (AOP, por las siglas de Aspect-Oriented Programming; o AOSD, por Aspect-Oriented Software Development) buscan resolver un problema identificado hace tiempo en el desarrollo de software. Se trata del problema de la separación de asuntos (separation of concerns). AOP no es el único intento por solucionar este problema, del que voy a hablar a continuación: hay varias propuestas, muchas de las cuales se agrupan (junto con AOP) en el campo de estudio denominado ASoC (Advanced Separation of Concerns).

Page 4: Poa 01

Separación de asuntos

El principio de separación de asuntos fue identificado en la década de 1970, plantea que un problema dado involucra

varias asuntos que deben ser identificadas y separadas. Las asuntos son los diferentes temas o asuntos de

los que es necesario ocuparse para resolver el problema. Una de ellas es

la función específica que debe realizar una aplicación, pero también

surgen otras como por ejemplo distribución, persistencia,

replicación, sincronización, etc. Separando las asuntos, se disminuye la

complejidad a la hora de tratarlas y se puede cumplir con requerimientos

relacionados con la calidad como adaptabilidad, mantenibilidad,

extensibilidad y reutilizabilidad.

Page 5: Poa 01

Separación de asuntos

El principio puede aplicarse de distintas maneras. Por ejemplo, separar las fases del proceso de desarrollo puede verse como una separación de actividades de ingeniería en el tiempo y por su objetivo. Definir subsistemas, objetos y componentes son otras formas de poner en práctica el principio de separación de asuntos. Por eso podemos decir que se trata de un principio rector omnipresente en el proceso de desarrollo de software.

Page 6: Poa 01

Separación de asuntos

Las técnicas de modelado que se usan en la etapa de diseño de un sistema se basan en partirlo en varios subsistemas que resuelvan parte del problema o correspondan a una parte del dominio sobre el que trata. Estas técnicas sufren en su mayoría la llamada "tiranía de la descomposición dominante" que consiste en guiarse al modelar, implícita o explícitamente, por una visión jerárquica determinada de la organización del sistema.

La desventaja de estas particiones es que muchas de las asuntos a tener en cuenta para cumplir con los requerimientos (en particular, habitualmente, las asuntos no funcionales) no suelen adaptarse bien a esa descomposición, como veremos más adelante.

Page 7: Poa 01

Separación de asuntos

Las construcciones provistas por los lenguajes de programación, que fueron creados para implementar los modelos generados por las técnicas de diseño existentes, reproducen las jerarquías y, por lo tanto, comparten el defecto explicado en el párrafo anterior.

En el paradigma de programación imperativa, la descomposición consiste en identificar procedimientos que resuelvan parte del problema, y la jerarquía se da en el árbol de ejecución, según el cual los procedimientos se invocan unos a otros.

En el caso de la programación orientada a objetos, la jerarquía generada en la etapa de diseño suele plasmarse en las relaciones de herencia o de composición entre objetos. Por ejemplo, algunos patrones de diseño de uso habitual como observador (observer), visitante (visitor) y mediador (mediator) exhiben estos problemas, ya que para aplicarlos es necesario adaptar a ellos más de una clase.

Page 8: Poa 01

Separación de asuntos

El problema aparece cuando un asunto afecta a distintas partes del sistema que no aparecen relacionadas en la jerarquía. En ese caso, la única solución suele ser escribir código repetido que resuelva ese asunto para cada subsistema.

Page 9: Poa 01

Separación de asuntos

Un ejemplo clásico de la programación orientada a

aspectos es el de distintos métodos de un

sistema de edición de gráficos que, luego de

modificar la representación interna,

terminan actualizando su vista en pantalla.

Asuntos diseminados

Page 10: Poa 01

Separación de asuntos

Estas responsabilidades, que aparecen diseminadas en el código atravesando partes del sistema no relacionadas en el modelo, se denominan asuntos transversales (crosscutting concerns).

Page 11: Poa 01

Asuntos transversales

Otro ejemplo, también clásico, de asuntos transversales es el logging o registro de la actividad de una aplicación. En varios puntos de ejecución, que podrían pertenecer a elementos del programa disconexos, queremos invocar un método que registra en un archivo de texto o en una base de datos el hecho de que se ha llegado a ese punto.

Page 12: Poa 01

Asuntos transversales

Las consecuencias directas de estas asuntos transversales son el código disperso y enredado (scattering and tangling). Se habla de código disperso cuando un mismo servicio es invocado de manera similar desde muchas partes del programa, como en el ejemplo que vemos en la Figura. Aquí cada barra representa un módulo del sistema, las líneas de código que invocan el servicio de logging están en rojo.

Page 13: Poa 01

Asuntos transversales

Si una misma operación tiene que acceder a varios servicios (logging, locking, presentación, transporte, autenticación, seguridad, etc), además de cumplir con su función específica, estamos ante una muestra de código enredado.

Page 14: Poa 01

Asuntos transversales

Si una misma operación tiene que acceder a varios servicios (logging, locking, presentación, transporte, autenticación, seguridad, etc), además de cumplir con su función específica, estamos ante una muestra de código enredado.

Page 15: Poa 01

Asuntos transversales

La fuente de estos problemas es que en realidad cada aplicación tiene una política sobre dónde se requiere cada uno de estos servicios; pero esa política no es explícita, está oculta como parte de la estructura del programa. Esto hace que sea difícil de entender, razonar sobre ella y mantenerla.

Page 16: Poa 01

Asuntos transversales

La solución que propone la comunidad de AOP es modularizar las asuntos transversales, justamente esa es la definición de aspecto: una incumbencia transversal modularizada.

Page 17: Poa 01

Aspectos

Ya sabemos cuál es la idea detrás de un aspecto, veamos ahora cómo se llevan a la práctica. Empecemos por ver la propuesta de AOP para resolver la dispersión de la Figura A, que se muestra en la Figura B.

A B

Page 18: Poa 01

Aspectos

Lo que se hizo fue definir un aspecto (pronto hablaremos de las partes que lo conforman) que indica que se debe ejecutar la instrucción Display.update(); al terminar la invocación a cualquier método cuyo nombre comienze con set, de una subclase de FigureElement. La notación usada está basada en AspectJ.

Page 19: Poa 01

Aspectos

Lo que se hizo fue definir un aspecto (pronto hablaremos de las partes que lo conforman) que indica que se debe ejecutar la instrucción Display.update(); al terminar la invocación a cualquier método cuyo nombre comienze con set, de una subclase de FigureElement. La notación usada está basada en AspectJ.

Page 20: Poa 01

Aspectos

Para entender cómo se aplica un aspecto, tenemos que empezar por el concepto de punto de unión (join point). Los puntos de unión son puntos en la ejecución de un programa.

Por ejemplo, "al invocar al método Line.getP1() por cuarta vez". Es importante recalcar que los puntos de unión no son posiciones en el código fuente (ni dentro de una instrucción, ni entre instrucciones), sino en la ejecución del programa.

Page 21: Poa 01

Aspectos

La frase anterior habla de la cuarta invocación de un método en una ejecución, y esto no corresponde a un punto en el código. En distintas ejecuciones podría variar qué instrucción es la que invoca por cuarta vez a Line.getP1(), por ejemplo, se podría llamar a este método dentro de un ciclo while (i<j) Line.getP1(); Dependiendo de los valores de i y j, y de lo que haya pasado antes en esta ejecución, la cuarta llamada a este método podría ser en esta instrucción o en otra.

Page 22: Poa 01

Aspectos

Ahora pasemos a hablar de un concepto un poco más complicado que el de punto de unión, que es el de pointcut. Un pointcut es un predicado, una afirmación que es cumplida por un conjunto de puntos de unión. En nuestro ejemplo de la Figura 3, aparece un pointcut: que vamos a analizar por partes.

Page 23: Poa 01

Aspectos

call(void FigureElement+.set*(..)) significa "al invocar (call) cualquier método de la clase FigureElement o de una sublclase (+), cuyo nombre comience con set (set*), que tenga void como tipo de retorno y cualquier cantidad de parámetros (..)".

Page 24: Poa 01

Aspectos

El siguiente fragmento es fácil de comprender: call(void FigureElement.moveBy(int, int)). El operador de disyunción (||) se usa para unir estos dos pointcuts y formar uno nuevo. Los puntos de unión que cumplan el pointcut compuesto serán aquellos que cumplan uno u otro de los dos.

Page 25: Poa 01

Aspectos

Además de call hay otros constructores de pointcuts, como

get (al leer el valor de una variable),

set (al modificarlo),

cflowbelow (dentro del flujo de control),

initialization (al inicializar un objeto), etc.

Y también formas de acceder al contexto como

target (clase que recibe el mensaje),

args (argumentos de una llamada), etc.

Page 26: Poa 01

Aspectos

Los pointcuts son parte de un aspecto, indican dónde (en qué puntos de unión) se va a aplicar.

La otra parte es lo que se llama un consejo (advice), que indica qué es lo que hay que hacer en esos puntos de unión.

Page 27: Poa 01

Aspectos

En la Figura, el consejo dice que hay que agregar la instrucción Display.Update(); después (after) de cada uno de los puntos de unión indicados por el pointcut. En vez de after, se podría haber puesto before (antes), after returning (después de ejecutar un método en forma normal), after throwing (después de arrojar una excepción) o around (en lugar de ejecutar el punto de unión).

Page 28: Poa 01

Aspectos

El mecanismo por el cual se combinan los aspectos con el código base se llama entretejido (weaving), y puede hacerse en distintos momentos de la vida de un programa.

Una posibilidad es llevar a cabo el entretejido en una etapa de precompilación: se toma el código base y los aspectos, y se produce nuevo código fuente con el resultado del entretejido, insertando los consejos en los puntos de unión correspondiente.

También se puede hacer durante la compilación, generando código objeto que cumpla la funcionalidad base más la de los aspectos.

Y otra alternativa es el llamado entretejido dinámico, por el cual se controla la ejecución del programa y, cada vez que se llega a un punto de unión incluido en un pointcut de un aspecto, se ejecuta el consejo asociado.

Page 29: Poa 01

Aspectos

En este ejemplo tan sencillo que vimos, aparecen ya las dos ideas más poderosas que hay detrás de los aspectos:

a) prescindencia (obliviousness) y

b) cuantificación (quantification).

Ambas están asociadas al mecanismo de construcción de pointcuts.

La prescindencia se refiere a que el programador encargado de implementar una funcionalidad específica no debería estar al tanto de las otras dimensiones que pueden afectar su código.

La cuantificación es la posibilidad de indicar en qué puntos de unión se aplicará un aspecto, sin necesidad de enumerarlos uno por uno.

Page 30: Poa 01

Prescindencia y Cuantificación

La prescindencia se corresponde con el principio de abstracción y encapsulamiento omnipresente en la ingeniería de software, es básica para poder mantener la separación de asuntos.

Si se hiciera necesario que un programador tuviera en cuenta, al escribir su código, cuáles serán los aspectos que se le aplicarán, no estaríamos logrando la separación de asuntos que planteamos como objetivo inicial. Por ejemplo, no podríamos cambiar a qué puntos de unión afectará un aspecto, sin modificar el código base.

Page 31: Poa 01

Prescindencia y Cuantificación

La cuantificación también es esencial al trabajar con aspectos.

Recuerden que hablando de asuntos transversales dijimos que cada sistema tenía una política sobre dónde se requería entrelazar un servicio.

Como los aspectos pretenden modularizar los asuntos transversales, la política debe hacerse explícita y formar parte del aspecto.

En la notación que vimos, la cuantificación está dada por el lenguaje de definición de pointcuts y, en particular, por los comodines (*, +, ..), que permiten referirse de forma genérica un grupo de puntos de unión. Es el equivalente a definir un conjunto por comprensión.

Page 32: Poa 01

Prescindencia y Cuantificación

En algunas supuestas implementaciones de AOP, se requiere que el programador del código base indique de alguna forma en su programa, en cada punto de unión, qué aspectos deben insertarse en ese lugar.

Este mecanismo viola tanto la prescindencia como la cuantificación, porque el programador no puede ignorar los aspectos y debe enumerar los puntos de unión.

Page 33: Poa 01

Prescindencia y Cuantificación

Otras implementaciones brindan herramientas para que, por fuera del código, se señale en forma interactiva dónde se espera que se entrelace un aspecto.

Este método es más limpio que el anterior desde el punto de vista de la prescindencia, porque la tarea puede llevarse a cabo independientemente de la escritura del programa.

Pero comparte con el anterior la violación del principio de cuantificación: la política no se hace explícita ni se modulariza como parte de los aspectos, está dada por las acciones del encargado de marcar a mano los puntos de unión. Incluso si el resultado de esas acciones se almacena en algún formato, los puntos de unión aparecen listados y no definidos por sus propiedades.

Page 34: Poa 01

Implicaciones en el uso de aspectos

El desarrollo de software orientado a aspectos todavía se encuentra en un estado incipiente. La mayoría de las implementaciones es de carácter experimental. La tecnología no ha sido hasta ahora claramente adoptada por la industria, aunque importantes empresas relacionadas con el desarrollo de software están financiando proyectos ambiciosos de AOP.

Page 35: Poa 01

Implicaciones en el uso de aspectos

Una de las razones para la falta de adopción puede encontrarse en la dificultad que introducen los aspectos para razonar sobre los programas.

Muchas de las técnicas de diseño y de las buenas prácticas de codificación actuales tienen por objetivo garantizar la composicionalidad del razonamiento sobre programas: no hace falta leer el código entero para entender qué es lo que hace un fragmento, se pueden extraes conclusiones sobre el comportamiento local y esas conclusiones siguen siendo válidas sin importar cómo se inserte el fragmento en un sistema mayor. Pero los aspectos pueden invalidar esta premisa, ya que permiten modificar "desde afuera" el comportamiento de una parte del programa.

Page 36: Poa 01

Implicaciones en el uso de aspectos

Existen algunas propuestas para solucionar este problema de AOP y proyectos completos de ASoC que constituyen alternativas al enfoque de aspectos, creadas con el objetivo específico de evitar alterar el comportamiento local o de hacerlo en forma predecible. Hasta el momento ninguna de estas variantes ha cobrado la relevancia suficiente como para mover a la comunidad de AOSD en esa dirección.

Page 37: Poa 01

Implicaciones en el uso de aspectos

Otro inconveniente que atenta contra la adopción generalizada de AOP es la reutilizabilidad reducida.

El principio de prescindencia garantiza el desacoplamiento en un solo sentido: el código base no depende de los aspectos.

Pero las notaciones de cuantificación y acceso al contexto como las que vimos atan los aspectos a una aplicación en particular u obligan al programador a seguir convenciones de codificación, lo cual va en contra de la prescindencia. Esto se debe al uso de comodines basados en el nombre que tienen los identificadores del código base.

Page 38: Poa 01

Implicaciones en el uso de aspectos

Siguiendo el ejemplo de la Figura, los programadores estarían obligados a poner nombres que comenzaran con set a todos los métodos cuya tarea fuera la de cambiar el valor de una propiedad que alterara la presentación en pantalla.

Page 39: Poa 01

Implicaciones en el uso de aspectos

O, alternativamente, haría falta modificar la definición del pointcut para adaptarla a otra convención (por ejemplo, si en una aplicación el nombre de estos métodos comenzara con update).

Page 40: Poa 01

Abdiel E. Cáceres GonzálezCentro de Investigación y de Estudios Avanzados - IPN

México D.F., México.2004

Contacto:

[email protected]@mazatlan.udo.mx