Documentos de Académico
Documentos de Profesional
Documentos de Cultura
Funcionales
Gerson Samaniego, José Pulido
Universidad de los Andes
gj.samaniego35@uniandes.edu.co, jc.pulido58@uniandes.edu.co,
Resumen.
Incluir requerimientos no funcionales (RNF) en una aplicación de forma
sencilla para el desarrollador es una de las características que debería
ofrecer un modelo de componentes. Lograr que el desarrollador se centre en
el diseño e implementación de la lógica funcional permite obtener mejores
resultados en las aplicaciones. En este artículo planteamos una solución
para incluir RNFs en un modelo de componentes. La estrategia consiste en
definir los RNFs como componentes no funcionales (CNF) y en definir la
composición de éstos con componentes funcionales (CF) u otros CNFs de
manera externa. Para expresar la interacción entre los componentes
proponemos un lenguaje de dominio específico orientado a aspectos.
Ilustramos nuestra propuesta con un caso de estudio de una aplicación de
comercio electrónico en donde incluimos algunos requerimientos no
funcionales.
Palabras claves.
Programación orientada por aspectos (AOP), Software basado en
componentes (CBSD), Requerimientos no funcionales.
1 INTRODUCCIÓN
Componentes
Representan funcionalidades que pueden estar expresadas en términos de contratos
ofrecidos (facetas), contratos requeridos (receptáculos) y un conjunto de fábricas que
permiten instanciar el componente. La figura 2 muestra un ejemplo de componente:
Conectores
Los componentes en Gaita se comunican por medio de conectores. Un receptáculo de un
componente espera poder ser resuelto por la faceta de otro. El Conector es el elemento
encargado de unir el receptáculo y el componente. El conector puede encerrar la lógica de
localización de los componentes requeridos, ocultando dicho trabajo al componente. De
ésta forma, el componente tiene sólo la lógica que le corresponde.
4 ESTRATEGIA DE SOLUCIÓN
Nuestra propuesta para incluir RNF, busca principalmente cumplir con algunas de las
premisas del CBSD relacionadas con los componentes: independencia del contexto,
comunicación por medio de las interfaces, separación de responsabilidades y
reutilización. En cuanto a la separación de responsabilidades, se intenta separar las
preocupaciones transversales asociadas a RNFs mediante técnicas de AOP.
La separación de la lógica funcional de la no funcional tiene varias ventajas [2]:
código menos enredado, fácil de depurar y mantener, reutilización de la lógica no
funcional, el desarrollador sólo se centra en la lógica funcional, etc.
Composición de Componentes
La propuesta se basa en composición de componentes no funcionales con
componentes funcionales1 y en la expresión de la interacción entre ellos de manera
externa (usando sus interfaces). Se trata de agregar lógica no funcional a un componente,
componiendo éste con otros predefinidos que ya implementan lógica no funcional. Por
ejemplo, si se quiere agregar manejo de seguridad al componente intermediario de E-
Commerce - CF (Componente Funcional), se asocia éste con un componente de seguridad
- CNF (Componente No Funcional) como se muestra en la figura 5.
Componentes No Funcionales
Cuando un desarrollador de RNFs identifica la necesidad No funcional, lo primero que
debe hacer es encapsularla en un componente con interfaces bien definidas (el CNF). Por
ejemplo, un CNF de seguridad puede ofrecer servicios como autenticación y autorización,
un CNF de persistencia servicios como guardar, actualizar y consultar. Los servicios
ofrecidos por los CNFs deben ser genéricos, es decir, no dependen de los CF finales, para
así permitir la reutilización.
Componentes Funcionales
Un punto clave de la propuesta es que tanto el CF como el CNF se desarrollan sin
conocerse. Una vez creado el CF, solo se puede aplicar lógica no funcional usando sus
interfaces, evitando la intrusión sobre su implementación. Con ésta limitación, es posible
que no todos los RNF puedan ser aplicados, pero es una forma de garantizar
desacoplamiento y reutilización.
1
Katalina Marcos [14], presenta en su tesis la composición de requerimientos no funcionales mediante
patrones de composición
2
La idea original de expresar la interacción mediante un lenguaje la mostraron Anis Charfi, Michel Riveill
y Mireille Blay-Fornarino en Transparent and Dynamic Aspect Composition. [1]
aplicando uno después de otro, por ejemplo: aplica Logger y obtiene su CF’ con
funcionalidad de logging; aplica seguridad a su CF’ y obtiene su CF’’ con funcionalidad
de logging y seguridad, y así sucesivamente.
Es posible que la interacción básica e incluso la secuencia de ellas, no sea suficiente
en escenarios más complejos. Por ejemplo, en E-Commerce pueden interferir más de un
RNF a la vez, en el momento de ejecutar una orden de pedido: el Intermediario tiene ciclo
de vida con estado, seguridad y logger, el Proveedor tiene estado persistente y seguridad,
el componente de Pagos tiene seguridad y logger, y todos deben tener en cuenta el
manejo transaccional distribuido. Para resolver casos más complejos de interacciones
nuestro modelo se puede extender creando interacciones complejas que permitan
expresar la relación del CF con más de un CNF a la vez.
No hace parte del presente trabajo indicar la forma correcta de la aplicación de los
RNFs ni el control de las posibles interferencias al aplicar más de uno a la vez. Un
desarrollador de aplicaciones basadas en componentes debe ser conciente de las
complejidades que surgen mientras ensambla su aplicación con lógica no funcional.
Programación Orientada a Aspectos en el ISL
Antes de mostrar un ejemplo de interacción en el ISL definiremos algunos conceptos
adoptados de AOP:
Join-Points: Son puntos bien definidos que se pueden interceptar en el flujo del
programa. Inicialmente, nuestro lenguaje sólo soporta los Join-Points que son alcanzados
cuando:
- Se crean nuevas instancias del un componente
- Se liberan instancias de un componente
- Se invocan servicios (métodos) del componente
Pointcuts: Permiten seleccionar o filtrar JoinPoints. Los pointcuts están orientados a
las propiedades asignadas a los servicios de los componentes. Trabajos parecidos en AOP
donde se intercepta con base en propiedades o meta-data, los podemos encontrar en
Aspectivity [22] y AspectJ 5. El siguiente es un ejemplo de pointcut:
pointcut logging() : call(@LogMessage);
En el ejemplo, se define el pointcut logging que selecciona los joinpoints alcanzados
cuando se invoca la ejecución de cualquier método al que se haya asignado la propiedad
LogMessage.
Pointcuts soportados por el ISL:
- call(@Propiedad): pointcut asociado a la invocación de un servicio en el que
esté presente la propiedad dada.
- if(condicion): permite evaluar los valores de las propiedades
- creation(@Propiedad): asociado a la creación de instancias del componente
- destruction(@Propiedad): asociado a la destrucción de instancias del
componente
- @Property(propiedad): pointcut primitivo que permite asignar la propiedad
del contexto a la variable propiedad definida como parámetro del pointcut.
Advices: Junto con los pointcuts, definen el punto exacto a interferir (Antes, después
o reemplazo) más las instrucciones a ejecutar cuando el Join-Point sea alcanzado. El
código (Java) del cuerpo del advice resuelve la interacción entre los componentes.
Ejemplo de interacción del CNF de seguridad:
package uniandes.gaita.rnf.Security;
import uniandes.gaita.rnf.security.property.RolesAllowed;
import uniandes.gaita.rnf.security.cnf.ISecurity;
import uniandes.gaita.rnf.security.interaction.ISecurityAux;
@InternalReceptacle("SecurityService")
private ISecurity security;
@Receptacle
private ISecurityAux security;
Mediadores
El mediador, al igual que en otros modelos de componentes (EJB por ejemplo), es un
componente que se antepone a los llamados del cliente sobre el CF para ejecutar la lógica
adicional necesaria. El cliente final recibe una instancia del mediador y no del CF como
tal (aunque él no lo sabe). El componente es generado cuando se interpreta la interacción.
El código Java de los advices forma parte de los métodos del mediador. Cuando un
método del CF necesita de lógica no funcional (porque una propiedad asociada a él así lo
describe) dicha lógica queda en el método equivalente en el mediador.
Resumen de la solución
Para la ejecución de la propuesta se define un marco de trabajo basado en los diferentes
roles que intervienen. Básicamente, se busca abstraer de la complejidad del manejo de los
RNF a los desarrolladores finales, quienes pueden crear su CF sin pensar en la lógica No
Funcional.
Solución en E-Commerce
Con base en la solución provista, se implementaron algunos RNF para el caso de estudio
del presente artículo. Intermediario, Proveedor y Despachador son componentes
funcionales orientados a servicios, y sobre ellos se aplicaron seguridad, logger y manejo
de estados. Destino, Producto y Cuenta son componentes funcionales que representan
entidades del negocio, y sobre ellos se aplicó persistencia. El requerimiento no funcional
de transacciones no se tuvo en cuenta en ésta primera aproximación.
5 IMPLEMENTACIÓN
6 TRABAJOS RELACIONADOS
En esta sección presentamos los principales modelos de componentes: EJB [24], CORBA
CCM [18], Microsoft .NET [16] y Fractal[5]. Mostramos una breve introducción a la
programación orientada a aspectos AOP[2] y comparamos estos trabajos con nuestra
solución.
Los modelos de componentes comerciales como EJB[24], .NET[16], CCM[18],
COM+[11] usan el concepto de contenedores de software para soportar el manejo de
algunos los requerimientos no funcionales (seguridad, transacciones, persistencia y ciclo
de vida).
Para que el contenedor pueda manejar los componentes, estos deben cumplir con
características especiales de cada implementación perdiendo interoperabilidad de los
mismos con otros modelos de componentes. Generalmente los modelos orientados a
contenedor “no hacen explícito el modelo del mundo no funcional que implementan” [13]
(sólo permiten interactuar con ellos de forma declarativa).
Otros modelos de componentes como fractal (modelo de componentes jerárquico)
[5] definen una membrana que interactúa con las propiedades internas y el conjunto de
subcomponentes que posee. El manejo de los requerimientos no funcionales está
representado en la membrana que provee la capa controladora del componente. Tiene la
facilidad de incluir nuevas interfaces de control para requerimientos adicionales. Pero la
implementación de la membrana de control está asociada a cada componente y no puede
ser definida independientemente para su reutilización en otros componentes.
En nuestra solución, los servicios no funcionales son expresados como componentes
independientes del contenedor y pueden ser compuestos con CFs y CNFs.
Por otro lado, la programación orientada por aspectos (AOP)[2] busca la separación
de propiedades funcionales y no funcionales que forman una aplicación. AOP disminuye
la dependencia entre los componentes funcionales y no funcionales, promueve el
reuso[20], facilita el desarrollo y la evolución del componente. AOP provee mecanismos
de composición transparentes y flexibles (principalmente a nivel de programación). En
este sentido, utilizamos el concepto de la AOP para aplicarlo a los componentes tipo caja
negra, con el fin de definir en el lenguaje ISL la interacción entre los componentes
funcionales y no funcionales.
Por su estrategia y madurez la AOP ha sido utilizada en aplicaciones JEE como se
muestra en el artículo AspectJ2EE [25] aplicado a componentes EJB. También los
encontramos en el modelo de componentes Fractal (implementaciones AOKell y
FractNet [15] ) y FAC[17]. Otro ejemplo interesante presentado en [9][10] del lenguaje
de dominio específico KALA para separar las preocupaciones relacionadas con los
sistemas de manejo de transacciones avanzadas ATMS.
En nuestro trabajo tomamos como base el lenguaje de aspectos AspectJ, para definir
el lenguaje de dominio específico ISL que expresa la interacción entre componentes
funcionales y no funcionales.
7 CONCLUSIONES
8 TRABAJO FUTURO
REFERENCIAS