GraalVM: Aplicaciones nativas AOT para los lenguajes de la JVM

En esta charla conjunta con el Colegio de Ingenieros de Guatemala se presenta una discusión acerca de GraalVM Native como innovación en el ecosistema de la JVM, durante la charla discutimos:

  • ¿Que es GraalVM?
  • GraalVM como VM políglota y reemplazo al JDK clasico
  • Compilación AOT
  • Static Linking
  • Helidon, Quarkus
  • Ventajas y desventajas de GraalVM Native

Como de costumbre los slides se encuentran disponibles en Slideshare:

Ergonomics para la JVM, Docker y Kubernetes

Durante el mes de marzo de 2021 realizamos un meetup en conjunto con la comunidad Cloud Native Guatemala. Nuestro objetivo era realizar una charla en formato «chill & slideless» pero que eventualmente derivó en un workshop bastante nerd gracias a las preguntas de la audiencia. En esta ocasión discutimos:

  • Las diferencias entre el modelo de memoria de Docker y la JVM
  • La importancia del mecanismo cgroups en contenedores
  • Como realizar tunning en versiones antiguas de Java para Docker y Kubernetes
  • ¿Que son y para que sirven las JVM ergonomics?
  • Nuevos frameworks Java para la era Cloud Native
  • GraalVM Native

Acá les comparto el vídeo

Muchas gracias a la comunidad por la invitación.

Desarrollo moderno con DevOps y Cloud Native

En esta charla conjunta con el Colegio de Ingenieros de Guatemala se presenta una discusión acerca del nuevo glosario del ingeniero de software incluyendo:

  • TDD
  • DDD
  • Cloud Native
  • 12 factors
  • DevOps
  • CQRS
  • Event Sourcing

Discutimos que significan todos esos términos y como pueden ayudarlos en su jornada cloud.

Como de costumbre los slides se encuentran disponibles en Slideshare:

Empaquetado de aplicaciones Java con Docker y Kubernetes

Utilizando como base una aplicación Java creada con KukulkanEE, en esta charla conjunta con el Colegio de Ingenieros de Guatemala revisamos los principios básicos de Docker y sus ventajas contra una máquina virtual.

Posteriormente empacamos una aplicación Java en cuatro escenarios revisando distintas consideraciones:

  • Como app desplegada en el Dashboard de un servidor de aplicaciones tradicional ejecutandose en Docker
  • Como app adjunta a una imagen de servidor de aplicaciones tradicional en Docker
  • Como fatjar/uberjar
  • Como microservicio en Docker

Por ultimo demostramos como es viable desplegar una aplicación empacada utilizando Kubernetes a través de Minikube y Oracle Cloud.

Como de costumbre los slides se encuentran disponibles en Slideshare:

¿Que esperar y aprender de Java en 2021?

Siguiendo con un post que publiqué a inicios de 2020, en este año atípico observé algunas tendencias que pueden marcar el ecosistema de Java y como developers deberíamos de considerar al iniciar nuevos proyectos.

Así que tomando mi manto de profeta Java, estas creo que serán las 7 tendencias más importantes durante el año en el ecosistema de Java:

La Java Virtual Machine continuara como motor del Big Data

En el área de Big Data existen algunas herramientas bastante conocidas para ingeniería de datos, tales como:

Lo que estas herramientas tienen en común es que las 3 se ejecutan sobre la JVM. Aunque la mayoría de científicos de datos utilizan Python para crear modelos matemáticos, la recolección y procesamiento para estos modelos siempre suele recaer sobre la JVM, Rust, Go o C++/C.

¿Porqué?. Al igual que en Tensorflow o Pandas con C, Python resulta ser un muy buen lenguaje para prototipos, pero su desempeño es pésimo a estas escalas, por lo que estos sistemas suelen utilizar Python como lenguaje «pegamento» y las cargas de trabajo reales se ejecutan en Go, Rust, JVM o C++.

Adicionalmente, para el siguiente nivel (ciencia de datos) hay nuevos proyectos para ejecutar cargas de trabajo, tales como:

Y a nível de la JVM no olvidemos a Project Panama.

Últimamente recibo la pregunta si Python va a matar a Java, cuando en realidad lo que deberían estarse preguntando es como Python mató a R y R no la vio venir. Debemos recordar que estos son lenguajes utilizados por matemáticos y físicos, no por ingenieros de software obsesionados con DDD, TDD y refactoring.

Java no es un buen «glue languaje» así como tampoco lo es Kotlin o JavaScript, pero es una buena plataforma para hacer el «trabajo sucio».

Creo que el gran perdedor acá fue Scala, ya que Scala si está posicionando como «glue language» pero con tanta abstracción funcional sinceramente se le fue la moto y se encuentra de nuevo en una búsqueda de identidad.

Java 17 impulsara Java 11

Java 17 es el siguiente lanzamiento LTS de Java, el cual debe incluir:

Entre otros. . .

Son tantos los cambios que han habido desde Java 8 que prácticamente estamos hablando de dos Javas distintos. Recordemos que 6 años son una eternidad en computación.

Java 8 seguirá siendo una versión popular, especialmente porqué hay demasiado FUD alrededor de el Java de Oracle (HotSpot) que ya ni vale la pena debatir. En resumen Java es libre y debes pagar por el solo si requieres soporte de Oracle (o terceros) o tu producto lo exige.

¿Porqué Java 11?. El ecosistema enterprise es más conservador que el startupero, y acá Java ofrece una base solida para innovar a través del ecosistema, entonces la gente puede que considere «estable» Java 11 hasta que salga la siguiente versión. Al menos esa es la tendencia.

Spring presentara finalmente una versión AOT

El 2020 fue el año del AOT en el ecosistema Java, el raciocinio es bastante simple, en entornos donde es más importante el arranque y el consumo de memoria vs. el peak performance -e.g. serverless y k8s limitados- los devs optan por GraalVM Native Image, prueba de ello es el aumento de popularidad para Quarkus y MicroProfile.

Spring desde hace algún tiempo está experimentando con la creación de un Spring Native, siendo una de las principales limitantes «reflection». Por eso mismo Red Hat tuvo que inventar un framework nuevo a pesar de que ya tenia uno bastante popular basado en Wildfly/JBoss.

Java (como lenguaje) finalmente sera desplazado por Kotlin en Android

Aunque muchas de las ventajas de versiones modernas de Java podrían traerse a Android, lo cierto es que el Java de Android se siente como programar en Java 7 con uno que otro Lambda.

En el ecosistema Android no se ve claro si en algún momento se soportara Java 17 (o inclusive 8 real), una decisión que parece más política dada la batalla entre Google y Oracle.

Ya es dificil que un dev Android en 2020 inicie un proyecto en Java y sera casi imposible en 2021, aunque el soporte es «oficial», esto también suena a «soporte oficial a un Java petrificado».

Por otro lado siempre debemos recordar que la JVM es un ecosistema, y la JVM sigue siendo la base del ecosistema Android (Android Studio, JDK, Bytecode to Dex).

Este sera un año tumultoso por el cambio desde Javax hacia Jakarta

La versión 9 de Jakarta EE vio la luz a finales de año y entre otras cosas como Jakarta NoSQL y Jakarta MVC, también tiene un cambio muy importante, ya no se utilizara javax sino jakarta en el namespace.

¿Que significa esto para fines practicos?

Si tu código depende de Servlets, JSF, JPA, CDI, Mail, Bean Validation (entro otros), TODOS tus imports ahora deberan ser import jakarta. y no import javax.

Esto basicamente le pega a TODO el ecosistema enterprise de Java, y siendo así las bibliotecas, y servidores de aplicaciones irán adoptando este cambio.

¿Que proyectos se veran afectados?. Entre los más importantes que ya tienen planes o estan iniciandolos puedo mencionar:

Dentro de Eclipse ya se cuenta con una herramienta para facilitar esta migración, denominada Eclipse Transformer, de la cual probablemente hable con más detalle en Q1 de 2021.

Si tienen planes de actualizar sus stacks en Java, considerar este cambio sera obligatorio.

JavaScript aumentara su relevancia en el ecosistema políglota de JVM

Un dato incomodo para la comunidad JS es que el framework más rapido de JavaScript, no se ejecuta sobre Node sino sobre la JVM, especificamente GraalJS. Hemos de considerar que desde hace tiempo el soporte Enterprise de GraalVM también incluye JavaScript, el mundo es políglota sin duda.

Adicionalmente debemos de considerar que aunque Nashorn se eliminó en Java 11, a partir de Java 15 existirá como un modulo optativo, asi que ahora no tenemos uno sino dos caminos para ejecutar JavaScript en la JVM.

Yo particularmente uso ambos y sigo prefiriendo Java, pero no tengo problema con JS y me agrada la evolución de ECMA y sobre todo TypeScript, para mi TypeScript pone el Java en JavaScript.

(Casi) No habrán conferencias Java presenciales en LATAM en 2021

Parte de la crisis del COVID, fue la suspensión de los eventos masivos. Si la lógica impera, los países del primer mundo recibirán antes la vacuna y nosotros iremos a la fila.

Espero uno que otro evento en Brasil y tal vez México, pero aun es muy riesgoso asistir a eventos presenciales. Estoy seguro que regresaran porque la experiencia on-line simplemente no es la misma, tal vez de acá en adelante los eventos híbridos sean la norma.

Un pequeño adiós a CentOS Linux y un hola a sus alternativas

Esta semana nos recibió con la noticia de que CentOS Linux como lo conocemos dejara de existir (¿Cuantos más 2020?). Para los que no están familiarizados con la plataforma, hasta este punto CentOS contaba con dos canales de distribución:

  • CentOS Linux: El «clon» de Red Hat Enterprise Linux, básicamente una recompilación del código estable liberado por Red Hat.
  • CentOS Stream: Una distribución de tipo «rolling» que recibe actualizaciones antes que Red Hat Enterprise Linux.

Aunque el proyecto CentOS continua, CentOS Linux como tal deja de existir en 2021.

¿Porqué es tan importante CentOS? ¿Como sucedió esto?

Hoy por hoy IBM (la dueña de Red Hat) es sin duda la mayor empresa que contribuye al software Open Source.

Atrás quedaron aquellos días donde Linux era hecho exclusivamente por programadores en su tiempo libre y la mayoría de proyectos serios en Linux como Gnome, OpenJDK o incluso JBoss no existirían como los conocemos sin Red Hat, la cual se ganó a pulso su reputación como el mayor proveedor de servicios en Linux.

En esta linea, la propuesta de CentOS siempre fue que pudiéramos tener un sistema operativo empresarial basado en Linux, y que a su vez tuviera la calidad de Red Hat Enterprise Linux. Con lo que aprovechando el código de Red Hat, el proyecto CentOS lo tomaba, eliminaba los sombreros rojos y nos proporcionaba una distribución «gratis» as in «guaro gratis».

Sin embargo algo que no se menciona muy a menudo es que el proyecto durante toda su vida presentó problemas de liquidez y sostenibilidad, por lo que Red Hat lo absorvió en el año 2014.

¿Es IBM y Red Hat el diablo?

En palabras de CNET, el movimiento de software libre ha muerto desde hace bastante tiempo y yo creo que lo ha hecho parcialmente, al menos como lo conociamos. La mayoría de Software Open Source con estas dimensiones hoy en día necesita ser rentable y necesita programadores a tiempo completo.

Sinceramente no me atrevería a criticar a IBM/Red Hat por la decisión, según se leé en Twitter, fue una decisión completa del board y en pro de la rentabilidad del proyecto creo que hasta tardó demasiado, prefiero ver a CentOS vivir en espíritu dentro de otros clones de Red Hat a que les suceda lo de Mozilla.

En esta década finalmente todos nos fuimos a la nube y los entornos on-premise cada vez se implementan menos, si la motivación es el dinero, es la ultima oportunidad de IBM para obtenerlo de instalaciones tradicionales de Linux considerando que todos vamos hacia Kubernetes y nubes cada vez más abstractas. No hay nada de malo en esto.

¿Que alternativas tengo?

Pagarle a Red Hat

La respuesta más simple suele ser la más obvia, si tu negocio depende de CentOS no hay nada moralmente malo en pagarle a Red Hat, de hecho seria un mecanismo real para contribuir al Software Libre y probablemente genera más lineas de código que cualquier otro tipo de aporte, pagarle a IBM es una alternativa real considerando que son uno de los mayores contribuyentes en Gnome o incluso a Java :).

Usar CentOS Stream

El código de Red Hat continuara abierto e incluso si se llega a cerrar, el código ya abierto está garantizado. Seguramente hay un costo asociado a mantener una distribución rolling en producción pero si el costo es demasiado, ¿tal vez le puedes pagar a Red Hat y hasta sea más barato?.

Usar otro clon de Red Hat Enterprise Linux

Aunque CentOS era el clon más popular, nunca ha sido el único y desde hace bastante tiempo (probablemente anticipando esta situación) varias empresas y comunidades crearon sus propios clones, entre los que debo destacar:

Oracle Enterprise Linux

En pocas palabras es un CentOS con el logo y valor agregado de Oracle:

  • Origen: Estados Unidos
  • Costo: Gratis (con opción a soporte de pago)
  • Soporte empresarial: A través de Oracle

Una de sus características interesantes es que ofrece una migración automática desde CentOS.

EulerOS

EulerOS seria como un Oracle Linux de Huawei y varios fabricantes chinos. Dejando a un lado la política, es también un clon de RHEL con su propio calendario de lanzamiento, compatibilidad binaria con Red Hat y un especial énfasis en soporte a ARM64.

  • Origen: China
  • Costo: Gratis (con opción a soporte de pago)
  • Soporte empresarial: A través de Huawei

De forma paralela también cuenta con un proyecto «primo» denominado openEuler con más fabricantes que colaboran en su desarrollo.

SpringDale Linux

Es un clon de RHEL mantenido por la Universidad de Princeton, como dato poco conocido lleva más o menos el mismo tiempo en desarrollo que CentOS, pero le faltó barrio publicitario supongo.

  • Origen: Estados Unidos
  • Costo: Gratis
  • Soporte empresarial: No

Derivados obscuros de Red Hat

Los anteriores probablemente sean los más conocidos, sin embargo existen algunas otras distribuciones basadas en RHEL menos conocidas, por ejemplo:

  • TurboLinux : Recuerdo que era famoso porque el banco más grande de china lo usa. Todo está en Chino en el website asi que hasta aca mi reporte Joaquin
  • BlueOnyx: Enfocada en proveedores de hosting pequeños y medianos
  • NethServer : Enfocado en pequeñas y medianas empresas

Forks del futuro

Agregado el 11 de diciembre.

Al menos dos proyectos han anunciado que crearan equivalentes a CentOS, técnicamente aun no son alternativas porque no existen ISO o repositorios, pero hay que echarles un ojo:

  • Rocky Linux: Es un fork del creador original de CentOS, el cual en sus propias palabras aun no asimila el cambio en CentOS.
  • Cloud Linux: Cloud Linux es una empresa dedicada a crear soluciones basadas en Linux para hosting y empresas. Aunque tecnicamente ya tienen su propia distribución, el cambio en centos los ha obligado a tener un fork completo

Salir del ecosistema de RHEL

Como ecosistemas alternativos Linux, tanto Debian, Ubuntu y SUSE tienen bastantes años en el mercado y ofrecen soluciones robustas de forma gratuita con opciones de pago.

Por supuesto tendremos que aprender un nuevo userland de herramientas, pero es una pequeña inversión si consideramos que todo esto pasó porque nunca donamos al proyecto CentOS y es uno más de los que 2020 se llevó.

Livecoding – Patrones de Microservicios con Java, Eclipse MicroProfile y Oracle Helidon

En esta sesión de livecoding exploramos el estado actual de los patrones de diseño de microservicios y las opciones que existen para Java en 2020.

Posteriomente utilizando Oracle Helidon exploramos algunos de estos patrones y su implementación con MicroProfile.


Lenguajes de programación de la JVM en 2020

En esta serie de videos junto a la audiencia del Congreso de Estudiantes de Ingeniería 2020 discutimos varios conceptos clásicos de lenguajes de programación.

Primero hablamos un poco de los distintos tipos de lenguajes de programación que existen:

Posteriormente tratamos de trazar una diferencia entre lenguajes de programación y plataformas de programación:

Por ultimo repasamos el estado actual (2020) de los lenguajes de programación de la Java Virtual Machine y respondemos algunas preguntas de la audiencia:

Consideraciones generales al actualizar proyectos Java empresariales desde Java 8 hacia Java 11

En este megapost mi objetivo es consolidar todas las dificultades (y soluciones) que he enfrentado al actualizar proyectos Java EE y/o MicroProfile desde Java 8 hacia Java 11. Es un hecho que Java 11 trajo consigo muchas características que cambiaron el ecosistema de Java y podrían ser problemáticas durante nuestras actualizaciones.

Aunque mi enfoque es Java empresarial, esta información puede servir de referencia para actualizaciones con otros frameworks/runtimes.

Este ha sido el post más largo que escribo en varios años por lo que agradecería que lo compartieran 😬.

¿Es posible actualizar proyectos Java EE/MicroProfile desde Java 8 hacia Java 11?

Si. En anteriores ocasiones he actualizado junto a mi equipo dos proyectos que considero épicos (más de 3 años de desarrollo) con las siguientes métricas:

Proyecto 1: Un sistema de gestión empresarial (MIS)

Nabenik MIS
  • Tiempo invertido en la migración: 1 semana
  • Módulos: 9 EJB, 1 WAR, 1 EAR
  • Clases: 671
  • Líneas de código: 39480
  • Inicio del proyecto: 2014
  • Plataforma original: Java 7, Wildfly 8, Java EE 7
  • Plataforma actual: Java 11, Wildfly 17, Jakarta EE 8, MicroProfile 3.0
  • Cliente web: AngularJS

Proyecto 2: Un sistema de venta y geocerca

Medmigo REP
  • Tiempo invertido en la migración: 3 semanas (por varios errores en upstream)
  • Módulos: 5 WAR/Microservicios
  • Clases: 348
  • Líneas de código: 17160
  • Inicio del proyecto: 2017
  • Plataforma original: Java 8, Glassfish 4, Java EE 7
  • Plataforma actual: Java 11, Payara 5, Jakarta EE 8, MicroProfile 3.2
  • Cliente web: Angular

¿Porqué debería actualizar hacia Java 11?

Como todo en informática la respuesta es: depende. Los motivos por los cuales he decidido actualizar suelen ser los siguientes:

  1. Reducir la superficie de ataque al contar con dependencias actualizadas, especialmente Open Source
  2. Reducir el débito técnico y preparar mis proyectos para un Java más dinámico
  3. Aprovechar las mejoras de desempeño en las nuevas versiones de Java
  4. Aprovechar las nuevas características de Java como lenguaje
  5. Dormir bíen gracias a esas ventajas técnicas

¿Porqué es dificil actualizar un proyecto Java EE desde Java 8 hacia Java 11?

De acuerdo a mi experiencia y en orden de prioridades, por los siguientes motivos:

Cambios en la frecuencia de lanzamiento de Java

Actualmente tenemos dos grandes ramas de máquinas virtuales de Java

  • Java LTS: El cual está pensado para soporte de largo plazo (3 años), siendo la última versión Java 11
  • Java current: El cual está pensado para tener ciclos de vida cortos (6 meses) y recibir características de forma rápida, el cual al momento de escribir este articulo es Java 15

El raciocinio detrás de este cambio es que Java como plataforma necesitaba dinamismo y es más fácil recibir pequeñas características cada seis meses, con lo cual estoy totalmente de acuerdo.

Sin embargo es un hecho que la mayoría de frameworks empresariales están enfocando sus runtimes hacia Java 11 para estar en linea con ciclos de soporte de la JVM más largos.

El uso de módulos internos en la JVM

El culpable de todas mis angustias

Errata: Actualicé y simplifiqué esta discusión siguiendo comentarios en Reddit

Java 9 introdujo cambios en clases internas que no estaban diseñadas para su uso fuera de JVM, evitando / rompiendo la funcionalidad de bibliotecas populares que hicieron uso de estos componentes internos para ganar velocidad y rendimiento, por ejemplo Hibernate, ASM o Hazelcast.

Por lo tanto y para evitarlo en el futuro, las API internas en JDK 9 se diseñaron de tal forma que de aca en adelante se busca que sean inaccesibles. De momento por defecto son inaccesibles en tiempo de compilación (pero accesibles con –add-export) y accesibles en tiempo de ejecución siempre y cuando la biblioteca ya exista en JDK 8. Con la salvedad de que en un futuro pueden ser inaccesibles por completo.

A largo plazo este cambio reducirá los costos soportados por los mantenedores del propio JDK y por los mantenedores de bibliotecas y aplicaciones que intencionalmente o no, hicieron uso de estas API internas.

Finalmente, durante la introducción de JEP-260, las API internas se clasificaron como críticas y no críticas, por lo que las API internas críticas para las que se introducen reemplazos en JDK 9 están obsoletas en JDK 9 y se encapsularán o eliminarán en una versión futura.

Esto para fines prácticos representa peligro en nuestros proyectos si:

  • El proyecto se compila contra dependencias pre Java 9 que a su vez dependen de componentes internos críticos
  • El proyecto incluye dependencias pre Java 9 que usan componentes internos críticos
  • La aplicación se ejecuta en un servidor de aplicaciones que incluye dependencias que dependen de componentes internos críticos

En cualquiera de estas tres situaciones existe la probabilidad de que el proyecto no funcione sin actualizar dependencias, lo cual puede a su vez revelar incompatibilidades porque el API de alguna dependencia/biblioteca ha cambiado entre versiones -e.g. Flyway-.

Eliminación de CORBA y los módulos de Java EE en el JDK

Otro cambio importante en Java 9 fue que varios modulos de Java EE y CORBA fueron marcados como «Deprecated» para ser eliminados en futuras versiones de OpenJDK.

A partir de Java 11 este cambio se hizo realidad y varios módulos de OpenJDK que eran incluidos para soportar Java EE fueron eliminados de OpenJDK, con esto, los siguientes paquetes ya no son parte de OpenJDK:

  • java.xml.ws (JAX-WS) para creación de servicios SOAP
  • java.xml.bind (JAXB) para procesamiento de XML
  • java.activation (JAF)
  • java.xml.ws.annotation (Common Annotations)
  • java.corba (CORBA)
  • java.transaction (JTA)
  • java.se.ee (Módulo agregador)
  • jdk.xml.ws (Herramientas para JAX-WS)
  • jdk.xml.bind (Herramientas para JAXB)

Para fines prácticos esto significó que ya no es posible generar y ejecutar clientes SOAP (o CORBA) directamente desde la JDK, y ahora es necesario agregar los proyectos upstream como en cualquier otra biblioteca.

El raciocinio detrás de este cambio fue que los módulos eran incluidos como una conveniencia para soportar la «nueva era» de Web Services en los 90s, pero que al final del día eran mantenidos por proyectos Upstream de forma independiente y los publicaban en Maven Central.

Independencia de JavaFX en OpenJDK

De la misma forma que los módulos de Java EE, en Java 11 el módulo de JavaFX fue removido y desacoplado de la distribución de Java Developer Kit, luego de 10 años de desarrollo.

Al igual que Java EE, el modulo sobrevive fuera de la distribución estándar del Java Developer Kit, y de hecho existe actualmente un proyecto independiente mantenido por la comunidad, además de empresas como Gluon, Azul Systems y Oracle -i.e. OpenJFX– para que JavaFX evolucione a su propio ritmo.

Entornos de desarrollo integrado y servidores de aplicaciones

Al igual que lo que pasó con las bibliotecas, los IDEs tuvieron que prepararse para la transición hacia Java modular, al menos en tres niveles:

  • El IDE como programa Java debe ser compatible con JPMS
  • El IDE debe soportar Java 9, 10, 11 … como lenguaje de programación
  • El IDE es la base de un ecosistema de plugins que TAMBIÉN debe actualizarse para soportar JPMS
  • Estos plugins a su vez deben ser compatibles con entornos de ejecución (servidores) compatibles con JPMS

Con esto tanto Netbeans como IntelliJ y Eclipse se actualizaron paulatinamente hacia Java 9 y superiores, PERO no podían dar garantías que todo el ecosistema estuviera actualizado.

Acá una situación común es que luego de instalar Java 11 y un IDE como Eclipse con soporte para Java 11, nuestro proyecto aun fuera incompatible porqué:

  • Utilizábamos la versión un plugin -e.g. Glassfish- que aun NO era compatible con JPMS
  • Utilizabamos un application server -e.g. Glassfish- que en la época aun NO era compatible con JPMS

Ok, ¿Como actualizo proyectos?

Dadas las situaciones anteriores, actualizar un proyecto desde Java 8 (o 7) es una tarea que requiere distintas verificaciones, por lo cual suelo una estrategia de 8 pasos:

  1. Verificar la compatibilidad del entorno de ejecución
  2. Verificar que versión de Java necesito
  3. Configurar nuestro entorno de desarrollo para soportar múltiples JVM
  4. Verificar el IDE
  5. Actualizar y configurar Maven
  6. Actualizar las dependencias del proyecto
  7. Incluir manualmente las dependencias de Java/Jakarta EE
  8. Ejecutar múltiples JVM en producción

1. Verificar el entorno de ejecución

Mike Loukides de O’Reilly considera que existen dos tipos de programadores y eso se hace evidente en Java. Por un lado están los programadores que crean los frameworks, bibliotecas y rutinas de bajo nivel y por otro lado están los programadores que utilizan estas herramientas para crear experiencias, productos y servicios.

Java Empresarial se encuentra en el segundo grupo, donde descansamos sobre hombros de gigantes y por este mismo motivo antes de intentar planificar cualquier actualización debemos de verificar que nuestro runtime/herramienta/servidor sea compatible (al menos) con Java 11. Afortunadamente el ecosistema de Java 11 ya es bastante maduro y varios proyectos fundamentales de Java han realizado la transición exitosamente, incluyendo:

De hecho en bastante improbable que una biblioteca aun no soporte Java 11, pero si ese fuera el caso debemos indagar con el fabricante/comunidad si el proyecto no ha muerto, sus planes para el futuro o pensar en contribuir con el desarrollo para que esto suceda.

2. Verificar que versión de Java necesito

Una segunda limitante no técnica que podríamos enfrentar es que para una determinada versión de un producto necesitamos un Java Developer Kit en particular, lo que se conoce como el proceso de certificación.

En jerga informática solemos decir que un paquete de software esta certificado cuando el fabricante brinda garantías de que el mismo funcionara de forma correcta bajo ciertas condiciones/entorno. Dicho de otra forma puede que el software ya funcione bien bajo Java 11 pero es necesario tener la garantía legal y de soporte para proceder con una actualización.

Un caso ejemplo es WebLogic, que necesita por contrato una compilación especifica de OpenJDK para ejecutarse (Oracle Hotspot) y una versión mínima para aplicar a contratos de soporte.

Otro podría ser SAP el cual requiere que se utilice la compilación de OpenJDK soportada por SAP (SAP JVM) para ejecutar sus productos.

3. Soportar múltiples JVMs en desarrollo

Al ser la actualización un proceso experimental de tipo prueba y error, una buena idea es soportar multiples JVMs en desarrollo, y para esto existen diversas herramientas:

SDKMan

Disponible para entornos UNIX (Linux, Mac, Cygwin, BSD) permite la instalación de varias herramientas útiles en el ecosistema Java como Maven, Gradle, Leiningen, Micronaut y diversas compilaciones de OpenJDK -e.g. AdoptOpenJDK, Amazon Correto, Oracle GraalVM-.

jEnv

También disponible para entornos UNIX (Linux, Mac, Cygwin, BSD) es un script de configuración de entorno. Tiene la particularidad que permite configurar la JVM a nivel de sistema, red y usuario. Esta es mi elección personal ya que permite gestionar JVMs instaladas bajo diversos formatos.

En el caso de Windows la forma más fácil que he encontrado es automatizar la tarea con archivos .bat. Pero para serles franco no uso Windows para trabajo/desarrollo desde el año 2006. Agradecería cualquier comentario al respecto.

4. Verificar el IDE

Recordemos que un IDE se compone de 3 partes

  1. La plataforma
  2. El soporte al lenguaje de programación
  3. Las extensiones para soportar herramientas especificas

Tanto Eclipse, NetBeans, IntelliJ IDEA y Visual Studio Code tienen versiones compatibles con Java 11 por lo que la tarea es actualizar hacia estas versiones.

Luego de la actualizacion y la ejecución sobre Java 11, debemos verificar si nuestras extensiones funcionan correctamente. Especialmente si se utilizan conectores hacia servidores de aplicaciones.

5. Actualizar y configurar Maven

Aunque existen otros sistemas como Ant, Gradle o Bazel, en mi opinión Maven sigue siendo el estándar de facto en la gestión de la configuración y dependencias de proyectos con Java.

Además de actualizar nuestra instalación de Maven, debemos tomar en cuenta que Maven como proyecto funciona a través de extensiones, las cuales se pueden forzar arbitrariamente. Por tal motivo debemos de estar seguros cual es la versión de plugins que utilizaremos en cada proyecto a compilar. En esta línea Maven cuenta con un POM (listado de dependencias) con versiones predeterminadas que deberíamos incluir en nuestros proyectos.

Una forma rápida de verificar las extensiones es utilizar versions-maven-plugin

<plugin>
      <groupId>org.codehaus.mojo</groupId>
      <artifactId>versions-maven-plugin</artifactId>
      <version>2.8.1</version>
</plugin>

El cual tiene un «goal» especifico para mostrarnos las versiones disponibles de los plugins de Maven

mvn versions:display-plugin-updates

Como regla general debemos utilizar las últimas versiones estables para no tener problemas con Java 11.

Así mismo debemos de configurar Maven para que sea capaz de compilar código nivel 11, lo cual se hace generalmente en dos puntos del archivo de configuración.

En la propiedad maven.compiler.x:

<properties>
        ...
    <maven.compiler.source>11</maven.compiler.source>
    <maven.compiler.target>11</maven.compiler.target>
</properties>

En maven-compiler-plugin si lo tenemos configurado de forma explitica:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-compiler-plugin</artifactId>
    <version>3.8.0</version>
    <configuration>
        <release>11</release>
    </configuration>
</plugin>

Como medida de compatibilidad el équipo de la JVM disponibiliza desde Java 9 la bandera illegal-access para permitir acceso reflectivo a modulos internos de la JVM, esto quiebra la teoría de separación por modulos de JPMS pero permiten aumentar la compatibilidad de algunos paquetes con histórico acceso a clases internas.

En ocasiones necesitaremos invocar las extensiones con esta bandera, por en surefire y failsafe los cuales son utilizados tradicionalmente en Java EE para invocar la ejecución servidores de aplicaciones que necesitan este argumento:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-surefire-plugin</artifactId>
    <version>2.22.0</version>
    <configuration>
        <argLine>
            --illegal-access=permit
        </argLine>
    </configuration>
</plugin>
<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-failsafe-plugin</artifactId>
    <version>2.22.0</version>
    <configuration>
        <argLine>
            --illegal-access=permit
        </argLine>
    </configuration>
</plugin>

6. Actualizar las dependencias de mi proyecto

Como se ha mencionado en la parte teórica del proyecto, es necesario actualizar todas las dependencias del proyecto hacia su última versión estable y/o compatible con Java 11.

Tomando en cuenta que a veces el salto mayor de dependencia -e.g. Flyway 4 hacia Flyway 6- implica un cambio en el API del proyecto, acá se debe considerar que podría ser necesario un refactoring de nuestro código, para ser sinceros esta es la parte que podría requerir más tiempo y lo que detiene a la mayoría de actualizaciones.

Un buen paso inicial es verificar las ultimas versiones estables utilizando también versions-maven-plugin:

mvn versions:display-dependency-updates

La salida nos informara que dependencias tienen nuevas actualizaciones:

Al momento de actualizar también debemos estar seguros que las dependencias son compatibles con mi entorno de ejecución y podría afirmar que esta es una fortaleza poco conocida de Java EE, al ser Java EE una dependencia única los servidores de aplicaciones/microframeworks se encargan de resolver conflictos de dependencias y suele ser una experiencia bastante fácil frente a abordajes «hazlo tu mismo».

7. Agregar los paquetes faltantes de Java EE (y tal vez migrar hacia Jakarta EE)

Aunque en proyectos modernos (REST) esto probablemente no sea un problema, en proyectos basados en Web Service SOAP o en bibliotecas muy especificas sera necesario que agreguemos las dependencias que fueron removidas de OpenJDK.

En el mundo Java EE por cada paquete suele haber dos dependencias:

  • El API o interfaz de programación
  • La implementación de referencia con el código del API

En este punto vale la pena evaluar tambien si no es buena idea realizar el cambio haciar Jakarta EE.

La historia corta es que en 2017 Oracle liberó la mayoria de propiedad intelectual sobre Java EE para que la especificación reciba mayores contribuciones de la comunidad, naciendo así el proyecto Jakarta EE bajo la fundación Eclipse.

Para fines prácticos Jakarta EE 8 tiene las mismas capacidades técnicas de Java EE 8 y los mismos paquetes. Actualmente la mayoria de servidores de aplicaciones modernos y Tomcat ya son compatibles con Java EE 8(WebLogic lo tiene considerado para el futuro).

Si deseamos hacer actualización y nuestro entorno de ejecución la soporta, debemos de reemplazar la dependencia de Java EE 8:

<dependency>
    <groupId>javax</groupId>
    <artifactId>javaee-api</artifactId>
    <version>8.0.1</version>
    <scope>provided</scope>
</dependency>

Por:

<dependency>
    <groupId>jakarta.platform</groupId>
    <artifactId>jakarta.jakartaee-api</artifactId>
    <version>8.0.0</version>
    <scope>provided</scope>
</dependency>

Asi mismo, puede que necesitemos las siguientes dependencias para compilar nuestro proyecto Java EE que originalmente eran parte de OpenJDK:

Java Beans Activation

Java EE

<dependency>
    <groupId>javax.activation</groupId>
    <artifactId>javax.activation-api</artifactId>
    <version>1.2.0</version>
</dependency>

Jakarta EE

<dependency>
    <groupId>jakarta.activation</groupId>
    <artifactId>jakarta.activation-api</artifactId>
    <version>1.2.2</version>
</dependency>

JAXB (Java XML Binding)

Java EE

<dependency>
    <groupId>javax.xml.bind</groupId>
    <artifactId>jaxb-api</artifactId>
    <version>2.3.1</version>
</dependency>

Jakarta EE

<dependency>
    <groupId>jakarta.xml.bind</groupId>
    <artifactId>jakarta.xml.bind-api</artifactId>
    <version>2.3.3</version>
</dependency>

Implementación

<dependency>
    <groupId>org.glassfish.jaxb</groupId>
    <artifactId>jaxb-runtime</artifactId>
    <version>2.3.3</version>
</dependency>

JAX-WS

Java EE

<dependency>
    <groupId>javax.xml.ws</groupId>
    <artifactId>jaxws-api</artifactId>
    <version>2.3.1</version>
</dependency>

Jakarta EE

<dependency>
    <groupId>jakarta.xml.ws</groupId>
    <artifactId>jakarta.xml.ws-api</artifactId>
    <version>2.3.3</version>
</dependency>

Implementación (runtime)

<dependency>
    <groupId>com.sun.xml.ws</groupId>
    <artifactId>jaxws-rt</artifactId>
    <version>2.3.3</version>
</dependency>

Implementación (standalone)

<dependency>
    <groupId>com.sun.xml.ws</groupId>
    <artifactId>jaxws-ri</artifactId>
    <version>2.3.2-1</version>
    <type>pom</type>
</dependency>

Java Annotation

Java EE

<dependency>
    <groupId>javax.annotation</groupId>
    <artifactId>javax.annotation-api</artifactId>
    <version>1.3.2</version>
</dependency>

Jakarta EE

<dependency>
    <groupId>jakarta.annotation</groupId>
    <artifactId>jakarta.annotation-api</artifactId>
    <version>1.3.5</version>
</dependency>

Java Transaction

Java EE

<dependency>
    <groupId>javax.transaction</groupId>
    <artifactId>javax.transaction-api</artifactId>
    <version>1.3</version>
</dependency>

Jakarta EE

<dependency>
    <groupId>jakarta.transaction</groupId>
    <artifactId>jakarta.transaction-api</artifactId>
    <version>1.3.3</version>
</dependency>

CORBA

En el caso de CORBA, existe el proyecto ORB dentro de Eclipse pero sinceramente es terreno poco explorado para mi. Solo me queda desearles buena suerte.

8. Ejecutar multiples JVMs en producción

Si todo compila, se ejecuta, los tests de regresión funcionan, podriamos decir que estamos ante una migración exitosa.

Sin embargo si nuestra empresa es una «Java Shop» es probable que tengamos varios proyectos con diversos runtimes y versiones de Java y no podamos actualizar todos al mismo tiempo por lo que suele ser una buena idea ejecutar servidores cono diversas versiones de Java instaladas.

La buena noticia es que la mayoria de distribuciones Linux ofrecen mecanismos para instalar/ejecutar diferentes versiones de JDK directamente desde el repositorio, las cuales funcionan bien una al lado de la otra.

Por ejemplo Oracle Linux ofrece OpenJDK 8, 11:

Al utilizar Oracle Hotspot mediante versiones en RPM obtendremos el mismo efecto, ya que sistemas basados en YUM suelen identificarlo como una alternativa Java:

En el caso que necesitemos un sistema «limpio» tambien es una buena idea distribuir nuestra aplicacion como un contenedor de docker, sabiendo que la mayoria de imagenes de JDK se encuentran disponibles en Docker Hub:

En el caso de Windows, mi recomendación es utilizar Docker ya que el mecanismo para tener diferentes JVM directamente en el sistema es el mismo que en desarrollo, usar archivos .bat y esperar lo mejor.

Programación en vivo: Creando un microservicio con Kotlin, Jakarta EE, MicroProfile y Payara Micro

En esta sesión de LiveCoding creamos desde 0 un microservicio con Kotlin que incluye configuración con Maven, una API REST con JAX-RS, Inyección de dependencias con EJB/CDI y persistencia hacia base de datos vía JPA utilizando H2.

Los slides se encuentran disponibles en Slideshare