domingo, septiembre 27, 2009

Sobre la Programación Orientada a IDE©

Hace algún tiempo que vengo luchando contra este concepto[*]. La idea viene de la falacia que todo hay que hacerlo desde dentro de la IDE. Así, la IDE es la que termina guiando nuestro desarrollo y volviéndolo uno con la decisiones unilaterales que han tomado sus desarrolladores.
No estoy para nada en contra de las IDE, solo de las IDE que te obligan a hacer las cosas de la manera que se les antoja. Ésta es una herramienta y no quiero que me obligue a nada, yo quiero usarla como se me antoje y mi profesionalismo me indique para expresar mi arte.

Yendo al contexto Java, que es donde me siento cómodo seguro por el momento, me he encontrado con incontables casos donde a la pregunta de "cómo es su ciclo de deploy" la respuesta comienza con "exportamos el proyecto desde eclipse"...
Por qué esto está mal (sin orden particular)?
• Se depende de un humano para armar 'entregables' (no hay integración continua)
• Atenta contra la posibilidad de incluir a un nuevo integrante al equipo que haga uso de otra herramienta
• Tenemos que manejar las dependencias desde el eclipse
Otros efectos colaterales:
• Tendencia a ensuciar los controladores de versiones con cosas propias de las IDE
• Tendencia a nunca entender lo que una IDE hace tan mágicamente (aunque esto es algo inherente a la estupidez en cualquier contexto)
Soluciones a esto:
• Uso de Maven

Por qué Maven?
Maven no es nada de otro planeta ni hace magias oscuras. Hace muy pocas cosas y las hace bien. Mediante el uso de Maven se obtienen algunos puntos muy positivos: controlar dependencias, manejar ciclos de deploy (incluyendo el empaquetado) y unificar (de manera IDE agnóstica) convenciones a la hora de trabajar. Ésto último tiene un punto a destacar alucinante, que venga alguien totalmente ajeno a nuestro desarrollo y no se sienta [tan] perdido frente a cientos de archivos de código; va a saber dónde estan los fuentes, dónde buscar tests, dónde mirar a grandes rasgos qué bibliotecas se usan y va a poder generar un entregable corriendo un solo comando.

Qué es lo peor que podés hacer?
Intentar ajustar maven a tu proyecto y no al revés. Maven es una herramienta para organizar, que si bien deja que modifiques sus convenciones al hacerlo estarías perdiendo muchas de las cosas que destaqué en la pregunta anterior. Cuando te convenzas que estas son las cosas que querés que tu proyecto cumpla, pagá el precio por haber comenzado por la senda del mal y purga tu alma moviendo archivos y repensando los paquetes que tiene tu sistema.

Qué es algo feo feo de ver?
A alguien usando JBoss Developer Studio para mostrar las maravillas de Seam (básicamente hot deploy) cuando realmente conciliar estas maravillas con las 'buenas prácticas' antes mencionadas es imposible (y lo peor es que la mayoría de la gente valora más un entorno de desarrollo a-La PHP en lugar de un proyecto ordenado).

Quiénes son los más horrorizados con no comer/ver la tele/dormir con la IDE?
Los desarrolladores .Net . Ellos han comprado una serie de preceptos guiados por Visual Studio y sus wizards, que se les hace arcaico y elitista tratar de usar herramientas de línea de comando, el resto simplemente "la complican de gusto".

Qué es lo que tendría que hacer un desarrollador nuevo cuando entra a un equipo?
• git clone [o el scm que quieran]
• mvn eclipse:eclipse [o la ide que quieran]
• [abrir la ide y buscar las cosas como tu intuición te indica]
• mvn package
• [deploy]
• [probar la aplicación]

Qué alternativas similares hay?
Para Java ninguna[**] y no me parece mal. Creo que se puede confiar bastante en los desarrolladores de maven como para que guien este camino.
Hablar de ciclos de desarrollo en otros lenguajes no puedo, solo comentar que en C se adolece del mismo problema que generó Ant en su momento, Autoconf/Autotools son infinitamente poderosos, infinitamente complejos y no existe una manera estándar de hacer las cosas, realmente una pena; apenas crece un poquito un proyecto C meterse es una tarea heroica.

[*]: término que nunca antes había escuchado :)
[**]: ant+ivy me parece una aberración mutante

viernes, agosto 28, 2009

Un poco de JAAS

Un poco de JAAS


Introducción:
JAAS es una especifación Java con el fin de autenticar y autorizar intenciones de acceso a recursos.
En en la práctica su uso más frecuente reside en la primera de estas dos intenciones. Esto, en mi opinión, se debe a que realmente la solución ofrecida para la autorización no es demasiado agradable para el desarrollador.

Filosofía:
JAAS está pensado para comportarse como una capa pluggeable que opera sobre dominios de autenticación. Su uso es totalmente transparente a través de la interfaz LoginContext que instancia todos los LoginModule del dominio especificado.
La idea de JAAS es proveer mucha generalidad sobre lo que significa la autenticación ya que no todo se hace a través de un par nombre de usuario/contraseña. Para esto, un LoginModule tiene que ser capaz de pedir la información necesaria para autenticar. Siendo la invocación de los módulos a través del LoginContext, es a este a quien se le pasa una instancia que implementa la interfaz CallbackHandler. El contrato establecido podría ser "cuando me llames al login, yo te voy a pedir estos datos". Haciendo nuevamente incapié en que esta información puede ser el nombre de usuario y la contraseña, la respuesta de un lector biométrico, la clave secreta que tiene una llave usb, etc., etc.
Durante el proceso de login (formalmente en el método LoginContext#commit), luego de una validación exitosa, se deja a disposición del invocador una instancia de la clase Subject. Un subject es simplemente un grupo de identidades que refieren a quien quiere ser autenticado. Algo interesante de JAAS es que no define un concepto claro de cuándo alguien está o no autenticado ya que este estado booleano acotaría la generalidad que se está intentando obtener. Podría ocurrir el caso en que alguien falle al autenticar y en este caso se le asigne una identidad fantasma con ciertos permisos según la hora del día en el que intentó la acción. En este caso tener un rol por defecto para acceder a ciertas acciones no basta. Así es que se deja que el LoginModule inserte tantos Principal como crea necesario para lo que le parezca y el que hizo el llamado de autenticación tendrá que saber interpretar el resultado. Cada Principal va a ser una implementación concreta de la interfaz que va a quedar disponible a través del subject.
Inmediatamente después de creada la instancia de LoginContext ya se le puede pedir el subject, este subject, al no haber pasado nunca por ningun LoginModule, va a encontrarse vacío de todo principal, pero es válido pedir su referencia.
Las semánticas para esta lista de Principal son múltiples, una lista vacía puede indicar un usuario todavía no autenticado, alguien autenticado que no puede hacer nada, alguien sobre el que falló la autenticación, entre otras. Así como también la presencia de Principals puede referir a múltiple información sobre el sujeto en cuestión: roles, claves públicas, vcards, etc.

Implementación:
La solución de JAAS puede ser usada tanto para una aplicación web como para una aplicación standalone de manera similar. No existe un servicio de autenticación ni mucha magia detrás del hecho de entender que el LoginContext obtiene de una configuración la lista de LoginModule que tiene que instanciar para cada dominio de autenticación. Además también tiene que suministrar el callback a través de los cuales cada LoginModule requerirá datos de entrada.
Los puntos oscuros de esta generalidad se encuentran fundamentalmente en dos lugares. Primero al momento de implementar el CallbackHandler, ya que el LoginModule sabe qué va a requerir pero al tener una interfaz genérica solo puede pedir cualquier cosa que implemente la interfaz Callback y esperar a que en runtime lo que yo quiero en mis callbacks sean bien llenados por quien los implementó. Esto se va a ver más claro con algo de código:
  • Al instanciar el LoginModule se le pasa un CallbackHandler.
  • En el método login el LoginModule hace uso del CallbackHandler para obtener lo que espera para autenticar.
  • Lo muestro en orden inverso ya que me parece más claro para entender el problema

[LoginModule#login]

RightFingerCallback fingerCallback = new RightFingerCallback();
USBKeyCallback() usbCallback = new USBKeyCallback()
callbackHandler.handle(new Callback(){fingerCallback, usbCallback});
metodoDeAutenticacionExtranho(fingerCallback.getFingerprintAsGifImage(), usbCallback.getKeyHardwired());


[Clase que intenta autenticar algo]

LoginContext loginContext = new LoginContext("dominio-raro-y-seguro", new CallbackHandler(){
public void handle(Callback[] callbacks) throws ...{
for(Callback callback : callbacks){
if(callback instanceof RightFingerCallback){
((RightFingerCallback) callback).setFingerprintAsGifImage(obtainFprint());
} else if (callback instanceof USBKeyCallback){
...
}
}
}
}

  • Sí, hay instanceof... se pueden hacer en algunos contextos juegos de polimorfismo pero en la mayoría de los casos hay que enfrentarse con esta situación y es importante saber que uno va a salir ligeramente herido en este camino.


El segundo lugar donde se busca generalidad es en la asignación de identidades ya que no todas las aplicaciones manejan roles, ni vcards, ni claves públicas, etc. Así se llega al punto donde así como se tienen Callbacks específicos para mis necesidades, se tienen Principal específicos para identificar la información que el autenticador me puede dar.
Otra vez algo de implementación:
  • Los principal se agregan en el metodo commit ya que no hay que olvidar que nuestro LoginModule convive eventualmente en una cadena de módulos de autenticación y es posible que alguno de ellos no valide con lo que si completamos el subject antes de llamar a todos los login() del dominio vamos a darle identidades a nuestro sujeto que no queremos (o sí, pero estas cuestiones se manejan en cuanto a la configuración de cómo interactúan los módulos entre sí -demasiado avanzado para esta introducción conceptual-)


[LoginModule#commit]
...
getSubject().getPrincipals().add(new MyPrincipal());
...


Así que, una vez ejecutado el método login del LoginContext va a quedar un subject hidratado (dependiendo si autenticó) con los Principal que definirán su identidad dentro de nuestro dominio, pudiendo filtrarlos e inspeccionarlos para decidir si son autorizados o no.

Dentro de JBoss Application Server:
Siendo JAAS un modelo de seguridad tan independiente, el AS no puede proveer demasiado para su funcionalidad básica. Hablando de la rama 4.2.x, se cuenta con el mbean XMLLoginConfig que hace más amigable la escritura de dominios mediante xml que por defecto se encuentra en <name>/conf/login-config.xml, el archivo en sí es bastante autoexplicativo y por cualquier duda más allá de lo evidente, se puede consultar el dtd en docs/dtd/security_config.dtd

Resources (o "no dije mucho más de lo que aparece en los siguientes links"):

domingo, mayo 10, 2009

Resteasy+JSON toma 1

RestEasy hace honor a su nombre y exponer un servicio rest es violentamente sencillo.
Es dificil agregar algo a este genial post
http://www.assertionerror.com/2009/02/26/restful-web-services-with-resteasy/

Mi vuelta de tuerca fue usar binding automático a través de jaxb, más aún, hacerlo directamente a json.
Así enviaríamos por rest lo siguiente:
{"person":{"name":"Joe Bloggs","phoneNumber":"123456789"}}
Retocando el post en el que me basé para este ejemplo, habría que cambiar los métodos createEntry, getEntry y updatePerson para recibir un Person en lugar de InputStream y eliminar los métodos helpers readPerson y outputPerson. Luego, lo que se consume y produce pasa a ser "application/json" así que se ajustan las annotations @Consume y @Produce (también hay que cambiar el test para que envíe como Content-Type lo mismo).
Finalmente la clase Person queda

@XmlRootElement(name = "person")
public class Person {
[...]
@XmlElement
public String getName() {
return name;
}
[...]
@XmlElement
public String getPhoneNumber() {
return phoneNumber;
}
[...]
}

Por ahora todo parece marchar sobre ruedas... veamos a qué evoluciona :)

Descarga del ejemplo con maven
Notas:
* en algún momento del lado el servidor interpreta que si le mando un número que comienza con 0, debe sacarlo, no importa si mi pojo tiene un atributo que es del tipo string.
* usar el server embebido como sugieren para unit testing no me llevó a los mejores resultados, luego del primer request, este se quedaba tildado y moría x timeout con un -1 como respuesta http. En el AS no tuve ningún problema al tirar el war y testearlo
Doc oficial: http://www.jboss.org/file-access/default/members/resteasy/freezone/docs/1.1-RC2/userguide/html_single/index.html

post-original
comentarios-a

viernes, mayo 08, 2009

Primer caso de éxito (personal) de Drools

Escribo para comentar mi primer experiencia con el uso de drools-expert en el campo comercial.
El desafío era realizar un servicio de búsqueda de servicios de correo entre distintos destinos. El problema con estos es que son muy arbitrarios, cambiantes y además el sistema debía soportar el agregado de distintos servicios menores que realizaran trayectos específicos.
Lamentablemente el post no será introductorio, para comprender lo siguiente deberían tener algo de jerga Drools o bastante imaginación. Igualmente puede ser útil que algo de esto quede en la cabeza mientras estén aprendiendo. Decidid vosotros.
También cabe destacar que todo el desarrollo estuvo basado en la versión 5.0.0.CR1 con lo que puede cambiar en las siguientes versiones.

En el camino, aparte de formar mi cabeza en modo Drools (pensar en activaciones, updates a la working memory, etc), me he topado con algunas cosas a tener en cuenta que no encontré en la documentación:
  • El KnowledgeAgent, daemon que me permitiría el traspaso de compilar las reglas de manera local al uso de guvnor, no soporta el compilado de reglas basadas en un DSL.
  • Los archivos de reglas escritas en DSL, tienen que ser del tipo DSLR y no se pueden mezclar reglas en DSL y reglas en mvel puro.
También como experiencia personal me queda como positivo la capacidad de cambio de reglas a medida que uno va aprendiendo más del lenguaje y cómo funciona. En un principio usamos hasta un RuleFlow para que un conjunto de reglas se ejecute antes que otras (se podría haber usado AgendaGroup también pero eso nos obligaba a setear el foco desde dentro de cada regla) y terminamos volando todo siendo este cambio completamente transparente a la aplicación.
Todo depende de definir un dominio agradable, y unas interfaces piolas, pero en sí, el flujo de evolución de Drools resultó absolutamente gratificante.
Como producto final puedo mostrarle el tipo de reglas que cualquier persona puede llegar a escribir:
regla "CA Cap Fed Rosario"
cuando
hay un envio de "Correo Argentino" con
ciudad de origen "Capital Federal"
ciudad de destino "Rosario"
entonces
el servicio es "Regional"
fin
El próximo paso del proyecto es manejar el flujo de un envío, así que voy a hacer todo lo posible para introducir Rule-Flow, no necesariamente porque haya hecho una comparación contra JBPM (del cual cuento con cierto background), sino que voy a intentar no diversificar tanto las tecnologías utilizadas. En las próximas entregas más novedades.

miércoles, mayo 06, 2009

Nace JBug Argentina

domingo, abril 26, 2009

Iniciandome con clutter y gnome-games

Como proyecto personal voy a intentar migrar a Clutter el juego gnobots2 utilizando el upstream de Clutter al menos hasta que salga la primer 1.0 estable.

Comienzo haciendo clone de todo gnome-games, clutter y clutter-gtk
$ git clone http://git.gnome.org/gnome-games
$ git clone git://git.clutter-project.org/clutter
$ git clone git://git.clutter-project.org/clutter-gtk

Compilo clutter y clutter-gtk.
Dentro de la carpeta gnome-games aplico el siguiente parche para que me deje funcionando clutter adentro de gnobots2 aplico estos dos pareches.

From 98601c7991dfed4b8a544133866070ffe11d7261 Mon Sep 17 00:00:00 2001
From: =?utf-8?q?Diego=20L=C3=B3pez=20Le=C3=B3n?=
Date: Sun, 26 Apr 2009 03:09:40 -0300
Subject: [PATCH] modified to use clutter 0.9

---
configure.in | 12 +++++-------
1 files changed, 5 insertions(+), 7 deletions(-)

diff --git a/configure.in b/configure.in
index 968405e..3329f08 100644
--- a/configure.in
+++ b/configure.in
@@ -562,8 +562,8 @@ fi
if test "$enable_clutter" = "yes"; then
CLUTTER_API_VERSION=
AC_MSG_CHECKING([for clutter API version])
- for API_VERSION in 0.8; do
- PKG_CHECK_EXISTS([clutter-$API_VERSION clutter-cairo-$API_VERSION],
+ for API_VERSION in 0.9; do
+ PKG_CHECK_EXISTS([clutter-$API_VERSION],
[CLUTTER_API_VERSION=$API_VERSION; break],[])
done
if test -z "$CLUTTER_API_VERSION"; then
@@ -571,13 +571,11 @@ if test "$enable_clutter" = "yes"; then
fi
AC_MSG_RESULT([$CLUTTER_API_VERSION])

- CLUTTER_REQUIRED=0.8.8
- CLUTTER_GTK_REQUIRED=0.8.3
- CLUTTER_CAIRO_REQUIRED=0.8.2
+ CLUTTER_REQUIRED=0.9.3
+ CLUTTER_GTK_REQUIRED=0.9.0

PKG_CHECK_MODULES([CLUTTER],[
- clutter-$CLUTTER_API_VERSION >= $CLUTTER_REQUIRED
- clutter-cairo-$CLUTTER_API_VERSION >= $CLUTTER_CAIRO_REQUIRED])
+ clutter-$CLUTTER_API_VERSION >= $CLUTTER_REQUIRED])
AC_SUBST([CLUTTER_CFLAGS])
AC_SUBST([CLUTTER_LIBS])

--
1.6.2.4

y luego

From 7517b3108fd3dce3bfb03b272c13115d0025db08 Mon Sep 17 00:00:00 2001
From: =?utf-8?q?Diego=20L=C3=B3pez=20Le=C3=B3n?=
Date: Sun, 26 Apr 2009 05:03:08 -0300
Subject: [PATCH] add clutter as dependency for gnobots2

---
gnobots2/Makefile.am | 6 ++++++
1 files changed, 6 insertions(+), 0 deletions(-)

diff --git a/gnobots2/Makefile.am b/gnobots2/Makefile.am
index 377ad20..0924855 100644
--- a/gnobots2/Makefile.am
+++ b/gnobots2/Makefile.am
@@ -59,6 +59,12 @@ gnobots2_CFLAGS += $(GHTREAD_CFLAGS)
gnobots2_LDADD += $(GTHREAD_LIBS)
endif

+if HAVE_CLUTTER
+gnobots2_CFLAGS += $(CLUTTER_CFLAGS) $(CLUTTER_GTK_CFLAGS)
+gnobots2_LDADD += $(CLUTTER_LIBS) $(CLUTTER_GTK_LIBS)
+endif
+
+
pixmapdir = $(pkgdatadir)/gnobots2/pixmaps
pixmap_DATA = gnomes.png \
yahoo.png \
--
1.6.2.4

Esto nos va a dar la posibilidad de habilitar clutter en el desarrollo de gnobots2.
Antes de trabajar hay que decirle a dónde buscar los .pc de clutter que acabamos de compilar. En mi caso sería:
$ export PKG_CONFIG_PATH=~/dev-new/c/clutter-upstream/dist/lib/pkgconfig:~/dev-new/c/clutter-gtk-upstream/dist/lib/pkgconfig
Ahora corremos el autogen.sh, con el fin que yo persigo sería:
$ ./autogen.sh --prefix=`pwd`/dist --enable-games=gnobots2 --enable-clutter
$ make && make install
esto nos dejaría listo en dist/bin/gnobots2 el ejecutable y ya en el código podemos agregar nuestras amigas líneas de uso de clutter

Más info de clutter, leer este tutorial.
En la próxima espero ya postear avances concretos sobre el juego

miércoles, abril 22, 2009

Primeros pasos con GIT-SVN

Partiendo de una infraestructura de SVN, todavía se puede aprovechar la versatilidad que te provee GIT para trabajar en tus modificaciones diarias e inestables (incluso muchas veces destructivas).
En el ejemplo voy a intentar hacer una demo con el svn de JBoss particularmente con el módulo de Drools.
$ git svn clone -s http://anonsvn.labs.jboss.com/labs/jbossrules/trunk/ drools-upstream && cd drools-upstream
si bien es interesante hacer esto, tarda realmente mucho, mucho, MUCHO... me fui a dormir cuando iban 6 horas... y parece que daba para bastante más. Igual vale bien la pena si uno está pensando en colaborar con alguno de estos proyectos.
Para empezar a trabajar creamos un nuevo branch del master (o el trunk en jerga SVN)
$ git checkout -b mi-feature-loca
el -b nos situa directamente en ese branch.
Comandos relacionados con la interacción git-svn:
  • git svn fetch, trae todos los cambios del repositorio SVN remoto
  • git svn rebase, igual que el anterior pero hace fast-forward de nuestros commits así quedan alineados con el árbol principal (explotando cuando no puede resolver solo los conflictos)
  • git svn dcommit, envía nuestros cambios locales como sucesivos commits de svn con los mensajes exactamente como los teníamos localmente.
Cosas útiles en el desarrollo diario:
  • git branch muestra los branches que tenemos en nuestro repositorio local resaltando el que estamos parados. Para esto también está bueno tener agregado en algún lado del PS1 de bash lo siguiente $(__git_ps1 "#%s") , que nos agrega el branch sobre el que se trabaja.
  • git status muestra el estado del index, que es la lista de los archivos conocidos por git.
  • git add para agregar los archivos del próximo commit. A diferencia de SVN hay que agregar cada archivo antes de commitear.
  • git commit es evidente, pero para los que prefieran ahorrarse el paso anterior, pueden hacer git commit -a que envía todos los cambios en el index.
Nota al pie:
Cada vez que quieras hacer un git svn rebase luego de haber felizmente levantado todo el entorno en eclipse o sencillamente habiéndole pasado el bienaventurado mvn eclipse:eclipse, git te va a decir que los .classpath y los .project están distintos, que los mergees.
Lo primero que tienen que hacer es aumentar el karma negativo hacia cualquiera de los core developers, esto puede ser aleatorio o en grupo da igual, por permitir que esto sea así. La idea final es que en su próxima vida vuelvan en modo alimaña--.
Después lo más sano es volar todos los archivos estos y dejarle que los vuelva a cero. Para ellos copien esta línea que hará su trabajo.
git checkout drools-ant/.classpath drools-api/.classpath drools-clips/.classpath drools-compiler/.classpath drools-container/drools-mc/.classpath drools-core/.classpath drools-decisiontables/.classpath drools-examples/drools-examples-drl/.classpath drools-examples/drools-examples-drl/.project drools-examples/drools-examples-fusion/.classpath drools-examples/drools-examples-fusion/.project drools-guvnor/.classpath drools-jsr94/.classpath drools-persistence-jpa/.classpath drools-pipeline/drools-messenger-jms/.classpath drools-pipeline/drools-transformer-jaxb/.classpath drools-pipeline/drools-transformer-jxls/.classpath drools-pipeline/drools-transformer-smooks/.classpath drools-pipeline/drools-transformer-xstream/.classpath drools-process/drools-bam/.classpath drools-process/drools-process-task/.classpath drools-process/drools-workitems/.classpath drools-repository/.classpath drools-server/.classpath drools-solver/drools-solver-core/.classpath drools-solver/drools-solver-examples/.classpath drools-templates/.classpath drools-verifier/.classpath
git checkout nos sirve para volver para atrás, al último estado commiteado, a un archivo.