sábado, 2 de agosto de 2008

Lightweight vs Heavyweight

Hace poco tiempo atrás, la búsqueda del Santo Grial para las aplicaciones Java en el servidor era usar soluciones "livianas" y se consideraba que los servidores de aplicación JEE eran los campeones de la "pesadez". Era una conversación bastante confusa porque era difícil encontrar una definición clara del tema. Este blog es una retrospectiva sobre el tema.

Ciclo de vida de la búsqueda

Creo que la búsqueda de la liviandad se hizo popular porque usa los mismos términos que en la parte cliente donde el "cliente liviano" (el browser) tiene ventajas sobre las soluciones tipo "cliente pesado" ("fat client" o aplicación ejecutable Windows o Linux). Quedo en el sub-conciente colectivo que liviano es mejor que pesado.

Ahora, "pesado" dejo de ser un concepto tan negativo en la parte cliente. Las RIA consisten en dejar más pesadas las aplicaciones en los browsers, claro que no se dice "pesado", se dice "rico": es la traducción literal de "rich" en inglés que suena mal en español chileno cuando se dice "aplicación rica". Pero, se refiere a lo mismo, son aplicaciones más complejas que usan API's javascript como Dojo's, jQuery o plug-ins como Flex, Silverlight e incluso applet java ("el retorno", "java begins", etc)..

En la parte servidor no se dice "rico" sino "modular". Es aceptable que un contenedor sea "pesado" si levanta solamente los servicios requeridos por las aplicaciones que corren sobre el y, por esta razón, OSGI es tan popular.


¿Cuales eran los criterios para definir un contenedor como pesado?

Eso, nunca me quedo exactamente claro, pero leyendo comentarios de otros y en base a mi propia experiencia puedo deducir que los factores importantes en el mundo JEE eran:
  • factores que afectan el tiempo de aprendizaje y tiempo para montar la arquitectura base:
    • cantidad de especificaciones distintas: es casi imposible conocer "al dedo" todas las especificaciones de JEE y sus relacionadas: XML, Web Service, HTML, CSS, etc.
    • cantidad de páginas/complejidad de una especificación. Por ejemplo, cada vez que dejo de usar un tiempo EJB Session Bean voy a leer de nuevo el capitulo de manejo de transacción y de excepciones, porque me cuesta recordar este tema y es muy fácil mandarse un condoro.
    • cantidad de framework que extienden y/o reemplazan algunas API's: solamente contando los ORM (como Hibernate) y los MVC Web (como Struts) deben haber más de 100. Eso obliga a probar muchas combinaciones, para detectar incompatibilidades, lo que provoca una situación equivalente al "DLL Hell" de Windows
    • cantidad de patrones necesarios para sacar provecho a la arquitectura (por ejemplo, "sesión bean de fachada", "service locator", etc)
  • factores que afectan la implementación y mantención:
    • Turn-around o tiempo necesario entre hacer un cambio en el código y poder probarlo, lo cual incluye:
      • tiempo necesario para compilar la aplicación,
      • tiempo necesario para desplegar los artefactos EJB-JAR, WAR, EAR
      • tiempo necesario para arrancar el servidor,
    • cantidad de capas de código necesarias para mitigar problemas/lagunas en la especificación como por ejemplo: el uso de DTO entre la capa EJB y la capa de presentación porque no se especifico que pasaba con los EJB Entity Beans despues de terminar la transacción.
    • dependencia del ciclo de desarrollo hacia un IDE como por ejemplo, cuando algunas opciones criticas se pueden setear solamente a través del IDE del fabricante del servidor de aplicación,
    • dependencias hacia clases o interfaces de la API, por ejemplo, obligando a extender una clase padre. De allí, nació la mítica búsqueda del POJO
    • cantidad de clases y archivos de configuración a generar. Por ejemplo, un EJB requiere editar 3 archivos java y una entrada en XML
    • Muchas API's relativamente de "bajo nivel" como Servlet JDBC, JMS, JTA, que obligan a generar mucho código. Curiosamente son dentro de las más exitosas.
  • factores que afectan el ambiente de ejecución
    • cantidad de recursos, memoria, CPU, espacio en disco usado por el servidor de aplicación,
    • rendimiento, escalabilidad de los servidores: las primeras versiones no eran para nada optimizadas.

¿JEE es el gran culpable?

Los especificadores de JEE hicieron muchos errores. El método que se uso fue: especificar primero y luego ver como el mercado reacciona. Como consecuencia, se incluyo ideas, conceptos y soluciones no probadas o probadas dentro de otro contexto (por ejemplo con los monitores transaccionales en lenguaje C que precedieron).

Pero el método tuvo varios logros excepcionales:
  • se formo una comunidad gigantesca alrededor de Java y JEE,
  • la portabilidad de las aplicaciones no tiene equivalente en la historia de la TI. Comparamos un poco:
    • SQL básico (select, insert, update, delete, más definición de tipos de datos) se resume a 50 páginas de especificación. A pesar de eso, no hay portabilidad absoluta entre los motores. Y eso sin contar la incompatibilidad completa entre las implementaciones de los store-procedure,
    • Javascript, DOM, HTML es relativamente sencillo: todavía hay diferencias notables entre los browsers.
    • Ruby tiene varias maquinas virtuales e implementaciones de sus bibliotecas que tienen problemas serios de compatibilidad entre si.
  • las especificaciones cubren todo lo requerido por aplicaciones empresariales (el mundo Java hizo en menos de 5 años lo que tardo 30 años para lenguajes C y COBOL)
Entonces, estoy de acuerdo que las especificaciones JEE tienen algo de culpa, pero lograron crear un mercado que vino al rescate: Hibernate/Spring no existieran si no fuese por estos estándares. Consientes de las deficiencias, los especificadores se dedican a simplificar (desde JEE 5) y ahora, a modularizar (JEE 6).


Pero las especificaciones no son las únicas responsables. Para mi, la sensación de "pesadez" esta más asociada a las implementaciones de éstas y voy a volver a mencionar Resin porque es el mejor ejemplo que se puede implementar JEE sin crear un monstruo. Resin implementa EJB versión 2.x y a pesar de eso:
  • usa menos de 30 MB en mono-usuario,
  • arranca en segundos (similar o inferior a Tomcat)
  • recarga los cambios en los fuentes sin tener que rebootearse. Detecta cambios en los fuentes Java, los recompila y genera si necesario los artefactos intermedios (como stub, skeleton, tablas de la BD).
  • No requiere de un IDE e incluso de una herramienta tipo make (como ant o maven). Con jEdit (o cualquier editor que pinta la sintaxis del código) sobra y basta.
  • tiene archivos de configuración XML editables por humanos.
Estas capacidades permite editar un fuente Java en un editor de archivo, guardar el fuente y recargar la página web: exactamente igual a lo que se hace en PHP y Ruby. Para lograr todo eso, tuvo que extender las normas JEE para el tema de despliegue de aplicaciones (no obliga a usar EJB-JAR por ejemplo). Eso no es una violación a la norma, porque permite desplegar con todo lo de la ley si se desea mantener compatibilidad.

Al otro lado del espectro esta el campeón de la pesadez, el IBM WAS y WSAD (ahora Rational Application Developper). Seguro, WAS tiene muchas cualidades como robustez, seguridad, facilidad de monitoreo, rendimiento, escalabilidad y el soporte de la empresa más importante de la historia de la TI ("nadie pierde su trabajo por elegir IBM"), pero de liviano no tiene nada. Yo creo firmemente que cuando muchos programadores piensan en lo pesado que es JEE están pensando en WAS y WSAD.


Conclusión

La pesadez en las especificaciones JEE y los servidores de aplicación que las implementan existieron. Las nuevas versiones reducen el problema gracias a la modularización (JEE6 y Glassfish v3). Las implementaciones de JEE tuvieron un rol importante en crear esta sensación.

El termino es demasiado ambiguo y es bueno que se deje de usar. Para mucha gente, pesado implica lento y dificil de escalar: ningun servidor de aplicación moderno es lento o impide la escalabilidad.


Update 13 de Agosto de 2008

Netbeans 6.5 beta y Glassfish v3 acaban de lanzar la facilidad "Compile & Deploy on Save": luego de guardar un fuente en el IDE, el ambiente (servidor de aplicacion+IDE) recompila y deploya el proyecto automaticamente Resin tiene una competencia muy seria.

1 comentario:

Jorge.Rodriguez.Suarez dijo...

Francois:

Excelente Post.

Me gusto mucho la frase "Nadie pierde su trabajo por elegir IBM". Solo faltó "...en Chile..."

Es triste pero cierto que acá es casi sino totalmente imposible cambiar la mentalidad con respecto a eso.