domingo, 15 de julio de 2012

Spring V.S. Java EE

En Epidata Consulting, empresa especializada en Arquitectura de Software, donde yo trabajo, cada tanto realizamos charlas internas, externas (para universidades o clientes) y charlas-debate a los que solemos llamar "On The Rocks". En un ambiente relajado, con cerveza y snacks, debatimos sobre algún tema en particular. El viernes hicimos una "On The Rocks" llamada "Spring V.S. Java EE", y salieron algunas ideas interesantes.

Spring y Java EE son dos potentes soluciones para Middleware. Ambas presentan las mismas funcionalidades, ambas llenan los mismos huecos. Si tuvieras que empezar un nuevo proyecto Java Enterprise, ¿usarías Spring o Java EE? ¿Cuáles son las variables que pueden condicionar tu decisión? ¿Cuál es el estado de arte de ambas tecnologías? ¿Son realmente antagonistas?

Contexto


En el comienzo nació la especificación J2EE (versión 1.2 en 1999, versión 1.3 en 2001 y versión 1.4 en 2003) y Rod Johnson vio que era malo. Las implementaciones eran lentas, pesadas; el estilo de programación era verboso, lleno de tareas repetitivas, tedioso; un "hola mundo" en EJB 1.1 requería una cantidad de clases, interfaces y archivos XML desproporcionada. Recordemos que el lenguaje Java se había publicado apenas tres años atrás.

En 2002, Rod Johnson publicó un framework que servía como alternativa a los lentos y pesados EJB 2.0 de la época, un contenedor "liviano" (noten que ya de por sí el insidioso término "liviano" sugería una rivalidad; como dicen los ágiles: ¿quién no quiere ser liviano?). El framework básicamente hacía lo mismo que los EJBs (los EJB se reemplazarían por Spring Beans) y proveería también distintos módulos para facilitar el acceso a datos usando Java EE (en ese entonces la especificación JDBC) o frameworks de persistencia populares como Hibernate y más adelante iBatis. En 2004 se lanza la versión 1.0 de Spring, que viene a sacar del "invierno" a los programadores J2EE, ofreciendo una alternativa, una salvación: su contenedor "liviano" y los conceptos de Inversión de Control e Inyección de Dependencia.

En mayo de 2006 llega el contraataque del lado de la JCP (Java Community Process). Después de tres años sin publicar una nueva versión, J2EE 1.4 (JSR-151) pasa a llamarse Java EE 5 (JSR-244) y muchos de los productos que venían pegando en la comunidad Open Source (Hibernate y Spring, entre otros) pasan a ser especificaciones. Hacía dos años que el lenguaje Java SE se había renovado, metiendo las anotaciones, esa nueva y controvertida forma de configurar, y la plataforma enterprise tomó ventaja absorbiendo las anotaciones para su configuración, rivalizando contra los verbosos y molestos descriptores XML de configuración de Spring y J2EE. Nacen JPA 1.0, EJB 3.0, JSF 1.2 y JAX-WS (para hacer servicios SOAP) como las sub-especificaciones que hacen la diferencia. Las implementaciones se van mejorando (Glassfish, JBoss, Weblogic, Websphere). Por primera vez el estándar saca ventaja y deja atrás a Spring.

En 2005, un año antes de la salida de Java EE 5, Rod Johnson funda la empresa SpringSource. Más adelante, Spring Framework incorpora las anotaciones a su inyector de dependencias, pero lo hace mucho tiempo después; recién en la versión 2.5 podemos hacer un uso full de ellas. Aunque EJB 3.0 y JPA presentan una mejora considerable, siguen perdiendo frente a Spring en funcionalidades como Orientación a Aspectos e Inyección de Dependencia, que sigue siendo mucho más potente (en Java EE 5 sólo podemos tener inyección de dependencia dentro de un EJB).

El 10 de diciembre de 2009, la JCP pone en jaque verdaderamente a Spring con su nueva versión de la especificación: Java EE 6. Una nueva sub-especificación viene a llenar los huecos de Java EE 5, la JSR-299, más conocida como CDI (Contextos e Inyección de Dependencia para Java). CDI puede correr sin un contenedor de EJB (como Spring, puede correr en un Tomcat, un Jetty o standalone), ofrece inyección de dependencia omnipresente, una capa de presentación stateful y declarativa, manejo de eventos avanzados e interceptores mucho más potentes que los que proveía EJB 3.0, con los que puede rivalizar en el mundo de la Orientación a Aspectos. Como si fuera poco, Java EE 6 trae JAX-RS (para hacer servicios REST), JPA 2.0 (con muchas mejoras) y EJB 3.1, que, entre otras ventajas, permite empaquetar EJBs en un paquete WAR.

Java EE y Spring en un Vistazo de Águila

Así está la cosa hoy en día. Java EE 6 es la última especificación de la JCP, contando con 17 implementaciones certificadas a la fecha y Spring Framework, la única implementación, se encuentra por la versión 3.1.0. En 2009, VMWare adquirió SpringSource y hace unos días, Rod Johnson, CEO de SpringSource, anunció su inminente renuncia de VMWare.

Algunas Comparaciones


La competencia es muy buena para el consumidor, en este caso los programadores. Spring y Java EE fueron copiándose mutuamente a lo largo de los años, mejorándose en función de lo que su rival todavía no hacía o hacía mal. Así como entre 1957 y 1975 hubo una carrera espacial entre la URSS y EEUU, se puede decir que SpringSource y la JCP libraron su propia carrera hacia la solución de Middleware perfecta. La carrera todavía no está terminada. Algunos dicen que sí, algunos dicen que la era de los frameworks está terminando. Yo no creo que todavía esté dicha la última palabra.

I. Estado de Arte


A la hora de hacer comparaciones es justo tomar las últimas versiones, evaluar el estado de arte de ambos lados de la balanza. Es ilógico comparar Spring 3 con EJB 2, una tecnología de hace once años. Estamos en la segunda década del siglo XXI y la especificación vigente es Java EE 6, comparemos entonces CDI 1.0 y EJB 3.1 contra Spring 3.1.

Todos nosotros, en general, usamos versiones antiguas en el trabajo. Es perfectamente normal, ya que no se comienzan proyectos con la velocidad con la que salen frameworks y especificaciones Open Source. A menudo mantenemos software heredado que cuenta con versiones viejas de Spring o de J2EE. Pero si tenemos que comenzar un nuevo proyecto, para que nuestra evaluación de tecnologías sea válida, tenemos que actualizar las versiones, e incluso mirar más allá, mirar hacia el futuro, hacia las versiones beta, las funcionalidades futuras que se discuten en las comunidades y las especificaciones draft.

II. Funcionalidades


A la hora de evaluar, no creo que sea importante en sí las funcionalidades o servicios que uno provee y el otro no, ya que mañana los dos la proveerán. Esta es la "carrera" por la solución de Middleware a la que antes me refería.

Últimamente los IDEs están viniendo con súper wizards para generar aplicaciones de forma instantánea. Simples CRUDs se pueden escribir de forma automática con Spring Roo, en el mundo de Spring, o con JBoss Forge, en el mundo de Java EE. Hay plugins para Eclipse, NetBeans, JDeveloper, que pueden acelerar la escritura de código y el aprendizaje; en Spring tenemos por ejemplo SpringSource Tool Suite, en Java EE podemos contar con JBoss Tools, o el mismo JDeveloper de Oracle si programamos para Weblogic, por ejemplo, o el mismo NetBeans que ya trae plugins out-of-the-box muy potentes para Glassfish.

Ninguno de los dos mundos tiene soluciones perfectas. Cuando uno sigue un tutorial puede encontrar errores. Los quick-starts tienen errores o se van desactualizando muy rápidamente. Las documentaciones están incompletas. Pero es el precio de la innovación, el precio del Open Source. Los tiempos se aceleran en los negocios, y deben acelerarse en el desarrollo de software para no morir ahogado por los requerimientos. A la hora de capacitarse, un programador debe ser cauteloso y tener criterio para entender los conceptos, más allá de la cantidad de botones "Siguiente" que debe presionar.

III. La Era de los Frameworks ha Terminado


La diferencia más grande entre Spring y Java EE es que el primero es un framework y la segunda una especificación. Spring tuvo un creador, Rod Johnson, que fundó una comunidad y una empresa alrededor de su framework y hoy en día no es más que eso: un conjunto de librerías, que uno puede descargar por la página oficial del proyecto o de los repositorios centrales de Maven, y utilizar; son un conjunto de JARs. En cambio, Java EE es un conjunto de especificaciones estándares, escritas, revisadas y aprobadas por una comunidad de expertos, que en su conjunto definen qué servicios debería proveer y cómo se debería programar en una plataforma para aplicaciones empresariales.

Para que una especificación sea terminada, tiene que pasar por un largo proceso en el que la misma nace en Draft Version, pasa a diferentes estados de Review, y por último llega a una Final Version. Las especificaciones pueden deprecarse o cancelarse. Para que la especificación llegue a Final Version, el comité de expertos de la JCP debe revisarla, puede corregir errores, aportar modificaciones y en una última instancia votar. Los expertos de la JCP son empleados de distintas empresas interesadas, entre ellas Apache, Oracle, Red Hat, IBM. O sea que, cuando usamos alguna interfaz que pertenece a una especificación, estamos usando un contrato que fue pensado y aprobado por grandes mentes humanas.

En la práctica, una especificación se traduce en un conjunto de interfaces Java. Luego, distintas comunidades Open Source y/o empresas pueden codificar las clases que implementen esas interfaces. A menudo, los mismos que están escribiendo la especificación codifican una implementación para corroborar que las interfaces tienen sentido. Ésas pasan a ser las implementaciones de referencia, las primeras Open Source que se publican. Luego, las distintas empresas pueden desarrollar sus propias implementaciones, respetando la especificación e incluso proveyendo más servicios que enriquezcan la especificación pero que, por supuesto, no sean estándares. Ejemplos hay muchos. Por mencionar algunos de los más conocidos: la implementación de referencia de JPA 2 es EclipseLink, otras implementaciones pueden ser Hibernate de Red Hat, TopLink de Oracle o OpenJPA de Apache; la implementación de referencia de EJB 3.1 es el contenedor de EJBs de Glassfish, otras implementaciones pueden ser JBoss de Red Hat, Weblogic de Oracle, Websphere de IBM o TomEE de Apache; la implementación de referencia de CDI 1.0 es Weld de Red Hat (pueden leer más de CDI en este post y en este otro).

IV. Portabilidad


La filosofía del lenguaje Java siempre fue: Write Once, Run Anywhere, y la forma en que se aseguró de lograr esto fue mediante especificaciones y estándares. Java SE define cómo debe ser el lenguaje, qué debería entender un compilador Java y qué debería ejecutar una máquina virtual (JVM). Así, cada fabricante de celular, electrodoméstico, sistema operativo para PC, servidores, etc, sólo debía escribir su propia máquina virtual, que corriera sobre su propia plataforma, y que implementara las especificaciones, para que los programadores pudieran escribir sus programas una sola vez y lo ejecutaran en cualquier plataforma que implementara una JVM.

Java EE es el conjunto de especificaciones que define los servicios que debe proveer una plataforma de software Java empresarial, en la práctica: un servidor de aplicaciones. Los servidores de aplicaciones son aquellos que implementan los estándares de Java EE. Cada proveedor (Red Hat, Oracle, IBM, Apache, etc) está obligado a respetar cierta funcionalidad y configuración para poder certificar con Oracle (el dueño legal del lenguaje Java), para poder ser aceptado dentro de un perfil válido y aparecer en esta lista oficial. Los perfiles no son más que distintos subconjuntos de sub-especificaciones Java EE. Además, cada proveedor puede implementar funcionalidad no estándar para mejorar algún aspecto de su implementación. Por eso es que si programamos contra el estándar, tenemos libertad para elegir el proveedor. Un EJB se usa y configura de la misma forma en un JBoss, Weblogic, TomEE o Glassfish. Si tenemos problemas con un servidor de aplicaciones y queremos pasarnos a otro que luce más estable, podemos hacerlo sin modificar el código de nuestra aplicación. En cambio, si el contenedor de Spring funciona mal, no tenemos ninguna otra alternativa.

Spring tiene una definición distinta de portabilidad que Java EE. Mientras que un servidor Java EE es una plataforma, que ya provee todas las implementaciones de las especificaciones en forma de librerías, Spring es un conjunto de JARs que deben ir dentro de tu empaquetado, generalmente un WAR. Cuando armamos un paquete de Java EE, no incluimos las librerías dentro de nuestra aplicación, porque ya existen en la plataforma en la que se ejecuta. Para asegurarnos la portabilidad en Java EE, a la hora de cambiar de servidor, tendremos que fijarnos que el servidor de destino implemente la misma versión de la especificación que el servidor de origen, y que nuestras aplicaciones no estén usando librerías y configuración fuera del estándar. En cambio, cuando usamos Spring, como en cada aplicación metemos todo el contenedor dentro del empaquetado, no habría problema de desplegar en cualquier servidor, así sea un JBoss 4, un JBoss 7, un Weblogic 12 o un Tomcat.

Claro que, la desventaja que tenemos con Spring, nada menor, es el tamaño de nuestros entregables. Para hacer un WAR que contenga una página con un CRUD simple o un Hola Mundo, ya tenemos que incluir un montón de librerías cuyo peso suma en varios megas.

V. Vendor Locking


Por todo lo que vengo explicando en los puntos anteriores, algunos dicen que Spring hoy es "legacy", un sistema heredado de aplicaciones que se construyeron cuando Spring sí era necesario y J2EE no podía competir. La libertad para elegir los contenedores de Java EE inclina mucho la balanza. Hay servidores de aplicaciones Open Source como Glassfish, hay otros como JBoss que también son comunitarios pero se pueden comprar suscripciones a través de Red Hat para obtener versiones más estables y soporte, hay otros como Weblogic y Websphere que se venden por licencias.

Spring tiene la desventaja de ser "vendor locking". Cuando en un proyecto se elige trabajar con Spring automáticamente se casa con SpringSource, hoy propiedad de VMWare. El proyecto queda atado de pies y manos al futuro de SpringSource y VMWare. Si el día de mañana la comunidad de Spring se disuelve, si a VMWare ya no le interesa el proyecto, tus proyectos basados en Spring van a quedar en una situación delicada (y sino pregúntenle a los miles de proyectos que están hechos con Flex).

Si a Red Hat dejara de interesarle JBoss, si Glassfish se discontinúa, no sería tan grave, ya que hay otra decena de servidores de aplicaciones Java EE que se pueden utilizar, y se programa para ellos de la misma manera.

VI. Estabilidad de la Plataforma


Los servidores de aplicaciones Java EE son testeados en una amplia variedad de sistemas operativos y plataformas mientras que, con Spring, los mismos desarrolladores de las aplicaciones son los responsables de probar con diferentes máquinas virtuales, sistemas operativos, releases, parches, etc. Al no ser estándar, Spring no puede asegurarte que funcionará bien en cualquier servidor que lo despliegues.

Cuando una empresa necesita estabilidad, confiabilidad y alta disponibilidad, no le importa pagar por ello. Por eso hay muchos proveedores que venden esa tranquilidad a las empresas, por ejemplo Red Hat, por ejemplo Oracle. Cuando un cliente compra una suscripción para JBoss (una EAP, por ejemplo), no sólo está comprando el testing sobre el servidor en sí, sino también el testing de la integración de todas las tecnologías que provee la plataforma, la armonía entre todas las implementaciones de especificaciones y librerías propias que están allí dentro (JBoss no sólo trae implementaciones de Red Hat, también hay algunas que son de Apache y otras tantas también de Spring). Si una aplicación hecha a medida corre en un JBoss con suscripción y usa alguna librería del mismo servidor, por ejemplo Hibernate (la implementación de JPA) y tiene problemas, puede recibir soporte. Si en cambio nuestra aplicación está basada en Spring y se despliega en un JBoss certificado, como Spring no es parte del servidor, ¿a quién vamos a quejarnos? VMWare nos puede decir que el problema es de Red Hat, y Red Hat puede decirnos que el problema es de VMWare. Probablemente estés probando la integración de las dos tecnologías por primera vez.

VII. Unit Test


Se dice por ahí, por la gran red de redes, que Spring sigue siendo más potente para realizar pruebas unitarias con JUnit, Test NG u otras herramientas. Con Java EE 6 tenemos Arquillian, una librería de JBoss de la cual ya he escrito en este post. Arquillian facilita el Unit Test de EJBs y de servicios que se ejecutan en el mismo servidor de aplicaciones. La filosofía más grande de Arquillian es: no mockeés tus objetos, probalos rápido en su entorno real. Atractivo, ¿no? En lugar de trabajar con Mocks o Dummies, Arquillian permite inyectar EJBs, o Managed Beans de CDI, u otros servicios, dentro de los JUnit Test, empaquetando rápido, desplegando y ejecutando del lado del servidor.

Arquillian no es estándar, pero no me extrañaría que en un futuro cercano sí lo fuera, quizá en Java EE 7 o Java EE 8.

VIII. Ecosistemas


Por último, para ir cerrando con estas comparaciones, quisiera aclarar que Spring es hoy un proyecto modular. Spring no existe por sí solo sino que corre usando en general la plataforma Java EE. Hay módulos de Spring que facilitan el uso de JPA, otros el uso de JMS, etc. Los módulos se pueden usar justamente de forma modular. Podemos tener una aplicación Java EE y usar algún módulo independiente de Spring. Los Spring Beans pueden inyectarse dentro de Managed Beans de JSF, Spring 3 soporta bidireccionalidad con EJBs, un proyecto de JBoss, Snowdrop, permite inyectar beans de Spring en EJBs. O sea que no siempre los dos mundos son antagonistas.

Ecosistema de Spring

Mientras que el ecosistema de Spring son módulos de librerías lanzados por SpringSource, el ecosistema de Java EE está comprendido por especificaciones de la JCP e implementaciones y extensiones de muchos proveedores.

Ecosistema CDI (Java EE 6)

Conclusión


Como se habrán dado cuenta si llegaron hasta aquí, la pelea no es pareja. De un lado del ring está SpringSource, propiedad de VMWare, solito, del otro hay muchos pesos pesados: Oracle, Red Hat, Apache, IBM, entre otros. Por unos años más, Spring va a seguir teniendo la antorcha de la innovación. Java EE, al ser estándar y requerir la aprobación de expertos y seguir un proceso, puede ser más lento a la hora de innovar. Pero Java EE lleva la antorcha del aplomo, la madurez y la libertad de elección. No olviden que casi todas las especificaciones surgieron de meter en una licuadora muchos productos que ya venían funcionando y tomar lo mejor de varios mundos. El ejemplo más claro es CDI, que surgió de las lecciones aprendidas de Spring, Google Guice y Seam. CDI cierra la brecha que todavía separaba a Java EE de Spring. Arquillian es otro peso fuerte, camino a hacerse estándar.

Aunque Spring y Java EE pueden funcionar de forma integrada, el costo de esa integración no es gratis y casi siempre lo paga el programador de aplicaciones cuando las cosas no funcionan. Por otra parte, siempre hay que ser imparciales a la hora de elegir; recordemos que la pelea es desproporcionada, van a encontrar muchos más sitios que defiendan a Java EE que a Spring, sitios de Oracle, de IBM, de Red Hat, etc.

Por otro lado, ni las tecnologías viejas eran tan malas, ni las nuevas son tan buenas. Siempre hay programadores que pueden desarrollar más rápido y mejor con tecnologías viejas que otros con tecnologías nuevas. Esto significa que, casi siempre, quienes hacen la diferencia son los profesionales y no los frameworks. Los frameworks por sí solos no pueden hacer nada.

Sin embargo, el software evoluciona, y la forma de hacer software también. Si no lo hiciera, nuestra disciplina (que todavía está en pañales) se estancaría. Debido a que el desarrollo de software es imperfecto y propenso a errores humanos, es necesario que evolucionemos constantemente, que adoptemos una posición de cambio y mejora continua. ¡No podemos darnos el lujo de quedarnos estancados en nuestras tecnologías de confort!

Hay una afirmación que me atrevo a declamar a los cuatro vientos y es que, hoy en día, no comenzaría una aplicación enterprise Java que no use ninguna de las dos soluciones de Middleware más importantes. Tanto Spring como Java EE son absolutamente necesarios; uno, la otra, o las dos. Y casi diría que si el cliente en el cual tendré que desplegar la aplicación ya cuenta con un servidor de aplicaciones Java EE, seguramente utilizaré CDI y EJB y JPA, más las sub-especificaciones que necesite. No hacerlo, sería como tener una Ferrari para manejar por las callecitas de microcentro.

Referencias


Java SE version history:
http://en.wikipedia.org/wiki/Java_version_history

Java EE version history:
http://en.wikipedia.org/wiki/Java_version_history

Spring Framework:
http://en.wikipedia.org/wiki/Spring_Framework

Entrevista a Rod Johnson, creador de Spring, después de anunciar su partida de VMWare:
http://www.infoq.com/news/2012/07/johnson-leaves-vmware

"Por qué Java EE 6 es mejor que Spring": Post del blog de Arun Grupta de Oracle:
https://blogs.oracle.com/arungupta/entry/why_java_ee_6_is

JBoss Developer Framework:
http://www.jboss.org/jdf/

Ejemplo de TicketMonster: Aplicación Java EE que usa JPA, JAX-RS, HTML5, JSF2, RichFaces 4 y jQuery, Mobile y otras yerbas más:
http://www.jboss.org/jdf/examples/get-started/

Excelentes Diapositivas sobre Java EE 6 V.S. Spring 3, de las cuales robé algunas imágenes:
http://www.slideshare.net/kelapure/java-e-evsspringshootout

Usando JSR-250 @PostConstruct, @PreDestroy y @Resource con Spring y con Java EE:
http://www.captaindebug.com/2011/11/using-jsr-250s-postconstruct-annotation.html

Spring V.S. Guice: Inyección por nombre (objeto) V.S. Inyección por tipo (clase):
http://www.javacodegeeks.com/2012/06/spring-vs-guice-one-critical-difference.html

Otro post a favor de Java EE contra Spring:
http://www.javacodegeeks.com/2012/03/why-i-will-use-java-ee-instead-of.html

Un post inclinando un poco la balanza a favor de Spring:
http://www.javacodegeeks.com/2012/07/java-ee-6-vs-spring-3-java-ee-has.html

Reference Cards de DZone sobre CDI y Spring:
http://refcardz.dzone.com/refcardz/contexts-and-depencency
http://refcardz.dzone.com/refcardz/spring-annotations

Epidata Consulting: On The Rocks: Spring V.S. Java EE
http://www.epidataconsulting.com/tikiwiki/tiki-index.php?page=On+The+Rocks%3A+Spring+V.S.+Java+EE