Thursday, 9 April 2009

AOP Aspect-Oriented Programming

Abro este post para comentar un poco el tema del AOP (Programación orientada a aspectos), ya que es un concepto bastante abstracto y que consiste en mejorar considerablemente nuestro código, haciéndolo más mantenible y simple. Sobretodo atendiendo al principio del DRY (Don't repeat youself), y evitar el copy-paste malicioso o boilerplate (su traducción seria lenguage estereotipado o repetitivo). Como explica Robbie Vanbrabant en su último libro (Agile Lightweight Dependency Injection Framework), muchos de nosotros hemos utilizado clases, métodos y packages, pero todos estos conceptos a veces no nos ayudan a solucionar todos nuestros problemas, y nunca pueden ayudarte a organizar tu código y evitar que esté duplicado por algún módulo. AOP, permite al código comportarse de diferente manera, y ser dividido en pequeños núcleos de componentes (aspectos), los cuales pueden ser inyectados arbitrariamente en cualquier lugar facilmente. Las llamadas de los métodos pueden ser interceptadas, aumentadas o redirigidas, y en muchas ocasiones sin tener que cambiar el código. Desde mi punto de vista, cuando llevas años escribiendo código, dentro de un equipo, siempre ha pasado que dos de nosotros hemos escrito lo mismo, porqué el código está mal organizado, o simplemente porqué no hay manera de manejarlo...
Si nuestro código empieza a tener más de 100 packages, más de 10M de líneas, etc...estamos hablando de que hay algo que no cuadra, o por un lado se escribe demasiado código, o realmente lo que está pasando es que se está duplicando.
Lo importante de la programación orientada a aspectos, es que el impacto sobre el proceso de desarrollo sea cero o nulo, y que solo impliquen pequeñas modificaciones elegantes que nos lleven a una mejora en nuestro código.

  • Un ejemplo práctico en Java:
Este ejemplo lo he hecho usando también el concepto del Guice AOP, que es el que utiliza el framework del Guice, por lo tanto en mi package, he tenido que importar las librerias aopalliance.jar y guice-1.0.jar, que las podemos encontrar en la web de google guice.

Este ejemplo simple consiste en tener una lista de personas, a las que alguien quiere acceder, por lo tanto buscarlas a través de un índice. Mediante AOP, creo una clase interceptora que me informa de si alguien intenta acceder a esta lista y que identificador de usuario está buscando:

El código fuente (muy sencillo), lo teneis implementado aquí:




import com.google.inject.Guice;
import com.google.inject.Injector;
import java.util.HashMap;
import java.util.Map;

public class People {
private static final Map<Number, Person> People = new HashMap<Number, Person>();

static {
People.put(1, new Person("John Smith"));
}

public Person search(Number number) {
return People.get(number);
}

public static void main(String[] args) {
Injector i = Guice.createInjector(new PeopleModule());
People people = i.getInstance(People.class);
Person p = people.search(1);
System.out.println(p);
}
}

//////////////////////////////////////////////////////////////////////////////////////


import static com.google.inject.matcher.Matchers.*;
import com.google.inject.AbstractModule;

public class PeopleModule extends AbstractModule {
@Override
protected void configure() {
bindInterceptor(subclassesOf(People.class),
returns(only(Person.class)), new PerformanceInterceptor());
}
}

//////////////////////////////////////////////////////////////////////////////////////

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;

public class PerformanceInterceptor implements MethodInterceptor
{
public Object invoke(MethodInvocation invocation) throws Throwable {
for (Object arg : invocation.getArguments())
if (arg instanceof Number)
System.out.println("Someone is looking por person ID: "+arg);
return invocation.proceed();
}
}

//////////////////////////////////////////////////////////////////////////////////////

public class Person {
private final String name;

public Person(String name) {
this.name = name;
}

public String toString() {
return String.format("%s[name=%s]", getClass().getName(), name);
}
}




el resultado de la ejecució del siguiente código es:

Someone is looking por person ID: 1
Person[name=John Smith]

Podeis encontrar más información en los siguientes enlaces:

http://code.google.com/p/gwt-ent/wiki/AOP
http://es.wikipedia.org/wiki/AspectJ
http://www.informit.com/articles/article.aspx?p=174533&seqNum=2
http://www.developer.com/design/article.php/3308941
http://www.eclipse.org/ajdt/

2 comments: