1. Desarrollo de Software Orientado a Aspectos
UNICEN - Facultad de Ciencias Exactas
Trabajo Final - Cursada 2010
Integrantes:
Barrios, Pablo
Cicciarelli, José
Ciolfi Felice, Marianela
Pacheco, Martín Ignacio
Pérez, César Daniel
Porchetto, Roque
Sánchez, Emiliano
Suzuki, Pedro
2. Contenido
Introducción...............................................................................................................................................3
Refactorización Manual del Concern......................................................................................................5
Refactorización Semi-Automática...........................................................................................................6
Refactorización Automática (Asistencia de la herramienta para todo el proceso)...........................9
Comparaciones entre las etapas ............................................................................................................10
Conclusión y Sugerencias.......................................................................................................................11
Índice de Figuras
Figura 1- Clases involucradas..................................................................................................................3
Figura 2 - Código del aspecto implementado de forma manual.........................................................5
Figura 3 - Pasos para la aplicación del refactoring Extract Feature into Aspect...............................6
Figura 4 - Código del aspecto obtenido en la etapa semi-automática................................................7
Figura 5 - Código final del aspecto obtenido en la etapa semi-automática.......................................8
Figura 6 - Dialogo de interacción con el agente.....................................................................................9
Figura 7 - Pre visualización de los cambios. ..........................................................................................9
Figura 8 - Código del aspecto obtenido en la etapa automática. ......................................................10
3. Introducción
El objetivo del trabajo consiste en lograr la refactorización del concern Command del
sistema JHotDraw (versión 5.4b1) aplicando diferentes técnicas de refactorización y haciendo
uso del catálogo de refactorings de Monteiro.
JHotDraw (http://www.jhotdraw.org/) es un framework en dos dimensiones para editores
de dibujos técnicos y estructurados, realizado en Java. Su diseño se basa en gran medida en
algunos patrones de diseño conocidos. Los autores originales son Erich Gamma y Thomas
Eggenschwiler.
El patrón Command permite solicitarle una operación a un objeto sin conocer realmente el
contenido de la operación, ni el receptor real de la misma. Para ello se encapsula la petición
como un objeto, con lo que además se facilita la parametrización de los métodos.
Unos de los propósitos relevantes de este patrón es que permite ofrecer una interfaz común
para invocar las acciones de forma uniforme y extender el sistema con nuevas acciones de
forma sencilla.
La refactorización permite reestructurar un código fuente (orientado a objetos, en este caso),
alterando la estructura interna del mismo pero sin modificar su comportamiento externo o
semántica. Para poder transformar a código orientado a aspectos se debe contar con las
estrategias de reestructuración de código (aspects refactorings), los cuales tienen en cuenta los
crosscutting concerns en el sistema que se está tratando.
Las clases del framework JHotDraw involucradas en este proceso de refactorización se
pueden observar en el diagrama de la figura 1.
Figura 1- Clases involucradas.
.
Para ello existen tres tipos de aspects refactorings:
1. Refactorings Aspect-Aware OO: Se refiere a aquellos refactorings orientados a objetos que
se extendieron y adaptaron para poder ser utilizados en el paradigma orientado a aspectos.
Cuando se realiza una reestructuración de software siguiendo técnicas de refactoring
orientado a objetos, es necesario tener en cuenta los aspectos y su relación con las
componentes funcionales de la aplicación.
4. 2. Refactorings de construcciones AOP (Aspect Oriented Programing): Estos presentan la
propiedad de estar orientados específicamente a elementos de la programación orientada a
aspectos. En los refactorings agrupados bajo esta segunda división se puede realizar una
subdivisión. En primer lugar aquellos refactorings que tienen un paralelo en la orientación
a objetos. En segundo lugar, hay un grupo de refactorings que son totalmente nuevos ya
que no tienen una equivalencia en OO, debido a los distintos elementos como los advices.
3. Refactorings de CCC (Crosscutting Concerns): Tiene como objetivo transformar los
crosscutting concerns en aspectos. Estos refactorings buscan agrupar los distintos concerns
que se encuentran diseminados por todo el código al modularizarlos en un aspecto.
Para llevar a cabo la refactorización se deben combinar diferentes técnicas para lograr
cubrir los posibles escenarios que se presentan al momento de migrar de un sistema OO a uno
AO.
La herramienta que se utilizó para la realización de este trabajo se denomina AspectRT
(Aspect Refactoring Tool). La misma es un plugin para el entorno de desarrollo Eclipse y se
integra con AspectJ.
Las características de AspectRT son:
Automatización de la mayor parte del proceso de migración. Es decir que dado un
código aspectizable, se da la posibilidad de aplicar un refactoring de forma
transparente al desarrollador.
Soporte para los tres tipos de refactorings mencionados anteriormente.
Vinculación con aspect mining para facilitar la tarea del descubrimiento del código
aspectizable.
La herramienta tiene un diseño flexible para poder ser extendida para soportar nuevos
refactorings.
5. Refactorización Manual del Concern
En primer lugar, se creó un aspecto, denominado Command, en el cual se volcaría todo el
código aspectizable relacionado con el concern a refactorizar.
Luego se procedió a aplicar el refactoring Move Method from Class to Inter-Type,
extrayendo el código del método execute, de la clase AbstractCommand, para colocarlo en el
método del aspecto, execute, en un principio como público.
Tanto la definición del método execute como su invocación fueron quitadas de
AbstractCommand, dado que su ejecución debería dispararse como parte de un advice de tipo
before, al alcanzar un pointcut creado para tal fin.
Dado que todas las clases que extienden a AbstractCommand, hacen un llamado a
super.execute(), y este método ya no pertenecía a la clase, fue necesario quitar la sentencia y
generalizar el pointcut del aspecto para que abarcara también a las clases mencionadas. Para
esto se utilizó la expresión regular AbstractCommand+, que hace matching con las clases que
extienden a AbstractCommand. Además se hizo uso del refactoring Extract fragment into
advice, moviendo la llamada a super.execute(), al código del advice, con la diferencia de que ya
no se invocaba a super sino a execute directamente.
Luego fue posible cambiar la visibilidad de execute, de pública a privada, ya que solamente
sería accedido desde el aspecto.
Por último, se aplicó el refactoring Encapsulate Implements with Declare Parents, dado
que AbstractCommand implementaba la interfaz Command, asociada al concern siendo
refactorizado. Básicamente, se quitó el implements Command de la clase y se colocó en el aspecto,
de la siguiente manera: declare parents: AbstractCommand implements Command. Fue
necesario además incluir la sentencia: import CH.ifa.draw.util.Command.
Figura 2 - Código del aspecto implementado de forma manual.
6. Refactorización Semi-Automática
En esta etapa comenzamos con el uso de la herramienta ya mencionada para la
refactorización. Lo primero que hicimos fue cargar el archivo XML de concerns provisto por la
cátedra. Una vez realizada la carga del mismo iteramos sobre los candidatos que se pueden
aspectizar, es decir las modificaciones que tenemos que hacerle al código orientado a objetos.
Por cada modificación, seleccionamos manualmente, basados en nuestro conocimiento del
catalogo, una de entre todas las opciones de refactorización que provee AspectRT. El
refactoring seleccionado fue, en todos los casos, Extract Feature into Aspect:
Por cada clase que extiende de AbstractCommand se mueve la sentencia super.execute() ,
del método execute, hacia el nuevo aspecto AspectCommand. Esto introdujo un nuevo
pointcut, que captura el joinpoint requerido, y un nuevo advice, que responde al pointcut y
contiene el fragmento de código mencionado, por cada extracción.
Los pasos seguidos en el asistente para la aplicación del refactoring se pueden observar en
la secuencia de imágenes de la figura 3.
Figura 3 - Pasos para la aplicación del refactoring Extract Feature into Aspect.
7. Luego usamos el refactoring Move Method from Class to Inter-type. Con este se
mueve el método execute (definido en la interfaz Command) de la clase AbstractCommand
dentro del aspecto llamado AspectCommand, como una declaración Inter-type.
El aspecto resultando de estos refactorings es el siguiente:
En este punto, el aspecto generado presenta errores de compilación en la definición de sus
advices. Este error se produce al llamar a super.execute y no poder resolver el tipo asociado a
_this en tiempo de compilación. La herramienta no considera las sentencias que involucran
llamadas a super y por lo tanto arrastra el error. Esto debió resolverse manualmente
introduciendo un método privado del aspecto llamado execute, el cual es llamado desde todos
los advices.
La introducción de este método en el aspecto solucionó los errores de código, pero continúa
presentando los siguientes problemas:
● Baja reusabilidad: Por cada clase que extiende de AbstractCommand se tiene que
realizar una “extracción de fragmento a aspecto”, introduciendo un nuevo advice
y pointcut.
● Duplicación de código: El aspecto presenta duplicación de código en los pointcuts
y advices asociados.
Por esta razón se aplicaron luego las siguientes refactorizaciones, con el objetivo de ordenar
la estructura interna del aspecto:
● Generalización de todos los pointcuts en uno solo: para esto hacemos uso de las
expresiones regulares que ofrece AspectJ, para capturar todos los joinpoints
involucrados.
● Utilización de un único advice que responda ha dicho pointcut.
Figura 4 - Código del aspecto obtenido en la etapa semi-automática.
8. Finalmente, el aspecto queda formado por: un método privado execute, un pointcut pc y un
advice de tipo before. Por otro lado, resuelve los problemas de duplicación de código y
reusabilidad de la clase AbstractCommand.
Figura 5 - Código final del aspecto obtenido en la etapa semi-automática.
9. Refactorización Automática (Asistencia de la herramienta para todo el
proceso)
En esta etapa comenzamos de igual manera, cargando el archivo XML de concerns
provisto por la cátedra. En lugar de seleccionar el refactoring manualmente, utilizamos el
agente para cada una de las modificaciones.
El agente siguiere directamente el refactoring Extract Fragment into Advice (figura 6)
para todas las modificaciones.
Figura 6 - Dialogo de interacción con el agente.
El agente solicita los nombres, tanto del pointcut como del aspecto, y luego muestra
una pre visualización de los cambios (figura 7):
Figura 7 - Pre visualización de los cambios.
10. El aspecto resultante, luego de aplicar el proceso de refactorización automático, es el
siguiente:
Figura 8 - Código del aspecto obtenido en la etapa automática.
En este punto observamos que el aspecto generado presenta los mismos errores que
sucedieron en la etapa anterior. El resultado obtenido no fue el esperado porque el agente no
tuvo en cuenta el error que mencionamos en la etapa anterior respecto del llamado al método
super.
Comparaciones entre las etapas
Si bien el código final de los aspectos resultantes de las tres técnicas utilizadas, es muy
similar, existe una diferencia entre el obtenido de forma manual, y los demás, ya que se
identificó una refactorización adicional, relacionada con la implementación de la interfaz
Command por parte de AbstractCommand.
Como punto de encuentro vale la pena mencionar que el desarrollador, al momento de
refactorizar manualmente, puede seguir un proceso similar al realizado por la herramienta, ya
que como primer enfoque podría pensar que la solución era crear un pointcut para cada clase
que extendía de AbstractCommand, y luego decidir optimizar el código orientado a aspectos,
generalizándolo.
Cabe destacar que el tiempo que llevó aplicar las técnicas fue similar dado que las
herramientas para la generación semiautomática y automática requirieron tiempo extra para
arreglar los errores presentados.
A continuación se presenta una breve conclusión sobre el trabajo desarrollado y unas
posibles sugerencias al respecto.
11. Conclusión y Sugerencias
La utilización de la herramienta para la refactorización de código orientado a objetos es
muy útil. Principalmente con sistemas grandes ya que brinda una guía al desarrollador
evitando posibles confusiones y ahorrándole tiempo.
En cuanto a la herramienta, destacamos su muy buena usabilidad, ofreciendo guías muy
intuitivas y completas para realizar los refactorings.
Con respecto a la calidad de código generado se tuvieron que realizar algunas
modificaciones en ciertos elementos del código de forma manual luego de la generación
automática de los mismos. La crítica más relevante, en este sentido, es que en el movimiento de
sentencias o fragmentos de código a un aspecto, no considera la semántica de la palabra
reservada super lo que acarrea errores en el aspecto.
Como mejora en el código vemos interesante la posibilidad de aplicar el refactoring
llamado Split Abstract Class Between Aspect and Interface. Este, como su nombre lo indica,
mueve la declaración de una clase abstracta a un aspecto y una interfaz, permitiendo que las
subclases, solo implementando la interfaz, hereden los atributos e implementaciones de los
métodos de la clase abstracta (ahora definidos en el aspecto). Esto permite emular, de cierta
forma, la herencia múltiple en Java.
En nuestro caso, mantendríamos la interfaz Command y eliminaríamos la clase
AbstractCommand, definiendo la implementación de los métodos y declaración de atributos en
un nuevo aspecto. Así, todas las subclases de AbstractCommand solo necesitan implementar la
interfaz Command y, de forma transparente, heredarían los atributos y métodos concretos que
tenia la clase abstracta.
Sería interesante que la herramienta pudiera ofrecerla en su catálogo, al ser muy
interesante por esta posibilidad de emular la herencia múltiple sin agregar nuevas
declaraciones, lo cual ofrece un código muy sencillo y fácil de mantener.