Académique Documents
Professionnel Documents
Culture Documents
Imagen
– Un filtro que tome dos imágenes y devuelva otra con la
Conjunto Imagen
entrante procesada diferencia entre ellas:
de filtros
(defun remove! (a b)
(and! a (not! b)))
Figura 1 Procesador de imágenes
– Un filtro que se quede con la parte superior de una
Los objetivos entonces a cumplir para el desarrollo del
imagen:
procesador de imágenes van a ser que sea fácil de
desarrollar y de mantener, así como que haga un uso (defun top-edge! (a)
(remove! a (down! a)))
eficiente de la memoria. Los motivos son evidentes:
con el primero conseguiremos de forma rápida y libre – Un filtro que se quede con la parte inferior de una
de fallos futuras mejoras del sistema; el segundo se imagen:
debe al tamaño de las imágenes, que suele ser elevado,
(defun botton-edge! (a)
por lo que conviene minimizar el uso de memoria y los (remove! a (up! a)))
requerimientos de almacenamiento.
– Un filtro que se quede con los píxeles negros de las
4.1 DEFINICIÓN DEL PROBLEMA partes superior e inferior:
Aún con la tradicional programación procedural (defun horizontal-edge! (a)
podemos implementar de una forma clara, concisa y (or! (top-edge! a)
apropiada para el dominio del problema nuestro (botton-edge! a)))
1
La sintaxis de este ejemplo no es Lisp estándar con objeto de que
sea más legible.
muestran dos diferentes diagramas de la versión sin
Para solucionarlo se puede tomar una perspectiva más optimizar del filtro hotizontal-edge! La figura 2
global del problema, tomando aquellos resultados presenta una descomposición funcional que se
intermedios como entradas de otros filtros y programar corresponde directamente con el dominio del problema.
una versión que sintetice los bucles de cada uno de los La 3 es un diagrama de flujo, donde las cajas representan
filtros de manera apropiada para implementar la los filtros básicos y las aristas el flujo de datos entre ellos
funcionalidad original, creando el menor número en tiempo de ejecución. Abajo, la caja etiquetada con a,
posible de imágenes intermedias. Así tendríamos el es la imagen de entrada.
siguiente código para el mismo procedimiento anterior
horizontal-edge!: horizontal-edge!
la aplicación. El hecho de introducir este constructor (define-filter and! …) void loop(int *i)
para los bucles posibilita que a continuación, el … {…};
lenguaje de aspectos sea capaz de detectar, analizar y
fusionar los bucles de forma mucho más fácil.
Aspect weaver
A
4.5 EL LENGUAJE DE ASPECTOS B
El diseño del lenguaje de aspectos para este ejemplo se
basa en la observación y las conclusiones que se tienen 2
1 3
del gráfico del diagrama de flujo de datos, ya que ahí se
entiende cómo se pueden fusionar los bucles. El
lenguaje de aspectos es un sencillo lenguaje procedural
que permite simples operaciones sobre los nodos del
diagrama de flujo de datos. Así el programa de aspectos …
puede detectar los bucles que pueden fusionarse y (cond ((and (eq (loop-shape node) ‘pointwise)
proceder a fusionarlos. El siguiente fragmento de (eq (loop-shape input)‘pointwise))
(fuse loop input ‘pointwise …
código es una parte de la aplicación donde se lleva a …
cabo la fusión de los bucles que tiene la misma
estructura y que están seguidos en el diagrama de flujo
Figura 4 Proceso en tres fases del entrelazador de
de datos. Primero comprueba las parejas de nodos del aspectos (aspect weaver)
grafo conectadas por una arista que tengan la misma
estructura pixelwise, esto es la que tiene un or o un En la primera fase el entrelazador de aspectos genera un
and. Aquellas que encuentre las fusiona en un único grafo de flujo de datos con el programa de componentes.
bucle, con la misma estructura y que combina de En este grafo, los nodos representan filtros básicos y las
manera adecuada las entradas, las variables del bucle y aristas el flujo de imágenes entre un filtro y otro. Cada
el cuerpo de los dos bucles originales. Véase el nodo contiene un único constructor de bucles como los
siguiente fragmento: presentados antes. Así por ejemplo, el nodo etiquetado
con A en la figura contiene el siguiente constructor,
(cond ((and (eq (loop-shape node) ‘pointwise) donde #<...> hace referencia a las aristas que llegan al
(eq (loop-shape
input)‘pointwise))
nodo:
(fuse loop input ‘pointwise
:inputs (splice …) (pointwise (#<edge1> #<edge2>) (i1 i2)
:loop-vars (splice …) (or i1 i2))
:body (subst …))))
En la segunda fase, se utiliza el programa de aspectos
Describir las reglas de composición y fusión para los para editar el grafo fusionando nodos y ajustando el
cinco tipos de bucles que se dan en la aplicación real cuerpo de los filtros de manera adecuada. El resultado es
requiere del orden de una docena de cláusulas similares un grafo con menos nodos y donde cada uno de los
para indicar cuando y cómo realizarla. Es por ello que nuevos nodos tiene ahora más operaciones básicas entre
no es posible pretender que un compilador haga por sí píxeles que antes de esta fase. Por ejemplo, el nodo
solo esta clase de optimizaciones, así como por ejemplo etiquetado con B, que corresponde a la fusión de cinco
compartir resultados intermedios o mantener el uso de bucles del original grafo, tiene el siguiente cuerpo:
(pointwise (#<edge1> #<edge2> #<edge3>) los aspectos es clara y es sencillo entender como se
(i1 i2 i3)
(or (and (not i1) i2) (and (not i3) i2)))) combinan y su efecto sobre los componentes. Si se
introdujeran cambios en los componentes o en el aspecto
Finalmente, en la tercera de las fases, un sencillo de fusión estos se reflejarían de manera sencilla sin más
generador de código recorre el nuevo grafo de los que volver a utilizar el entrelazador de código y dejarle
nodos fusionados y genera una función en C para cada hacer su trabajo. Lo laborioso que es escribir los detalles
nodo, así como una función main que llama a estas de la implementación se ha eliminado del trabajo del
funciones en el orden apropiado, pasándoles los programador, por lo que no tiene que enfrentarse a esos
resultados a cada una de la función del nodo que le pequeños detalles y minuciosidades que tan complicadas
preceda. Esta generación de código es sencilla puesto hacen las versiones eficientes.
que cada nodo contiene únicamente un constructor de
bucles donde el cuerpo está formado únicamente por La versión real de esta aplicación desarrollada en Xerox
funciones básicas entre píxeles. Palo Alto Research Center tiene 1039 líneas de código,
contando los componentes y los tres aspectos. El
Un aspecto fundamental de este sistema es que el entrelazador de aspectos, incluyendo un componente de
entrelazador no es necesariamente un compilador muy generación de código reusable, tiene 3520 líneas4. La
complejo e “inteligente”. Al usar POA hemos dejado versión programada a mano requiere 35213 líneas, lo que
que sea el programador quien defina todas las es una diferencia significativa en tamaño, pensando
decisiones sobre las estrategias implementación además que en esta el código es mucho más complejo y
haciendo uso de un lenguaje apropiado de aspectos. El delicado, debido a que está todo mezclado: la
entrelazador no necesita tomar ninguna decisión funcionalidad y las optimizaciones. Eso sí, la versión a
inteligente. Pedir al programador que se encargue de los mano es más rápida aunque menos eficiente en espacio de
aspectos de implementación podría parecer un paso memoria. En cualquier caso, la versión orientada a
atrás en el arte de programar. Sin embargo, no es tanto aspectos es unas 100 veces más rápida que la versión sin
así. Cuando por ejemplo un programador está optimizar.
definiendo un aspecto que afecta al uso de la memoria,
usar POA supone definir las estrategias de 5. CONCLUSIONES
implementación a un nivel apropiado de abstracción, La separación de conceptos es una herramienta de
mediante un lenguaje de aspectos adecuado. No se ingeniería del software que reduce la complejidad de las
requiere entrar en los detalles de implementación, ni se aplicaciones a niveles manejables para las personas y
requiere trabajar directamente con el código confuso permite a los desarrolladores centrarse en problemas
enredado. A la hora de evaluar los beneficios de una concretos, ignorando otros que en determinado momento
versión de una aplicación orientada a aspectos es no sean tan importantes. Para hacer un uso efectivo de la
importante compararla con ambas la versión clara e separación de conceptos es preciso en cada momento ser
ineficiente y la eficiente pero compleja. capaz de identificar, encapsular, modularizar y manipular
diferentes dimensiones o niveles conceptuales de
4.7 RESULTADO FINAL abstracción en cada una de las fases de vida del software,
La aplicación real del ejemplo presentado es algo más para no verse afectado por los efectos negativos que tiene
complicada. Además del aspecto aquí presentado hace la dispersión del código, el efecto dominó que pueden
uso de dos más: uno para compartir la ejecución de suponer cualquier modificación o la necesidad de
operaciones básicas comunes, reduciendo el volumen reestructuración debido a la aparición de nuevos
de éstas; y otro para asegurar que a la misma vez se requisitos. Los conceptos de corte suelen aparecer en la
tienen en memoria el menor número de imágenes fase de captura de requisitos y suelen tomar diferentes
posibles, para optimizar el uso de memoria. Los tres formas durante el proceso de desarrollo.
están escritos con el mismo lenguaje de aspectos.
Hasta antes de la POA, los paradigmas de programación
Como hemos visto en el ejemplo, la implementación se han basado en una única y dominante manera de
mediante POA ha conseguido los objetivos propuestos descomposición del software (clases, funciones, reglas...)
al principio. Se puede razonar fácilmente sobre el La POA persigue la eliminación de lo que se conoce
código de la aplicación, por lo que es además fácil de como tiranía de descomposición del software.
mantener y ha sido fácil de desarrollar, mientras que al Actualmente existen diferentes implementaciones que,
mismo tiempo es bastante eficiente. Al mantenerse con más o menos éxito, persiguen este objetivo. La que
limpio el código de los componentes, es fácil para el actualmente goza de mayor difusión es AspectJ [5], una
programador entenderlos y ver la forma en la que se
combinan unos con otros. Igualmente la definición de 4
Realmente la parte del núcleo tiene 1959 líneas. El resto es del
componente reusable de generación de código.
extensión orientada a aspectos de Java, en la que se
distinguen entre clases, que encapsulan los requisitos
funcionales del sistema, y aspectos, que encapsulan los
requisitos de corte no funcionales. Otra solución es la
aportada por IBM, Hyper/J [6], que soporta la
separación e integración de diferentes dimensiones,
entendiéndose éstas como diferentes niveles
conceptuales de abstracción. Una de ellas sería la
dimensión de las clases, donde los requisitos
funcionales tendrían cabida. Otra podría ser la de los
requisitos no funcionales, que en AspectJ
identificaríamos como aspectos (sincronismo,
concurrencia,...) y otra podría incluir las restricciones
impuestas a la aplicación que desarrollamos (tiempos
de ejecución, entornos de funcionamiento,...) AspectJ
ha apostado por encapsular las dos dimensiones hasta
ahora mejor identificadas. Hyper/J nos deja la puerta
abierta a nuevas dimensiones.
6. REFERENCIAS
1. T. Elrad, R. E. Filman, and A. Bader. Aspect-
Oriented Programming. Commun. ACM, 2001.
2. Gregor Kiczales, John Lamping, Anurag
Mendhekar, Chris Maeda, Cristina Lopes, Jean-Marc
Loingtier and John. Irwin, Aspect-Oriented
Programming, Xerox Palo Alto Research Center, 1997.
3. Karl J. Lieberherr. Adaptive Object-Oriented
Software. The Demeter Method. Northeastern
University Boston.
4. Cristina Lopes, A Language Framework for
Distributed Programming, Ph.D.thesis, Northeastern
University, noviembre 1997.
5. The AspectJTM Programming Guide, the AspectJ
Team, Xerox Parc Corporation
6. Peri Tarr, Harold Ossher. Hyper/JTM User and
Installation Manual, IBM Research, 2000.