ZTT y Tapestry4

Este es el cuarto en una serie de posts donde hablo de ZTT en mi proceso de desarrollo.

1) Desarrollador ágil JAVA. ¿Oxímoron?
2) ZTT y Tapestry5
3) Matt Raible acerca de ZTT

Live Template Reloading

Tapestry4 tiene un muy promocionado "modo desarrollador" en el cual los cambios en los templates html se reflejan en la aplicación sin necesidad de reiniciar el servidor de aplicaciones.
Basta con agregar -Dorg.apache.tapestry.disable-caching=true al comando de ejecución del servidor de apps.

Si bien esta simple configuración es muy útil, tiene sus inconvenientes. El primero es que recarga todos los templates por cada request, hayan o no sido modificados. Cuando la cantidad de componentes en una página es muy grande (como suele ser mi caso) y cuando la cantidad de requests es mucha (como cuando se utiliza AJAX) la velocidad de respuesta de la aplicación se vuelve intolerable y después de la 5 o 6 recargas de la página suele dar algún que otro problema de memoria.

Una mejor alternativa es habilitar el servicio de reset usando -Dorg.apache.tapestry.enable-reset-service=true. Con este servicio habilitado es posible resetear la caché de templates y el pool de componentes simplemente accediendo a la URL /app?service=reset&page=Home o /reset.svc?page=Home

Existen varias propuestas de mecanismos para facilitarle al programador el acceso al servicio de reset. La opción tradicional es dejar abierto un tab del firefox en esa URL y hacer F5 cada vez que se quiera hacer reset. Andreas Andreu (uno de los commiters de tapestry) propone hacerlo desde un script de greasemonkey. Yo, en cambio, prefiero usar una tarea de ant:


<telnet port="8080" server="localhost" timeout="20">
<read>
<write>GET /reset.svc?page=Home HTTP/1.0</write>
<write></write>
</read>
</telnet>


El servicio de reset está desabilitado por defecto porque en producción podría ser muy fácilmente explotado para obtener una denegación de servicio.
Para habilitar reloading de templates en producción fui un paso más allá de lo documentado y expuse el servicio de reset via JMX (gracias a HiveMind) de tal manera de poder automatizar el reset de la cache tomando las mayores precauciones de seguridad (y así evitar un posible DoS).

hivemodule.xml


<contribution configuration-id="hivemind.EagerLoad">
<load service-id="hivemind.management.MBeanRegistry"/>
</contribution>

<contribution configuration-id="hivemind.management.MBeans">
<mbean service-id="TapestryMBean"/>
</contribution>

<service-point id="TapestryMBean" interface="
org.amneris.tapiz4.jmx.TapestryMBean">
<invoke-factory>
<construct class="org.amneris.tapiz4.jmx.TapestryMBeanImpl">
<set-object property="resetEventHub" value="infrastructure:resetEventHub"/>
</construct>
</invoke-factory>
</service-point>

<contribution style="font-weight: bold; font-style: italic;" id="hivemind.EagerLoad"><load id="hivemind.management.MBeanRegistry"></load></contribution><contribution style="font-weight: bold; font-style: italic;" id="hivemind.management.MBeans"><mbean id="TapestryMBean"></mbean></contribution><service-point style="font-weight: bold; font-style: italic;" id="TapestryMBean" interface="com.amneris.muba.jmx.TapestryMBean"><invoke-factory><construct class="com.amneris.muba.jmx.TapestryMBeanImpl"><set-object property="resetEventHub" value="infrastructure:resetEventHub"></set-object></construct></invoke-factory></service-point>java
import org.apache.tapestry.services.ResetEventHub;

public class TapestryMBeanImpl implements TapestryMBean
{

ResetEventHub resetEventHub;

public void resetTapestryCache()
{
resetEventHub.fireResetEvent();
}

public void setResetEventHub(ResetEventHub resetEventHub)
{
this.resetEventHub = resetEventHub;
}
}


Live Class Reloading

En cuanto a class reloading en Tapestry4, ya comenté en el post anterior que solo conozco 2 alternativas (si alguien de alguna más por favor que me lo comente).

1) Sysdeo tomcat launcher plugin (open source)
2) JavaRebel de ZeroTurnaround (software de pago, altamente recomendado)

Matt Raible acerca de ZTT

En un reciente post Matt Raible dice que si tuviera que pedir un deseo para el 2008 sería que todos los frameworks web en Java tuvieran soporte para ZTT.

Matt no usa el término ZTT sino que le dice "hot deploy", pero el concepto es el mismo. En su post menciona Groovy, Grails (que está en Groovy), Seam y Tapestry5 como frameworks que ya lo soportan "out of the box", y comenta que no debería ser necesario comprar JavaRebel para poder usar ZTT en Java sino que debería ser obligación de todo framework proveer esta funcionalidad (cosa que veo un poco difícil).

Yo soy un feliz usuario de JavaRebel y lo recomiendo. La única alternativa FLOSS que conozco es el tomcat launcher plugin de Sysdeo (si alguien conoce alguna más por favor que me lo comente), que viene con un classloader propio. El plugin de sysdeo es excelente pero tiene sus limitaciones, sólo funciona con el IDE Eclipse y con el servidor de aplicaciones Tomcat (cualquiera de sus versiones) y, además, tiene varios problemas especialmente cuando se agregan métodos nuevos a una clase o cuando se cambian parámetros en anotaciones.
JavaRebel, en cambio, funciona con cualquier IDE (incluso funciona con maven :D ) y con varios servidores de aplicaciones. Como contra tiene que no es open source y que su licencia cuesta $150 (aunque bien valen la pena).

Ambas alternativas son incompatibles con cambios de estructura en el modelo Hibernate. Me pregunto como hará Seam para manejar los cambios en el modelo? los detectará? Hmmm tendré que hacer la prueba.

Por cierto, si no saben lo que es JavaRebel no se pierdan el simpático corto animado: "La historia de un rebelde Java" (A Story of a Java Rebel)

ZTT y Tapestry5

Al comenzar a hablar de ZTT en java hay que hacer la siguiente aclaración: es prácticamente imposible asegurar que cualquier estrategia para ZTT para java funcionará en el 100% de los casos.
La principal razón para esto es que no hay una manera estándar establecida de hacer manipulación de bytecode de clases (weaving), y entonces cada framework o librería implementa su manera: algunos usan AspectJ, otros Javassist, otros Jakarta Commons JCI y otros como Tapestry5 implementan su propio ClassLoader.
Esto lleva a que varios esfuerzos para aproximarse a ZTT resulten incompatibles entre si y con determinados frameworks. El caso más típico es Hibernate. En esta serie de post veremos diferentes estrategias para acelerar el desarrollo al utilizar frameworks como Trails, Tapestry4, Tapestry5, Spring. Pero cuando se trata de Hibernate siempre hay que hacer consideraciones aparte, porque al realizar una modificación sobre una clase del modelo Hibernate, no todas las estrategias para ZTT funcionan correctamente. Hibernate tiene su propio weaving de classes (weaving estático con Javassist) que no permite hacer el cambio "on the fly" de una clase sin notificarle a Hibernate y recargar toda la configuración. En otro post mostraré de que manera se puede disminuir el impacto de esta limitación de Hibernate recargando el contexto de Spring.

Tapestry5 seamless ZTT


Una de las nuevas características de Tapesty5 es la recarga automática ("on the fly") de clases o templates que hayan sido modificados (Live Class and Template Reloading).
Lo mejor de la implementación de Tapestry5 es que funciona exactamente igual en desarrollo que en producción y no necesita (prácticamente) ninguna configuración o consideración extra.
Para verlo en funcionamiento se pueden consultar los excelentes screencasts de Tapestry5 que Howard ha preparado como introducción a las diferentes características del framework.
Incluso es realmente fácil de probar para aquellos familiarizados con Maven. Existe un archetype que permite probar estás caracteristicas de Tapesty5 en 10 minutos.
Las limitaciones: Tapestry5 implementa su propio ClassLoader y debido a la ambigüedades en las especificaciones de "class loading" (lo que ha generado varias discuciones) para servidores de aplicaciones, hay que tener ciertas precauciones al usar otros servidores de aplicaciones que no sean Jetty.
Otra limitación es que el class reloading se limita a clases controladas por Tapestry5 IoC, por lo que si el cambio ha sido en clases del modelo Hibernate o alguna clase que se inyecta via Spring, estos cambios no serán detectados.

Tapestry5 "Live Class and Template Reloading" es LO MEJOR (dentro del open source) que he visto para facilitar la vida del desarrollador web java y reducir el tiempo del ciclo de deployment al mínimo posible. Gracias a esta característica creo se convertirá en "él" framework web java del 2008 y seguramente volverá a ganar el premio que otorga Sun a la innovación en Java.

Desarrollador ágil JAVA. ¿Oxímoron?

Yo me considero un desarrollador ágil JAVA, o mejor dicho yo me considero un desarrollador ágil Tapestry. Pero he de reconocer que si bien la velocidad de desarrollo con Trails y/o Tapestry está entre las mejores del (sub)mundo JAVA, no sirve ni siquiera como punto de referencia cuando se la compara con la de otros lenguajes y frameworks.
Uno de los principales problemas del desarrollo en JAVA es la agilidad y productividad del programador. Realmente estamos lejos de imitar la agilidad con la que se puede desarrollar en lenguajes como Ruby o PHP, y si hablamos de frameworks web en particular, estamos lejísimos de frameworks como Rails o Akelos.

¿Por qué el desarrollo con Akelos o Rails es tanto más rápido/ágil que el desarrollo con cualquier framework web JAVA?
La clave es el Zero Turnaround Time (ZTT), que podría traducirse como: "Recarga sin demora" o "Recarga inmediata" o "Cero tiempo de recarga".
El ZTT permite que cualquier pequeño cambio en la aplicación se pueda ver inmediatamente en el navegador, simplemente alcanza con hacer "refresh" en el navegador y listo, "feedback inmediato".

El gran beneficio del feedback inmediato es que permite determinar muy rápidamente si los cambios en la aplicación son correctos o no, y ésta es la gran ventaja que hace que el "desarrollo ágil" vaya de la mano con ZTT.

Este es el punto de partida de una serie de posts donde compartiré mis trucos para agilizar mi proceso de desarrollo y para aproximarme (aunque sin alcanzarlo nunca) al ZTT.

¿A que framework web le deberías estar dedicando tu tiempo libre?

Uno de los desarrolladores de AppFuse (y escritor de un libro sobre AppFuse que está por publicarse) se pregunta que framework debería estar aprendiendo por las noches y se queja (aunque minimamente) de la cantidad de frameworks que ha tenido que aprender este año.

Entre los destinatarios de sus quejas estoy yo que intenté convencerle de que le preste un poco de atención a Trails. No lo logré :( pero las experiencias que hemos intercambiado han hecho que el intento valga la pena.

Como resultado de ese intercambio se creó una configuración de CAS usado como SSO que es compatible tanto con AppFuse como con Trails.

La versión para AppFuse se publicará en http://code.google.com/p/casidentity/
y la versión para Trails en http://code.google.com/p/amneris/

Continuando con el post de David y con el título de este post: Mi elección personal y recomendación es: Tapestry 5
Tapestry 5 va a ser la nueva revolución en el mundo Java, recuerden lo que les digo.

Por último David arenga a los programadores web Java a echarle un ojo a Rails y yo quiero aprovechar este post para hacer lo mismo.

MIREN RubyOnRails, préstenle atención, desarrollen algo, indaguen en las entrañas del framework (son una joya en cuanto a diseño y programacíon), les aseguro que como resultado de la exploración saldrán siendo mejores programadores (Java o cualquier otro lenguaje).

Conclusión:
Pregunta: ¿A qué framework web le deberías estar dedicando tu tiempo libre?
Mi respuesta: Tapestry 5 y/o Ruby on Rails