Programacion

Juan Mellado, 26 Junio, 2010 - 09:50

FacebookFacebook es la red social de más éxito hoy en día, y desde un punto de vista puramente técnico, sus datos son realmente espectaculares. Presume de tener del orden de unos 30.000 servidores capaces de servir unos 570 billones de páginas al mes. Hace una semana publicaron un artículo con algunos detalles del software que utilizan en sus máquinas.

Aunque empiezan diciendo que se consideran un sistema de tipo LAMP (Linux Apache MySQL PHP), enseguida aclaran que más bien es un "LAMP con heteroides". Utilizan versiones de Linux, MySQL y PHP que ellos mismos han optimizado. Además de mucho otro software, naturalmente, propio y ajeno, la mayoría de código abierto.

- HipHop para PHP es uno de los desarrollos propios de Facebook más conocidos, y se trata básicamente de un compilador cruzado que toma código escrito en PHP y genera código equivalente en C++ que puede ser compilado con g++ para una ejecución de forma nativa más óptima. Con este enfoque aseguran haber conseguido hasta una reducción de un 50% del consumo de CPU en sus servidores.

- Thrift es un desarrollo propio de Facebook que liberó y ahora forma parte de la fundación Apache. Sirve para poder realizar llamadas entre distintos lenguajes de programación, que en el caso de Facebook son unos cuantos: PHP, C++, Java, Erlang, ... La idea es que en un fichero de texto plano se definen las estructuras de datos y las funciones públicas, y la librería genera el código fuente correspondiente para el lenguaje de programación que se le indique. La librería garantiza que los datos serán serializados en el cliente y reconstruidos en el servidor donde quieran que se ejecuten estos de una forma totalmente transparente y eficiente. O sea, un RPC (posibilidad de realizar llamadas remotas) con su propio IDL (lenguaje de definición de interfaces). No obstante es un proyecto que ha decaido un poco, sobre todo por el auge de Avro que el mes pasado se convirtió en un proyecto "raíz" de Apache. De características similares, pero con un enfoque más atractivo, ya que no obliga a utilizar código fuente generado de forma automática por una herramienta.

- Cassandra es otro de los productos estrella de Facebook. Es un sistema de almacenamiento distribuido altamente escalable y con una gran tolerancia a fallos. Es uno de los baluartes actuales de las base de datos "NoSQL" para el almacenamiento de pares (clave, valor). Hace un tiempo escribí un post explicando el modelo de datos en el que se basa su funcionamiento. Es un software muy interesante y que ha entrado a formar parte también de la fundación Apache.

- Hadoop es un conjunto de proyectos de código abierto originales de la fundación Apache con los que se persigue que los desarrolladores tengamos las herramientas necesarias para poder generar programas distribuidos, escalables y con alta disponibilidad. Se compone de un núcleo de librerías comunes, varios frameworks, y una serie de software más específico implementado sobre los anteriores. Uno de los más populares es MapReduce que implementa las funciones Map y Reduce utilizadas para el procesamiento de grandes cantidades de información en entornos principalmente de cloud computing. La idea básica es que se parte de unos vectores con los datos a procesar a los que aplica la función Map para generar nuevos vectores en un dominio distinto, y luego se aplica la función Reduce para agrupar los vectores generados al dominio de salida deseado. Recomiendo leer el artículo de la Wikipedia para entenderlo mejor. Es muy interesante.

- Hive es un subproyecto dentro de Hadoop, aunque es un desarrollo original de Facebook que luego liberó. Es un datawarehouse cuyo objetivo es permitir acceder a través de consultas SQL a los enormes vectores de información utilizados normalmente con Hadoop con el propósito de realizar análisis estadísticos o de tipo data-mining.

- BigPipe es una de las "armas secretas" de Facebook. Es un servidor de páginas webs dinámicas que introduce el concepto de pagelets con el que descompone una página web en varias partes, de forma que cada una de ellas pueda generarse en paralelo. La idea es que cuando se solicita una página web esta se devuelva lo antes posible, pero con una estructura mínima que se compone de bloques vacíos (perfil, búsqueda, chat, ...). Estos bloques son las pagelets que se van generando en paralelo en el servidor, y que cuando están listas se envian al cliente y se renderizan con JavaScript. De esta forma se consigue que la generación de una única página web se haga en paralelo, en vez de forma secuencial como es lo más habitual, y que el fallo en un subsistema (perfil, búsqueda, chat, ...) no impida servir una página, aunque esté incompleta.

- Memcached es un proyecto externo de código abierto muy popular al que Facebook ha contribuido optimizando algunas partes. Es un sistema distribuido de cache de objetos con un alto rendimiento. La idea es evitar tener que hacer consultas pesadas almacenando resultados previos en memoria, de forma que pueden ser servidos directamente en vez de ejecutando cada vez las consultas. O sea, el funcionamiento normal de una cache pero aplicado a gran escala, sobre queries que atacan una base de datos, clientes que solicitan páginas webs, o cualquier otro tipo de pares (clave, valor). Pero no es mágico, no es un software que se pone entre cliente y servidor y lo hace todo. Hay que programar. En los clientes hay que llamar a la cache para ver si tiene el dato, y si no lo tiene hacer la consulta de la forma habitual, y entonces llamar a la cache para que almacene el dato durante el tiempo que se quiera que sea válido.

- Varnish es un acelerador de HTTP de código abierto. Se coloca entre los clientes y uno o más servidores web actuando como balanceador de carga. Pero es un software que ofrece mucha más funcionalidad que la de mero balanceador. Ofrece un servicio de cache para responder a las peticiones de forma inmediata sin tener que realizar realmente las llamadas a los servidores web, y permite ejecutar procesos a medida para prácticamente cualquier tipo de información o evento que se produce en una comunicación HTTP. Facebook lo utiliza sobre todo para servir las fotos e imágenes de los perfiles, ¡unos cuantos billones de ficheros cada día!

- Scribe es el sistema de log desarrollado por Facebook y liberado como código abierto. La idea es que los cliente envian a servidores dedicados, a través del anteriormente mencionado Thrift, las trazas en forma de pares (categoría, mensaje). Y los servidores organizan todos los mensajes recibidos en función de sus categorías escribiéndolos finalmente en ficheros alojados en algún tipo de filesystem distribuido, ¡unas cuantas decenas de billones de mensajes cada día!

Juan Mellado, 12 Junio, 2010 - 09:51

En estos últimos días ha terminado de liberarse el código fuente de una serie de juegos "indies" bastantes populares: Aquaria, Gish, Penumbra Overture y Lugaru. Todo esto dentro de una iniciativa (ya finalizada) llamada "The Humble Indie Bundle (pay what you want)" que permitía a los usuarios pagar el precio que quisieran por estos juegos, además de World of Goo, para el que no se va a liberar los fuentes. Una campaña que si bien puede parecer arriesgada, ha conseguido recaudar 1.273.613 dólares, de los cuales el 30,85% (392.953 dólares) han sido destinados a Electronic Frontier Foundation y Child's Play Charity.

Cada proyecto ha puesto los fuentes en un sitio distinto y con una licencia distinta. Aquaria lo ha colgado en un repositorio público con Mercurial y licencia GNU, Gish en un simple zip con licencia GPL, Penumbra Overture en un repositorio con git y licencia GNU, y Lugaru en otro repositorio también con Mercurial pero con licencia GPL2. Mucho que cotillear ahí dentro.

Lo bueno que tienen estos proyectos es que funcionan para las tres plataformas más extendidas actualmente: PC, Mac y Linux. Además de que son juegos de tipos completamente distintos. En 2D y 3D. Aunque naturalmente la idea no es que se compile el código y se haga el mismo juego con gráficos o sonidos distintos. Eso no tiene ningún sentido. Al menos no más allá de un homenaje al juego original. Lo que si puede servir es para que algunos programadores se fijen en como están resueltos algunos problemas que les impiden avanzar en sus proyectos. O tomar decisiones acerca de cuales librerías multiplataforma utilizar. Sobre todo cuanto se está empezando y no se tiene criterio para tomar este tipo de decisiones.

En cuanto al código en si mismo, me ha llamado la atención que Gish esté hecho en C, y no en C++ como el resto. Pero por lo demás no hay muchas sorpresas, ya que lógicamente usan SDL, OpenGL y OpenAL. Y sin ninguna capa de abstracción, o muy sencillas, en la mayoría de los casos, como era de esperar. Los ficheros de mayor peso son los que hacen la mayor parte del trabajo, y contienen en algunos casos métodos de bastantes cientos líneas de código, de miles en algunos casos. También hay código comentado, obsoleto, o con indicaciones del autor acerca de su propósito, normalmente para activar algunos procesos de depuración específicos. Para compilar contra una plataforma u otra se usan directivas #ifdef embebidas dentro de las clases en los puntos en los que fueron necesarios ponerlos. Penumbra tiene un motor separado, ya que es un proyecto más técnico que surgió a partir de unas demos tecnológicas, pero el resto son más programas "de una pieza" a los que se han ido añadido clases a medida que hacían falta.

Curiosamente, o no, el comentario de todos los programadores que han liberado su código es "ahí lo tenéis, pero no esperéis gran cosa". La mayoría se muestra orgullosa de que funcione y que fuera un éxito, pero a la hora de mostrar el código lo ven de otra forma. Que si es un lío. Que si es una mezcla de varios proyectos anteriores. Que si se hizo después de un par de copas. En fin ... Supongo que esto pone el desarrollo de este tipo de software al nivel de la "artesanía" que sigue siendo hoy en la mayoría de los casos. Crear diseños sólidos, módulos debilmente acoplados, interfaces claras, y todo ese tipo de características que propugna la ingeniería del software es algo deseable, pero también muy dificil y costoso. Un programador trabajando por su cuenta en un proyecto personal puede permitirse el lujo de empezar la casa por el tejado y luego ir uniendo el resto de las partes. No sé a qué vienen tantos reparos. La mayoría del código que se produce hoy en día, y se produce una barbaridad, tiene que ser por fuerza mediocre. Ya es hora de que nos permitan sentirnos orgullosos de nuestro trabajo.

Juan Mellado, 13 Junio, 2009 - 08:08

Estos días he estado recibiendo un curso de formación introductorio a Struts y Spring. Dos frameworks bastante populares dentro del mundillo del desarrollo, principalmente web, para Java. Es bastante fácil encontrar referencias a ambos productos aquí y allá, pero encontrar a alguien que sepa decir con precisión para que sirven exactamente cada uno de ellos es algo más complicado. Sobre todo por que, a mi juicio, son soluciones que intentan abarcar demasiados aspectos a un mismo tiempo con el objeto de ofrecer una solución completa y exhaustiva, lo que hace que se pierda facilmente la perspectiva del conjunto si no se va cuidado. Hay muchos sitios donde mirar, y al final es fácil no saber donde poner la mirada. A algunos de estos mega-proyectos no les vendría mal una operación de "marketing" para venderse mejor.

Struts me lo han conseguido vender más o menos bien, aunque con matices. Pero Spring no me ha acabado de llegar, posiblemente por las circunstancias de mi proyecto actual, donde ya se encuentran resueltos muchos de los problemas que se plantearon gracias a un framework propio. Pero vayamos por partes.

Todo artículo que trate de Struts parece tener que empezar hablando irremediablemente del patrón MVC (Modelo-Vista-Controlador). Este framework vive de él. Y la idea general que he sacado del curso es que todo gira alrededor suyo, y en la separación de capas que proporciona. Al principio yo esperaba que me iban a mostrar un sistema de plantillas bastante elaborado, a la manera de muchos paquetes PHP, pero curiosamente esa parte la hemos visto al final. Lo primero ha sido ver como se pasa el control al framework de forma transparente a través del fichero web.xml habitual en las aplicaciones web. Lo que en un principio me ha alegrado, hasta que me he dado cuenta de que en realidad lo que se estaba haciendo era poner las referencias a los servlets en otro fichero. El mismo perro con otro collar. Afortunadamente, más tarde ha mejorado mi percepción al entender como se conseguía que las clases de negocio se dedicasen sólo y exclusivamente al negocio, las clases de presentación a lo suyo, y así sucesivamente. Siempre está bien tener este tipo de organización que garantice que todos hacen lo mismo en un mismo sitio, y Struts puede ser un punto de partida tan válido como cualquier otro.

Struts actúa como un proxy intermedio que controla el flujo de vida de las aplicaciones redirigiéndolo a nuestras clases en los momentos adecuados.

Una visión algo parcial de Struts nos permite verlo además como un conjunto de librerias, del que cada cual utiliza las partes que le interesa. Con este enfoque, la primera libreria que vimos fue la de internacionalización, ya que es algo bastante sencillo de entender de entrada, y su uso no implica cambios demasiados grandes en la forma habitual de escribir un JSP. De hecho es bastante simple, consiste en utilizar una fichero de recursos por cada idioma que soporte la aplicación, con las cadenas de texto, y hacer referencia a ellos a través de las etiquetas propias que proporciona Struts. El uso de etiquetas propias embebidas dentro de los propios JSP es una constante en este framework.

Otras librerías que vimos fueron las enfocadas a la creación y gestión de formularios, elementos muy frecuentes en la mayoría de aplicaciones webs transaccionales. Desde facilidades para tareas comunes, como el mantenimiento de los valores previos introducidos entre llamada y llamada al servidor, pasando por un tratamiento casi transparente de las excepciones, hasta el control de errores y validación de campos de entrada de forma centralizada. Todo ello mediante la escritura de clases que reciben directamente la información a tratar en cada caso, y que son llamadas por el propio framework que controla en todo momento el flujo de proceso de la aplicación. Siendo quizás la parte más representativa de esta parte, el hecho de que los nombres de las clases a las que tiene que llamar el framework residen en ficheros XML, aunque lógicamente las clases que escribimos están obligadas a implementar determinadas interfaces para que puedan ser llamadas correctamente.

Por lo que respecta a Spring, su patrón de diseño clave es el de la inversión de control, aunque el framework en su conjunto abarca muchas áreas. Por una parte la gestión de la capa de acceso a datos (DAO y ORM), por otra parte la de gestión del negocio (J2EE), y por otra parte la capa de presentación. Lo que viene a ser otra vez el omnipresente patrón MVC. Como curiosidad, hay que mencionar que Spring ofrece soporte de forma nativa para el uso de programación orientada a aspectos, de forma que nos permite inyectar código propio en clases ajenas. Sobre esto último, durante el curso, vimos la evolución que ha sufrido el framework, y las posibilidades mejoradas que ofrece al respecto la versión 2.0, aunque a mi parecer no tantas como otras soluciones creadas especificamente para este propósito. De hecho, esto es un incoveniente que se plantea para muchas de las funcionalidades que ofrece el framework. Como su gestor de transacciones por ejemplo, que se queda corto frente a un servidor de aplicaciones normal.

En la práctica el uso de Spring es similar al de Struts, en lo que al uso de ficheros XML se refiere. El peso de la configuración recae en el uso de "contextos", ficheros en los que a grandes rasgos se definen las clases concretas que debe utilizar el programa. Lo que de entrada puede sonar algo extraño, ya que estamos acostumbrados a instanciar objetos de un paquete específico en nuestro código fuente. La ventaja de este enfoque es que permite modificar los paquetes que debe utilizar una aplicación de manera indirecta, minimizando así las dependencias "hardcoded" entre componentes. No obstante, esto es sólo una minúscula parte de la potencia que ofrece este enfoque. Por ejemplo, en un fichero de contexto podemos indicar que un determinado objeto se trate mediante el patrón Singleton, de forma que sólo se instancie una única vez a lo largo y ancho de toda la aplicación. Pero las ventajas no acaban ahí, ya que es posible incluso indicar las clases a utilizar al instanciar los parámetros de los constructores, e incluso de variables de instancia. Es evidente que en la práctica todo esto tiene un carácter bastante técnico.

Spring, entre otras muchas cosas, permite reducir las dependencias entre los componentes de una aplicación declarando de forma independiente las clases concretas a utilizar en cada caso. Y proporciona patrones, interfaces y facilidades para la integración con otros paquetes populares, como Hibernate, por citar sólo uno, e incluso con el propio Struts, minimizando el impacto del uso de los mismos.

En cualquier caso, hablando ya de una forma más general, lo que no me ha convencido de ninguna de las maneras, es la aseveración de que estos frameworks permiten cambiar el comportamiento de una aplicación sin tener que tocar el "código fuente". Y por una razón muy sencilla. En el momento que me obligan a escribir el nombre de una clase en un fichero XML, ese fichero pasa a formar parte de mi "código fuente". Ese fichero XML se tiene que distribuir junto el resto de la aplicación, y ese fichero XML hace referencia a una parte de mi código. Tratando de ser un poco magnánimo, es fácil entender que en realidad esto es algo que llevamos haciendo toda la vida, como cuando parametrizamos el nombre de un driver de acceso a base de datos en un fichero de configuración. La clase del driver no suele ser parte de nuestro código, pero no por ello deja ser código. Eso sí, por favor, que no me lo vendan como si ambas cosas fueran casos distintos.

En cualquier caso, a mi me parece un atraso que en pleno siglo XXI se sigan escribiendo JSP y XML prácticamente a mano. Los ficheros de texto son muy complicados de validar, y los editores normalmente no pueden detectar los errores semánticos que se cometen habitualmente al escribir cadenas de texto. Y de los "scriptles" mejor ni hablo.

En estos cursos tan intensivos de paquetes tan grandes es fácil verse saturado por la cantidad de información que se recibe. Uno está acostumbrado a hacer las cosas de una forma determinada en el día a día, y de pronto se te plantea, no una, sino cuatro, cinco, seís, ... formas distintas de hacer una misma cosa con una herramienta que estás viendo por primera vez. Agravada además la experiencia por el hecho de que todo este tipo de software en particular se encuentra saturado por una cantidad ingente de abreviaturas, siglas, acrónimos, etiquetas, y los omnipresentes ficheros XML con sus inmumerables posibilidades disponibles como hilos conductores de todo el proceso.

Sin embargo, superado el "shock" inicial, es recomendable hacer una pausa y pararse a analizar todo desde la distancia. A mi juicio, la principal dificultad de estos frameworks la plantea el hecho de que requieren una visión estratégica del desarrollo del software, es decir, a muy largo plazo. Las ventajas de los patrones de diseño que implementan estas soluciones son el tipo de artificio que se supone que debe tener presente en todo momento un "arquitecto de sofware". Para un "programador de a píe" no dejará de ser una forma de hacer las cosas, un poco rebuscada quizás. La separación de capas, la posibilidad de poder cambiar el comportamiento de diversos aspectos de una aplicación modificando un, llamémosle "fichero de configuración", la reducción de dependencias entre paquetes, o la posibilidad de inyectar código de forma casi arbitraria, es algo grande, muy grande en realidad.

Si trabajas para una empresa/proyecto que usa un framework propio, puede que estos paquetes no te resulten demasiado atractivos, aunque resuelvan ciertas cosas de mejor forma que los estás haciendo tú. Pero si no estás trabajando con ningún paquete de estas características, entonces son una alternativa seria a considerar. Aunque abrumen un poco, requieran paciencia al principio para entender la filosofía de diseño, no se presenten como el típico IDE visual de drag and drop, y haya que dedicarles un tiempo hasta conseguir definir un buen flujo de trabajo que se ajuste a nuestras necesidades.

Juan Mellado, 21 Febrero, 2009 - 09:15

Recientemente, en la documentación técnica aportada por un cliente para un proyecto, se insitía en la imperiosa necesidad de utilizar el paradigma de la programación orientada a aspectos para los nuevos desarrollos. A estas alturas, cuando uno lee estas cosas, lo primero que piensa es "Golden Hammer habemus". Pero ya se sabe que donde manda patrón (cliente), no manda marinero (desarrollador). En San Google y Santa Wikipedia puede encontrarse bastante información sobre el tema, aunque no está nunca de más intentar sacar conclusiones por uno mismo.

La definición de "Programación Orientada a Aspectos" (AOP) es similar a cualquier otra que se pueda leer acerca de una nueva tecnología que pretenda solventar los problemas recurrentes de la construcción de software. Separar, encapsular, modularizar, facilitar, ... ¿Pero qué tiene entonces de especial este paradigma? ¿No tenemos ya la ubicua programación orientada a objetos para eso? Pues la verdad es que a lo que estamos acostumbrados está bien (OOP), pero la AOP aporta un puntito interesante al asunto. La gracia del tema está en que parece haber sido ideada más por programadores que por arquitectos. Su índole es de carácter práctico, y va más allá del trazado de subdivisones, diagramas de abstracciones, o esquemas de muy alto nivel de más que cuestionable utilidad en el día a día.

Para entender que es lo que aporta la AOP frente a otras tecnologías, lo mejor es utilizar un ejemplo. Esto es lo que hacen prácticamente todos los artículos que pueden leerse por Internet, y resulta comprensible, los objetivos que persigue este paradigma son tan génericos que resulta complicado entender la filosofía de su enfoque si no se ve su aplicación sobre casos concretos.

El ejemplo "paradigmático" de esta tecnología consiste en imaginar un paquete de clases cualquiera, escrito en cualquier lenguaje de programación disponible, al que se quiere añadir una nueva responsabilidad. Por ejemplo, imaginemos que se trata de un paquete de clases que se utiliza para gestionar las cuentas de usuarios de un sistema online. Por política de la empresa propietaria del sistema, se decide que cada vez que se ejecute un método de estas clases, se debe escribir en un fichero de texto de trazas (log) un mensaje con el nombre del método ejecutado para hacer un seguimiento exhaustivo del uso de este paquete.

Siguiendo un procedimiento bastante habitual, se abriría el IDE, y se empezaría a cambiar uno a uno los métodos de las clases, añadiendo las líneas de código oportunas para escribir al log. Aunque es posible también que se creara un paquete nuevo de clases por encima, a modo de proxy, que se dedicase solamente a escribir al log y pasar la llamada al paquete original. Con este último enfoque incluso se podría utilizar un patrón Factory, e instanciar clases de un paquete u otro a conveniencia, para su uso por ejemplo en los entornos de desarrollo donde el seguimiento exhaustivo no es preciso. No obstante, aún quedarían bastantes detalles por afinar, como qué sistema de logger utilizar, y sobre todo, qué ocurrirá si en un futuro se decide cambiar dicho sistema de, supongamos inicialmente uno in-house, a un paquete comercial, o tal vez a uno libre y de código abierto. Aunque sobre este último punto se podría argumentar que lo correcto sería ceñirse a una interface bien definida, y posiblemente estándar, para que el cambio fuese lo menos dramático posible. Y aún asi, habría que seguir decidiendo que ocurre si se produce por ejemplo una excepción al escribir al log, y una de serie de cosas por el estilo.

La clave del asunto está en observar dos puntos importantes. Primero, que las distintas soluciones implican modificar el código ya existente, y segundo, que el paquete afectado asume una nueva responsabilidad más allá de para la que fue creada originalmente, esto es, gestionar cuentas de usuario. La programación orientada a aspectos promete que es capaz de conseguir lo que se pide sin tener que modificar ni una sola línea de código ya existente, y manteniendo claramente separadas ambas funcionalidades, a pesar de que una utilice la otra.

¿Y cómo obra esta magia? Pues viendo a los programas como lo que son en la práctica, cuando se encuentran en ejecución: flujos de instrucciones y datos. Considera los acontecimientos que suceden durante la ejecución de un programa (creación de una instancia de la clase C, ejecución del método M, lanzamiento de la excepción E, ...), y se los ofrece al programador, para que pueda asociarles el código que quiera que se ejecute cuando ocurra alguno de esos acontecimientos. Es similar a la programación basada en eventos, donde se indica a que método se tiene que llamar cuando ocurre algo de particular interés, como la pulsación de un botón por ejemplo, pero llevada a otro ámbito, el de la ejecución del código. Similar a lo que se hace desde un depurador cuando se pone un punto de parada condicional. La AOP permite al programador escribir una regla del estilo "cuando se ejecute cualquier método del paquete [de cuentas], llama a mi función [que escribe un mensaje en el log]". Y lo más grande es que en la práctica (en la vida real, con un compilador real que soporte AOP) basta crear un fichero con apenas 10 líneas de código para escribir esa regla y conseguir el resultado deseado.

Esta tecnología no espera que el programador se ciña a una interface, a un diseño por contrato, que utilice anotaciones, o cualquier otro tipo de meta-información embebida dentro de "su" código. El enfoque es radicalmente opuesto. La tecnología ofrece cosas al programador en vez de exigirle. Permite inyectar "por fuera" la funcionalidad requerida en el momento deseado.

Lo bueno de este enfoque, vuelvo a repetir, retornando al ejemplo, es que no hay que tocar el código fuente ya existente, las reglas se definen en otro fichero, y las funcionalidades quedan separadas completamente, es sólo en el fichero de reglas donde se encontrarán las referencias a los dos paquetes. Por un lado el sistema de gestión de cuentas, que se dedicará única y exclusivamente a gestionar cuentas, y por otro el sistema de logging, que se limitará a escribir al log.

¿Pero cómo se consigue esto en la práctica? Pues gracias a una serie de proyectos que han incorporado la AOP a lenguajes de programación de uso habitual. Para probar esto de una forma rápida y cómoda recomiendo AspectJ, que es una implementación para Java, y AJDT, que es su correspondiente plugin para Eclipse. En este ambiente, la definición de la regla del ejemplo quedaría escrita en un fichero con extensión ".aj" de forma similar a como se muestra en el ejemplo siguiente:

public aspect AspectLogging{

    pointcut logging() : execution(* com.enterprise.product.accounts.*.*(..) );

    before() : logging(){
        System.out.println(thisJoinPoint);
    }
}

El código es bastante sencillo, es más, tiene el aspecto de código Java ordinario, pero utilizando algunas palabras reservadas propias. Por ejemplo, aspect sirve para encapsular las reglas, de igual forma que lo hace class con los métodos y atributos. De hecho, un aspect funciona por defecto como un Singleton, y admite métodos y atributos como si fuera una clase ordinaria. La diferencia es que permite además incluir puntos de corte (pointcut), que sirven para definir los momentos concretos durante la ejecución del programa en los que se tiene que activar. Con execution se indica que se active, como si fuera un evento, cuando se ejecute un método que cumpla con el patrón que se le pasa como parámetro. Otras posibilidades incluyen handler para que se active al saltar una interrupción de un tipo concreto, call para cuando se invoque a un método, get para cuando se acceda a un atributo, y así sucesivamente. Merece la pena echar un vistazo a la documentación para hacerse una idea mejor de la potencia disponible. El parámetro que admite un punto de corte es una expresión regular que permite hacer referencia a una o más partes del código del programa. En el ejemplo la expresión tiene que leerse como "cualquier método, de cualquier tipo, de cualquier número de parámetros, de cualquier clase, del paquete com.enterprise.product.accounts".

La escritura de expresiones regulares siempre suele resultar una actividad un tanto viciante. Las combinaciones son infinitas, e incluso se pueden concatenar con "||" y "&&" como si fueran expresiones booleanas. Ahí van unas cuantas:

//Ejecución de cualquier método
    execution( * *(..) )

//Ejecución de cualquier método público
    execution( public * *(..) )

//Ejecución de cualquier método no estático
    execution( ! static * *(..) )

//Ejecución de cualquier método que admita un String
    execution( * *(String) )

//Ejecución de cualquier método "setNif" que admita un String y no devuelva nada
    execution( void setNif(String) )

//Ejecución de una excepción de la clase CustomException
    handler(CustomException)

//Cualquier lllamada a un método "set" realizada desde un objeto de la clase Account
    call( void set*(..) ) && target( Account )

Una vez definido un punto de corte se puede refinar un poco más el momento concreto en que se quiere activar, y asociarle el código que se quiere ejecutar. En el código de ejemplo se ha utilizado before para indicar que se quiere activar antes de que se produzca la ejecución de los métodos que cumplen con la expresión regular, pero también se podría haber utilizado after para indicar que se activara después de la ejecución, e incluso around para sustituir completamente el comportamiento del método original por otro. Esta última posibilidad es ciertamente deliciosa, por decirlo de una forma suave.

Por último, queda el código que queremos que se ejecute. Código Java simple y llano, como una vulgar salida por la consola estándar, que redirigida a fichero podría hacer las veces de tosco sistema de logging. De esta forma, lo que ocurrirá, es que cuando se ejecute cualquier método del paquete cuentas se ejecutará también el código con la salida por consola. ¡Objetivo cumplido! Y todo ello sin haber tenido que tocar ni una sola línea de código original. ¡Promesa cumplida! Y es más, si algún día la empresa decidiera cambiar el sistema de log por otro más elaborado, el cambio sería transparente, ya que bastaría con cambiar el código de la regla. E incluso si, en una última vuelta de tuerca, se decidiera cambiar el paquete de cuentas por otro, sería muy sencillo hacer que las nuevas clases escribiesen al log cambiado la expresión regular. El único problema extremadamente grave que se plantea es que ya no podremos facturar un número insano de horas a nuestros clientes por hacer estos cambios como veniamos haciendo hasta ahora. ¡Maldita tecnología!

Un último comentario acerca del ejemplo, sobre la palabra reservada thisJoinPoint. Almacena el punto de concreto dentro de la ejecución del código original en el que ha activado la regla. La he puesto a modo de referencia, para destacar el hecho de que dentro del código se puede hacer referencia a información de contexto. De hecho, se puede incluso referenciar al propio objeto dentro del que se ha producido el evento, y los argumentos que recibe o retorna el método. Recomiendo nuevamente mirar la documentación para ver las enormes posibilidades que ofrece AspectJ a este respecto.

Juan Mellado, 10 Abril, 2008 - 19:29

IndielibLoover publicó ayer un post en el foro de Stratos anunciando la salida de Indielib, un motor pensado para ayudar a los desarrolladores a programar juegos 2D muy rápidamente. Totalmente gratuíto, incluso para aplicaciones comerciales. Está escrito en C++, se entrega en forma de dos librerías para Microsoft Visual C++ 6 y 2008, y viene acompañado con un manual con toda la documentación en formatos HTML y PDF. El SDK contiene como bonus los ejecutables y fuentes de 19 tutoriales completos.

Técnicamente comentar que se apoya en SDL, DevIL y Direct3D. Esto último hace que sólo funcione bajo Windows, pero aporta la ventaja de que se utiliza la aceleración por hardware para realizar todas las operaciones gráficas. Gracias a ello también permite cargar modelos 3D para mostrarlos sobre fondos bidimensionales, algo habitual en algunas aventuras gráficas por ejemplo. En general tiene una lista bastante importante de características soportadas (features): interfaz sencillo, traslaciones, rotaciones, escalados, efectos, animaciones, colisiones, scrolls, varios tipos de cámaras, varios viewports simultáneos, ... y así un largo etcétera. En los ejecutables de las demos que vienen ya precompiladas pueden verse muchas de estas características en funcionamiento, aunque se echa en falta un jueguecillo.

En el post del anuncio pedía algo de promoción en el ciberespacio, así que sirva este post para la causa.