Documente Academic
Documente Profesional
Documente Cultură
Ambientes de Programación
Integrantes:
Janice Martínez
Steven Martínez
Néstor Martínez
Abdiel Martínez
2
Introducción
La industria de desarrollo de software ha evolucionado grandemente en los últimos
años. Algunas veces como desarrollador es difícil mantenerse al día con las nuevas
tecnologías o procesos que cada día se incorporan. Sin embargo a pesar de todos los
avances que se están dando existen problemas para los cuales todavía no se tiene una
solución ideal. Uno de estos problemas es la correcta modularización, en especial,
cuando se lidia con un sistema complejo y grande. La adopción de OOP (siglas en
ingles) ha ayudado grandemente a que se avance para subsanar este dilema; sin
embargo, no es suficiente. La programación orientada a aspectos va un paso más allá y
aunque lejos de ser una solución ideal, subsana algunos deficiencias del modelado que
se logra por medio de OOP .
3
Separación de Asuntos (Separation of Concerns)
El principio de Separación de Asuntos fue propuesto en la década de 1970 por Edsger
W. Dijkstra en su ensayo: “Rol del pensamiento Científico”. En este ensayo Esdger
establecía que un problema dado debe ser separado en varios aspectos o asuntos.
Quince años después es evidente que el concepto de separación de asuntos es
grandemente adoptado por los profesionales de la computación. Como prueba de esto
podemos citar el libro publicado por Chris Reade “Elementos de Programación
Funcional”. En el cuales se describe la separación de asuntos de manera mas
detallada. Reade declara que el programador debe ser capaz de hacer varias funciones
a la vez:
4
Podemos definir asuntos como los diferentes temas o asuntos de los que es necesario
ocuparse para resolver el problema. Una de ellos es la función específica que debe
realizar una aplicación, pero también surgen otros como por ejemplo distribución,
persistencia, replicación, sincronización, etc. Usualmente asuntos son equivalentes con
características o comportamientos del programa.
5
como incremento en el costo de mantener el software, decremento en la reusabilidad,
entre otros.
Los asuntos transversales dan lugar a código disperso y enredado (scattering and
tangling). En el caso de scattering en lugar que un componente se enfoque en
desarrollar un solo asunto, el componente desarrolla varios asuntos. Cómo
desarrollador debemos conocer sobre todos los asuntos que se están desarrollando en
el componente. Incrementando la curva de aprendizaje del código de la aplicación.
Los asuntos transversales se pueden clasificar en: Compañeros (Peers). Estos son
asuntos que se distinguen claramente uno de otros. Los mismos tienen el mismo nivel
de importancia. En el ejemplo familiar del ATM, retiro de efectivo, depósito,
transferencia de fondos todos son asuntos transversales compañeros (Peers).1 Estos
asuntos se pueden desarrollar como sistemas independientes, sin embargo al
desarrollarse dentro del mismo sistema nos encontramos con el hecho de que existe
sobreposición en la codificación de los mismos.
1
(Jacobson, et al., 2004)
6
denomina código de unión (glue code). No importa que tan bueno sea el diseño, con las
técnicas de modelado convencionales, el código de unión es necesario.
Para superar estas limitaciones es necesaria una nueva metodología modular que nos
permita: alcanzar verdadera separación de los asuntos, incluyendo los asuntos
transversales, en todas las fases de desarrollo de software (requerimientos, análisis,
7
diseño, codificación y pruebas). Está nueva metodología también debe permitir la
composición de asuntos de manera coherente e integral.
8
• Pointcut (Puntos de Corte) define los Consejos que se aplicarán a cada Punto
de Cruce. Se especifica mediante Expresiones Regulares o mediante patrones
de nombres (de clases, métodos o campos), e incluso dinámicamente en tiempo
de ejecución según el valor de ciertos parámetros. Un ejemplo sencillo se puede
aplicar a clases que representen figuras geométricas. En
9
o Aspectos en Tiempo de Ejecución.2
2
(Wikimedia Foundation, 2009)
10
Lenguajes Programación Orientado a Aspectos
Como toda investigación lleva a una aplicación práctica la programación orientada a
aspectos no es la excepción. Existen varios lenguajes de programación que han
implementado, algunos más exitosos que otros, técnicas para poder aplicar los
aspectos. Algunos de estos programas son específicos a un dominio y no se pueden
usar como lenguajes multi-propósitos. Otros han sido iniciativas de universidades y al
carecer del respaldo económico no han tenido la adopción esperada, quedando en las
fases experimentales. Cómo un ejemplo de este último caso se puede mencionar a
Aspect.Net.
Tejedor (Weaver): estadísticamente aplica el consejo (advice) a los puntos de unión que
se establece basado en las reglas descritas en el aspecto.
AspectJ
Es una extensión multi-propósito de Java que implementa la programación orientada a
aspectos. Está formada por una serie de herramientas que permiten a los
desarrolladores de Java administrar mejor los problemas inherentes de los sistemas
11
grandes y en general aplicar mejor la modularidad dentro de los mismos, en especial
aplicar correctamente la separación de los asuntos transversales. Originalmente fue
desarrollado por profesionales del Centro de Investigación de Palo Alto de Xerox, ahora
es parte del proyecto Eclipse.
Es un lenguaje práctico que provee, en un paquete compatible con Java, un set sólido
de características de Programación Orientada a Aspectos. No está diseñado para ser
una encarnación en blanco de las ideas de Programación Orientada a Aspectos, no es
una implementación formal ni un estudio agresivo del dominio y las oportunidades de la
POA.
12
transversales estáticos (static crosscutting). En ella se definen nuevas operaciones en
tipos existentes.
Los diferentes tipos de puntos de unión que AspecJ tiene se presentan en la siguiente
tabla:
13
hace el llamado, pero antes que cualquier
método/constructor haya sido llamado.
- Ejecución de un constructor
Aplicación de AspectJ
Estudiar la Solución Convencional primero —En este paso, se diagrama,
diseña, e incluso se crea un prototipo de la solución convencional. La solución
convencional resalta las ventajas de la solución que provee AspectJ, el propósito
principal es ayudar a entender el diseño necesario para una mejor solución con
14
AspectJ. La idea es identificar el código disperso y enredado (scattering and tangling) y
luego modularizarlo. Una vez se logra suficiente experiencia en este paso, se puede
reducir la importancia del mismo o incluso eliminarlo..
Diseño
Al igual que cualquier proceso de desarrollo de software un buen diseño es la piedra
angular para que el proyecto se desarrolle de manera exitosa; diseñar software usando
AspectJ no es la excepción a la regla. Al considerar el uso de AspectJ desde las etapas
3
(Laddad, 2003)
15
iníciales del diseño se obtiene los mayores beneficios de la utilización del mismo, ya
que se garantiza que los asuntos transversales son manejados correctamente e
integrados efectivamente por medio de los aspectos.
- Reconocer los asuntos transversales. Este paso es parte del mapeo necesario
de requerimientos a módulos. Una manera sencilla de identificar estos asuntos
es la utilización de frases como: “cada vez”, “en todo lugar”. Si nos encontramos
utilizando estas frases para describir parte de las funcionalidades en distintos
módulos, tenemos ante nosotros un asunto transversal. Reconocer los asuntos
transversales a tiempo, permite que estos sean delegados a aspectos que se
integran fácilmente a los módulos existentes.
Implementación
En general el proceso de implementar un sistema utilizando AspectJ no es muy
diferente que cuando se utiliza un lenguaje de orientación a objetos. Hay algunas
consideraciones básicas en las cuales se debe hacer más énfasis como:
16
-Separar en módulos correctamente el código: idealmente cada operación debe
corresponder con una funcionalidad. La unidad granular para definir los puntos de unión
son los métodos. Es importante que cada método tenga una función clara y concisa. De
esta manera el aplicar un aspecto será pan comido.
- Diseñar los aspectos. Se puede considerar utilizar patrones como plantillas para
diseñar los aspectos. También es necesario aplicar una nomenclatura
consistente a los aspectos en sí. Esto facilitará la aplicación e puntos de unión
dentro de los aspectos si así se requiera. Es válido también determinar si los
mismos aspectos se pueden reutilizar en otros sistemas que presenten los
asuntos transversales que se quieren resolver.
17
orientación a objetos. El aspecto adicional sería la creación del aspecto en sí. Se hace
mayor énfasis en mantener una nomenclatura uniforme e identificar todos los puntos de
unión mediante la definición de los puntos de corte.
Fase de Pruebas
AspectJ provee una serie de escenarios que ayudan a automatizar el proceso de
pruebas de la aplicación. Debido a la naturaleza no intrusiva de los aspectos se puede:
Crear casos de usos: Por medio del uso de aspectos privilegiados se puede acceder a
los elementos privados de una clase. Esto permite que se creen programas de prueba
sin que se modifiquen la clase original que se quiere probar. Una vez se haya
garantizado que las pruebas dan los resultados esperados, los aspectos se pueden
sacar del sistema fácilmente.
Pruebas de desempeño: Para tal fin se pueden crear aspectos que ayuden a monitorear
el desempeño de la aplicación cuando este en la versión beta.
Reporte de errores: se pueden usar aspectos que brinden información adicional acerca
del contexto de los errores. El contexto no sólo incluye el stacktrace sino toda la
información que esté disponible en el punto de unión donde se dio el error. En este
sentido los reportes de errores son superiores a la información estándar que proveen
los compiladores.
Ejemplo de AspectJ
Haciendo alusión al asunto transversal sobre registros de sucesos. Presentamos el
siguiente ejemplo. Es una pequeña aplicación que tiene como objetivo simular algunos
flujos existentes en un salón de clases.
Requerimientos
Los requerimientos del micro sistema son:
18
- Listar la lista de estudiantes registrados en una clase
Debido a que este es un ejemplo práctico enfocado en mostrar las diferencias básicas y
ventajas de utilizar AspectJ, la parte gráfica del micro sistema no será desarrollada. El
ejemplo se enfocará en crear las clases necesarias que satisfagan los requerimientos
antes señalados.
El siguiente diagrama de clases muestra el diseño inicial con el cual se pretende cumplir
con todos los requerimientos antes mencionados.
Como se puede observar en el diagrama la clase principal del sistema es la clase Class.
A continuación podemos ver la implementación del código en AspectJ y posteriormente
la implementación del código en C#.
Implementación Java
package com.object.model;
import java.util.ArrayList;
import java.util.*;
19
private String _ClassName;
public Class()
{
ActiveTasks = new ArrayList<Task>();
RegisteredStudents = new ArrayList<Student>();
}
20
public void ListTasks()
{
for(int i = 0; i < ActiveTasks.size(); i ++)
{
System.out.println("Task name: "
+ ActiveTasks.get(i).GetName()
+ " Due date: " + ActiveTasks.get(i).
GetDueDate().toString() );
}
}
Implementación en C#
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ObjectModel
{
public class Class
{
List<Student> RegisteredStudents;
List<Task> ActiveTasks;
Professor _Professor;
public Class()
{
RegisteredStudents = new List<Student>();
ActiveTasks = new List<Task>();
}
21
}
}
}
Las dos implementaciones son muy parecidas y en apariencia cumplen con los
requerimientos señalados. Existen algunas diferencias inherentes al syntaxis propios de
los lenguajes, pero en teoría la implementación es la misma. No obstante, si
observamos cuidadosamente nos podemos percatar que ninguna de las dos
implementaciones cumple con el requerimiento sobre registrar todos los sucesos que se
esten realizando en el sistema. Necesitamos hacer unos ajustes en ambas
implementaciones para satisfacer todos los requerimientos.
22
Implementacion C# con registro de sucesos en consola
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ObjectModel
{
public class Class
{
List<Student> RegisteredStudents;
List<Task> ActiveTasks;
Professor _Professor;
public Class()
{
Console.WriteLine("CTor init");
RegisteredStudents = new List<Student>();
ActiveTasks = new List<Task>();
Console.WriteLine("CTor end");
}
23
public void RemoveTask(Task taskToRemove)
{
Console.WriteLine("RemoveTask init");
if (ActiveTasks.Contains(taskToRemove))
{
ActiveTasks.Remove(taskToRemove);
}
Console.WriteLine("RemoveTask end");
}
public void ListTasks()
{
Console.WriteLine("ListTasks init");
foreach (var tempTask in ActiveTasks)
{
Console.WriteLine("Taks name: " +
tempTask.Name + " due date "
+ tempTask.DueDate);
}
Console.WriteLine("ListTasks end");
}
}
}
24
Implementación usando AspectJ
package com.object.model;
import org.aspectj.lang.*;
public aspect LoggingAspect {
pointcut traceMethods()
: execution(* *.*(..)) && !within(LoggingAspect);
before() : traceMethods() {
Signature sig = thisJoinPointStaticPart.getSignature();
String sigName = sig.getName();
String declaringName = sig.getDeclaringTypeName();
System.out.println(declaringName + " " + sigName + " init");
}
after() : traceMethods(){
Signature sig = thisJoinPointStaticPart.getSignature();
String sigName = sig.getName();
String declaringName = sig.getDeclaringTypeName();
System.out.println(declaringName + " " + sigName + " end");
}
}
Por medio del uso del aspecto LogginAspect podemos incluir registros de sucesos en
todas las clases. Hemos modularizado exitosamente el asunto transversal. Ya que hay
un sólo lugar donde se maneja el registros de suceso, sería muy sencillo cambiar el
método consola por log4j o la librería estándar de Java para registrar sucesos
AspectJ también nos presenta una herramienta muy útil con la que se pueden ver los
puntos de unión que cumplen la condición.
25
Por medio del uso de esta herramienta podemos tener una idea exacta de cuantos
puntos de unión se han identificado para cada uno de los puntos de corte.
26
Implementación de Aspecto en .Net C#
Para la implementación de la tecnología de programación orientada aspecto nosotros
encontramos una herramienta llamada PostSharp. Existen otras librerías que permiten
la implementación de esta tecnología en .Net. Esta herramienta nos permite reducir el
número de líneas de código en la mayoría (si no todos) de los lenguajes .Net
implementando aspecto.
PostSharp nos facilita la implementación en nuestro código encapsulando los aspectos
como atributos personalizados, haciendo nuestra vida más fácil y la implementación
más placentera.
27
Implementación de XTraceMethodBoundaryAttribute
Como queremos insertar código antes y después del cuerpo del método, vamos a
derivar nuestro atributo personalizado de OnMethodBoundaryAspect e implementamos
los métodos OnEntry, OnSuccess y OnException.
El esqueleto de nuestro atributo personalizado es:
[Serializable]
public sealed class XTraceMethodBoundaryAttribute :
OnMethodBoundaryAspect
{
28
La funcionalidad de preparar plantillas y la implementación esta encapsulado en
las clases Formatter y MethodFormatStrings. Su implementación no es de
interés en nuestra discusión, así que no lo vamos a describir en nuestro ejemplo.
¿Cómo podemos realizar esto con PostSharp?
Primero, definimos las instancias de los campos que contienen las cadenas de
formateo y otras cosas que no queremos computar o calcular en tiempo de
ejecución. Después, implementamos el método CompileTimeInitialize para
configurar estos campos. Durante la post-compilación, PostSharp Laos
serializará el objeto. Eso significa que los campos que son inicializados en
tiempo de compilación para ser utilizados en tiempo de ejecución deben ser
serializables. Como este es el comportamiento predeterminado, no tenemos
que ponerle mucha atención a eso.
29
Métodos en Tiempo de Ejecución
Vamos de vuelta a nuestro esqueleto de nuestra clase
XTraceMethodBoundaryAttribute. Tenemos que implementar los métodos
OnEntry, OnSuccess and OnException. Todo lo que tenemos que hacer es
formatear las plantillas con los parámetros concretos y llamar el método
Trace.TraceInformation.
public override void OnEntry(MethodExecutionEventArgs context)
{
Trace.TraceInformation(
this.prefix + "Entering " +
this.formatStrings.Format(
context.Instance,
context.Method,
context.GetArguments()));
Trace.Indent();
30
Conclusión
Por medio del desarrollo de esta monografía se ha podido apreciar las ventajas que
AspectJ y PostSharp brindan en el desarrollo de un sistema. Descartando el esfuerzo
necesario para aprender sobre la sintaxis requerida para especificar los puntos de
cortes de los diferentes aspectos que se han querido introducir al sistema, el uso
correcto de garantiza un menor tiempo escribiendo código. Si bien es cierto que esta
labor sería un proceso mecánico, por medio de estos marcos de trabajo se puede
eliminar el mismo.
31
Referencias
Gael Fraiteur. Bringing AOP to .NET, PostSharp.
[En línea]
http://www.postsharp.org/
32