¿Que esperar y aprender de Java en 2023?

Inicié esta tradición en 2020, que luego tuvo buena recepción en 2021 y 2022, los dejare como jueces del resultado final pero a mi parecer las predicciones han sido bastante certeras. Siendo así, arranco el año con mis predicciones acerca del ecosistema de la Java Virtual Machine en 2023.

En otro orden de noticias dejé el blog abandonado porque dejó de funcionar en la migración MySQL 5 hacia MySQL 8 pero ya está solucionado :D.

Llegará el prime time para reflection y reflectionless con AOT

Una de las mayores novedades en los últimos años ha sido la aparición de GraalVM Native Image. El cual nos permité compilar programas Java hacia ejecutables nativos que inician más rápido y consumen menos memoria, para ello utilizando una máquina virtual nativa mínima denominada Substrate VM.

GraalVM Native utiliza un principio denominado closed world assumption el cual es bastante utilizado en el diseño de compiladores AOT. En pocas palabras y sobresimplificando el concepto, esto significa que al inicio 1- se ejecuta la aplicación en formato JVM (Java normal), 2- se analiza que clases son «alcanzables» desde el punto de partida de la aplicación y 3- únicamente las clases alcanzables se compilan hacia nativo.

Esto en principio es una buena idea PERO, en el caso de Java, hace que medio ecosistema no funcione porque en Java la tendencia ha sido el uso de proxis dinámicos junto a reflection, especialmente en frameworks altamente dependientes de metadatos -i.e. anotaciones- como Spring y Java EE.

Sobresimplificando nuevamente, cuando nosotros utilizamos @Inject en Java EE (o @Autowired en Spring), estamos declarando la dependencia de un componente, pero la implementación real no es creada por nuestro código sino por el framework en tiempo de ejecución, o sea no existe en tiempo de compilación. Lo cual impide que se utilice GraalVM native de forma fácil.

Esto se puede resolver de dos formas:

  1. Generar el código en tiempo de compilación con un procesador (tal y como lo hace Dagger en Android o implementadores de JSR-269 -e.g. Lombok-)
  2. Informar al compilador que la clase va a existir, lo cual es posible en GraalVM pero es demasiado trabajo

Durante la aparición de GraalVM Native, la tendencia fue el uso de la primera técnica, la cual es utilizada por frameworks como Micronaut, Helidon y Quarkus. Pero el elefante en la sala es que el framework más utilizado de Java (Spring) depende enteramente de proxis dinámicos y reflection.

Sin embargo, en 2022 apareció una luz para el ecosistema. En lugar de que cada programador tenga que configurar a mano la compilación con GraalVM Native, Oracle inició un nuevo proyecto denominado Reachability Metadata, en el cual los creadores de frameworks y bibliotecas pueden incluir esa configuración faltante directamente en GraalVM para que GraalVM Native Image funcione sin mayor intervención del usuario. Siendo Spring el que más ha jalado del carro dado el lanzamiento de Spring Native:

Con esto tanto los frameworks reflectionless como los tradicionales tienen ahora la posibilidad de ofrecer Java AOT a sus usuarios y la tendencia es que aumente su uso, especialmente porque Oracle anunció que donara la tecnología de AOT hacia OpenJDK.

Los early adopters se van a subir a la «VirtualTheadneta»

Uno de los problemas más complejos en escalabilidad y computación concurrente es la existencia de recursos blocking, es decir recursos que hacen que una petición quede bloqueada hasta su finalización.

Por ejemplo en el Java clásico, cuando se realiza una consulta hacia un API REST, se efectúa la siguiente secuencia de interacciones:

Usuario (browser) -> Internet -> Servidor (Thread http) -> Thread de procesamiento (-e.g. JAX-RS, CDI-) -> Base de datos

Dado que la Base de datos es un recurso exclusivo (especialmente si se garantiza ACID) el thread http estará bloqueado hasta que la base de datos genere una respuesta y esta sea procesada para su entrega al usuario. Esto en principio no es un problema para pocos clientes porque no debe durar más de unos pocos milisegundos y existirán otros threads que pueden atender a otros usuarios.

Sin embargo, con una mayor cantidad de clientes esta arquitectura no escala porque cada thread de JVM es equivalente a un thread del sistema operativo y estos threads son caros -i.e. consumen memoria RAM y mientras más threads, menor su desempeño dado el scheduler del sistema operativo-.

Este problema a su vez tiene dos soluciones:

  1. Programar con loops de eventos, colas de espera y funciones async -e.g. NodeJS, Vert.x, Netty
  2. Reutilizar los threads del sistema operativo con rutinas autocontenidas y thread virtuales -e.g. Goroutines, Coroutines

Con el pasar de los años la primera solución fue revolucionaria (y de ahí la popularidad de NodeJS) pero con el también nos dimos cuenta de algo obvio: escribir buen código async es muy difícil.

Tan dificil que solo en la JVM aparecieron diversos «entandares» para la escritura de código async, como RxJava, Mutiny, Reactor y CompletableFuture en la JVM.

Lenguajes como JavaScript o C# optaron por impulsar con todo la primera opción con la introducción de Async/Await. Sin embargo el équipo de la JVM decidió no hacerlo y estuvo cocinando (a fuego muy muy lento) una solución dentro de la familia número 2, los Virtual Threads.

De nuevo y sobresimplificando, los virtualthreads son un mecanismo para permitir la creación de miles de threads virtuales sobre unos pocos threads de sistema operativo. Con esto se libera al sistema operativo de la responsabilidad de manipular múltiples threads y mediante un planificador la JVM puede ejecutar, pausar y resumir rutinas autocontenidas -i.e. threads virtuales- sobre threads reales.

Aunque técnicamente los VirtualThreads aun se encuentran en preview. Ya empezaron a aparecer frameworks que toman ventaja de este nuevo concepto como Helidon Nima, así mismo frameworks consolidados como Vert.x o Spring ya compraron su pasaje para subir a la «VirtualThreadneta». Estoy seguro que veremos más en 2023.

La petrificación en Java aumentara su relevancia, especialmente en AWS Lambdas

Desde hace varios años en la comunidad del kernel Linux se busca una habilidad salida de Jurassic Park, poder «petrificar» nuestras aplicaciones con su estado (total o parcial) y poder restaurarlas en un punto en el futuro incluso despues de un reinicio, a esto se le conoce como el proyecto CRIU.

Aunque esta habilidad no es tan obvia, puede ser utilizada en Java para solventar una característica que no es siempre es deseable en entornos como Kubernetes o Serverless: el tiempo de arranque.

Al arrancar una aplicación Java, la JVM realiza distintos análisis y validaciones sobre el bytecode, lo cual es imperceptible con pocas clases pero es un problema conocido con miles de clases, para lo cual se utiliza habitualmente AppCDS (para precalcular estos metadatos) o GraalVM Native como solución.

En esta línea y si se utiliza correctamente podemos distribuir una aplicación «arrancada y petrificada» para que su ejecución sea inmediata, con lo que tampoco tendríamos necesidad de optar por AppCDS o compilación AOT.

Actualmente hay tres grandes usuarios comerciales de este tipo de tecnologías:

  1. IBM con OpenLiberty y su propia JVM que ya cuentan con esta característica, denominada comercialmente InstantOn la cual utiliza CRIU
  2. AWS Lambda con SnapStart la cual utiliza Firecracker Snapshoting
  3. Azul Systems con ReadyNow

Sin embargo como todo en Java, esta característica se encuentra ya en estandarización para poder instrumentar la JVM y que funcione mejor con casos de uso de «petrificación». Este proyecto se conoce como el proyecto CRaC, con lo cual deberiamos ver estos beneficios en más entornos.

IMHO aunque CRaC no esté listo, quien va a hacer popular este tipo de tecnología es AWS, ya que es bien fácil de activar, basta con activar un toogle button en Lambdas y no representa costo adicional.

MicroProfile tendrá menos implementaciones pero más implementadores

En 2023 MicroProfile cumplira su 7mo aniversario, en estos 7 años pasó de ser un mero complemento de Java EE hacia un ecosistema.

En un ecosistema como el de Jakarta EE o MicroProfile hay generalmente tres partes importantes:

  1. La especificación, la cual no son más que APIs y directrices de como debe comportarse una biblioteca
  2. La implementación, o sea una biblioteca Java que cumple con la directrices de la especificación -e.g. SmallRye (Red Hat), Geronimo (Apache)
  3. El distribuidor, un framework o servidor que utiliza una implementación para ofrecer esas características -e.g. WildFly, Quarkus, Payara-

Con el aumento de características, se necesitan más manos para mantener las implementaciones de MicroProfile, entre las cuales recuerdo que existen:

  1. SmallRye de Red Hat
  2. Launcher de Fujitsu
  3. Geronimo de Apache
  4. Payara MicroProfile
  5. KumuluzEE MicroProfile

Recientemente Apache TomEE anunció que dejara momentaneamente Geronimo para utilizar SmallRye, el cual tambien es utilizado por Quarkus, OpenLiberty y Helidon con lo que se perfila como la implementación más popular y presiento que más proyectos la adoptaran.

Empezara la debacle de Java 11, pero Java 8 sigue en nuestros corazones y data centers

Por si aún no lo han notado, muchas versiones de Java 11 empiezan a quedarse sin soporte en 2024, por lo que en este momento iniciar un proyecto con Java 11 es ir demasiado tarde.

Por otra parte también recordemos que el siguiente LTS de Java (Java 21) saldra en septiembre de este año y siendo así Java 11 sera el tercer LTS vivo, por lo que será momento de dejarlo descansar al menos para proyectos nuevos.

¿Y aca que tiene que ver Java 8?. Para mi Java 8 es el Duncan MacLeod de Java. Año tras año me encuentro con clientes que tienen Java 8 desplegado a pesar de que no todos cuentan con soporte.

Cuando despertó Java 8 seguia ahi.

Augusto Monterroso de un universo donde es computin.

Las «emociones» de la JVM se centraran en Amber, Lilliput y Valhalla

Tal y como lo fue en su momento Coin y Lambda, el équipo de la JVM siempre tiene proyectos nuevos en el horizonte que emocionan un poco más a la comunidad Java. Personalmente y dado el estado del ecosistema, apuesto mis emociones a tres proyectos que pueden tener avances significativos:

  • Amber: El siempre eterno proyecto que busca modernizar el lenguaje de programación Java. Nunca nos decepciona.
  • Lilliput: El cual busca reducir el consumo de memoria rediseñando la forma en la cual la JVM manipula la información. Espero al menos una beta significativa
  • Valhalla: El cual busca también mejorar el consumo de memoria en Java mediante el uso de value objects

Regresaran las conferencias de la JVM en Latinoamerica

Creo firmemente que Perú, Colombia y México tienen las condiciones para regresar con su conferencia anual de JVM. De hecho México ya lo hizo.


Así mismo creo que regresará el tour de conferencias de Oracle en formato presencial.

Por último y luego de la experiencia en Colombia, también apuesto por otro TDC en Español, el cual aunque es multi tecnología, tiene bastante ADN Java.

Bienvenido 2023

Si llegaron hasta acá les deseo un 2023 lleno de Java, menos Old GC y más Young GC, pueden seguirme en:


Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *