Autentia

Blog

Greach 2019, asistimos a la octava edición

Los pasados días 28 al 30 de marzo estuve en la nueva edición de Greach, un evento históricamente centrado en el ecosistema Groovy que, por primera vez, ampliaba su foco abarcando al resto de lenguajes de la JVM y resaltando su uso en el ámbito de los microservicios y las aplicaciones móviles.

Es el primer año que asisto y debo reconocer que, pese a contar con tan solo dos tracks, no hubo ninguna charla a la que entrase “por rellenar el hueco”. Tengo que destacar gratamente la calidad técnica de las ponencias, no sólo en el contenido, sino también en la elaboración de las slides y en la exposición oral –aspectos igualmente importantes–.

A continuación voy a resumir lo aprendido en algunas charlas a las que asistí, para que sirva de aperitivo antes de que salgan los vídeos (porque están grabadas y serán publicadas próximamente en nuestro canal de youtube).

Keynote

Andrés  Almiray (@aalmiray) nos relata, a través de un paseo histórico, la evolución de los frameworks en Java.

Comienza por un rígido Struts, que supuso un punto de inicio en la separación de responsabilidades dentro del Modelo Vista Controlador. Continúa con Grails y Griffon, explicando cómo nacieron influenciados por Rails y su principio de convención sobre configuración. Más tarde, el rápido crecimiento de los requisitos de hardware supuso la llegada de los centros de datos en la nube, que llevó al nacimiento de los microservicios y los contenedores; y con ellos, los llamados microframeworks: desde Ratpack, pasando por MicroProfile, hasta llegar a los modernos Micronaut y Quarkus (que nacen enfocados a aprovechar todo el potencial de GraalVM y su compilación Ahead-Of-Time).

Sin embargo, pese a toda esta evolución, a día de hoy el mercado de los microservicios está liderado por Go –en parte debido a su reducido tamaño– y aún hay mucho camino que recorrer. Es crucial una mayor implicación de la comunidad en estos proyectos –la mayoría son Open Source–, no necesariamente programando, sino aportando ideas o proporcionando feedback.

Micronaut State of Union

Graeme Rocher (@graemerocher), el creador de Micronaut, nos cuenta cómo este framework nació como respuesta a los principales problemas de Java en los microservicios –debidos, sobre todo, a su gran tamaño en memoria–.

Según nos explica, todo framework basado en reflexión y procesamiento de anotaciones en tiempo de ejecución se vuelve pesado. Por eso la próxima versión versión 1.1. de Micronaut viene con una mejor integración con GraalVM, al eliminar la carga dinámica de clases y proporcionar un mecanismo de reflexión en tiempo de compilación utilizable incluso sobre clases de terceros. Otro novedad destacable de esta versión es la modularidad, con ciclos de entrega independientes; tratándose de un framework orientado a microservicios, hacen bien en predicar con el ejemplo. Se añaden también nuevas integraciones con librerías de terceros, como RabbitMQ, GraphQL, GRPC, Amazon AWS y Google Cloud Platform.

Tras unos prácticos ejemplos de uso de la nueva clase BeanIntrospector y de Programación Orientada a Aspectos con @Introduction y @Around, Graeme nos desveló el prometedor roadmap de Micronaut, que incluye integración con OAuth 2 y OpenID, validación de Beans sin reflexión, un toolkit de acceso a datos inspirado en GORM y soporte para JMS y para las corrutinas de Kotlin.

Spock vs. JUnit 5 – Clash of the Titans

Marcin Zajaczkowski Greach19

Al potente framework de testing Spock le ha salido hace poco un duro competidor: JUnit 5. En esta charla, Marcin Zajączkowski (@SolidSoftBlog) hace una extensa comparativa entre las dos librerías, analizándolas bajo diferentes prismas, asumiendo en ambos casos que venimos de Junit 4. El veredicto es, como en tantas ocasiones, que depende de lo que más valoremos.

Junit 5 destacó en la sencillez de desarrollo, la curva de aprendizaje, la integración con los IDEs más usados –a Spock se le resisten ciertas refactorizaciones– y la facilidad de migración (desde la versión 4). Por otra parte, Spock sobresalió en la estructura de los tests, el manejo de excepciones, la ejecución condicional y, de manera arrolladora, en los tests parametrizados ( debido a la riqueza de su presentación en formato de tabla). En el mocking quedaron empatados, aunque si valoramos que Spock no requiere ninguna librería externa, le podríamos conceder una ajustada victoria.

Cabe destacar que no hubo ningún aspecto donde el framework perdedor no se desenvolviera dignamente.

Android Dev Tools & Workflows

Saúl Molinero (@_saulmm) hace una extensa recopilación de herramientas y plugins que le ayudan a lo largo del ciclo de desarrollo de aplicaciones Android.

En primer lugar tenemos Pidcat, una envoltura del famoso visor de logs Logcat con configuración de color y filtrado por paquetería. Scrcpy, un completo controlador remoto del móvil sobre el que estemos desarrollando, con simulación de clicks, visionado de pantalla e instalación de APKs con simplemente arrastrar. Flipper, de Facebook es una potente aplicación de debugging que incorpora inspección de red, de excepciones y detección de memory leaks. Existe una versión anterior, llamada Stetho, que recomienda seguir usando por su completo inspector de base de datos (aún no incluido en Flipper).

En este repaso no puede faltar el propio IDE Android Studio, que incorpora de serie muchas herramientas de  inspección (CPU, red, memoria, GPU, layouts). Otra característica incluída en el IDE es Emulator Snapsots, que permite guardar configuraciones determinadas de la aplicación (propiedades, bases de datos, etc.) para poder ejecutarlas en cualquier momento.

Por otra parte, para probar nuestra aplicación en diferentes dispositivos, tenemos Firebase Test Lab, que nos permite configurar una inmensa variedad de móviles reales alojados en un centro de datos de Google.

Y como no todo es testing y análisis de errores, Saúl nos muestra también unas cuantas herramientas útiles durante otras fases del desarrollo. Como Detekt, para realizar análisis estático de código en Kotlin. Bitrise, que lleva la integración continua a las aplicaciones móviles. En la gestión del flujo de trabajo usa Github, potenciado con utilidades como Probot, para automatizar tareas relacionadas con las pull requests, las etiquetas para clasificar issues, o el plugin Open in Github de IntelliJ.

He de confesar que, dada mi poca experiencia con Android –la última vez que trasteé, no se programaba en Kotlin–, me sentí como un niño ante un catálogo de juguetes. Me llevo a casa muchas ideas sobre las que investigar.

Understanding Coroutines

Antonio Leiva (@lime_cl) imparte toda una master class sobre las corrutinas en Kotlin. El que haya trabajado con asincronía sabrá que complica bastante el código. Las corrutinas gestionan eficientemente toda la gestión de hilos de manera transparente al desarrollador, que puede seguir trabajando con código secuencial –en apariencia–. De todos modos, aunque parezca sencillo al principio, es importante entender cómo funcionan y qué posibilidades presentan, para poder sacarles el máximo partido y no acabar pegándonos un tiro en el pie.

A lo largo de la charla, Antonio va desarrollando conceptos como funciones suspendidas, contextos, dispatchers, builders (modos de lanzamiento) y scopes –que nos permiten implementar lo que se conoce como concurrencia estructurada–.

Aprendí muchas cosas nuevas y me apunté otras tantas como deberes para casa. Puedo decir que las corrutinas me han sorprendido gratamente, por la manera en la que ayudan a entender dos términos frecuentemente confundidos: concurrencia y paralelismo.

GraalVM with Groovy & Kotlin

Greach-Alberto-Avila

Alberto de Ávila (@alberto_deavila) nos sumerge en los entresijos de GraalVM a lo largo de una charla bien estructurada, cuyo objetivo es explicar cómo se amoldan los lenguajes Kotlin y Groovy dentro de esta nueva tecnología. Entre los puntos fuertes de GraalVM destaco los dos que considero más revolucionarios:

  • Por una parte tenemos la interoperabilidad con otros lenguajes, a través del framework Truffle. Esto nos permite emplear el más apropiado para cada tarea, gestionando toda la aplicación con las mismas herramientas (un sólo depurador, un sólo monitor de memoria, etc.) . Es el concepto de los microservicios pero, en este caso, dentro de un solo ejecutable.
  • Por otra parte, la funcionalidad de la que todo el mundo habla: la generación de imágenes nativas, es decir, tener toda la aplicación –máquina virtual incluída– compilada en código máquina gracias al framework Substrate VM. Esto trae consigo notables mejoras en el consumo de memoria y el tiempo de arranque, pero conlleva unas restricciones que, a veces, chocan con la manera en que Groovy y Kotlin funcionan por dentro. Al adaptar aplicaciones para esta compilación, hay que tener especial cuidado con la reflexión. De todos modos, no está totalmente prohibida; se puede incluir una “ayuda” en forma de json indicando las clases que requieren inspección. A parte de eso, hay complicaciones con la generación dinámica de código, y es en este punto donde Kotlin le gana la partida a Groovy; mientras que el primero tiene casi todas sus características soportadas, en aplicaciones con Groovy habría que reescribir las partes que usen metaprogramación y closures –probablemente, una porción importante de todo el código–. En ambos casos, Micronaut puede simplificar el proceso; con restricciones, en el caso de Groovy.

La charla acaba con la previsión de un prometedor futuro para GraalVM, presentando un mayor rendimiento y soportando más lenguajes y más plataformas.

Accelerating CI

Felipe Fernández (@felipefzdz), desde su experiencia trabajando con Teamcity, nos cuenta los principales problemas que suelen aparecer en los procesos de integración continua y de qué manera se pueden solventar:

  • Pipelines lentos. A alto nivel, un pipeline está formado por una serie de pasos, compuestos de: entradas, procesamiento (tareas de Maven o Gradle) y salidas. Hay dos maneras de agilizar este proceso: evitar trabajo innecesario, empleando cachés de builds; y paralelizar pasos independientes, para lo que puede ser necesario descomponer las builds grandes –sin que llegue a ser peor el remedio que la enfermedad–.
  • Mantenimiento manual. La configuración desde una consola de administración web no es una buena solución a largo plazo. Toda la comodidad inicial que nos proporciona la interfaz gráfica se torna en quebraderos de cabeza a la hora de deshacer cambios; y la cosa empeora si queremos migrar todo el sistema a otra plataforma.  La solución que propone Felipe es tener toda la configuración en forma de código, ya sea con el DSL de Kotlin para Teamcity, o directamente con Gradle. De esta manera se puede gestionar el proceso de una manera más mantenible, pudiendo incluso llevar un control de versiones.
  • Derroche de recursos. Teamcity permite emplear Build Agents de diferente naturaleza, en los que delega la ejecución de las builds. Pueden residir directamente en hardware, en máquinas virtuales, contenedores semi-permanentes o contenedores efímeros. Los he ordenado de mayor a menor potencia y, al mismo tiempo, de menor a mayor elasticidad. Por ello, la decisión sobre el tipo de agentes a utilizar dependerá de la naturaleza de nuestro proceso de integración continua.
  • Optimizar “de oído”. Cualquier optimización debe apoyarse en métricas, que nos guíen hacia los cuellos de botella y nos permitan cuantificar las mejoras obtenidas. En este caso, las más comunes son el tiempo de encolamiento, el tiempo total de la build crítica y el ratio de reintentos –diferenciando si la causa se debió a errores en el código o a problemas con el entorno–. A estas métricas se les pueden añadir todas las que sean necesarias.

Zipfiles on the Fly with Micronaut

Jacob Aae Mikkelsen (@JacobAae) nos describe un caso de uso de streams reactivos con Micronaut. Pese a toda la expectación que levanta este nuevo enfoque, no es común encontrarse con situaciones reales donde esta tecnología suponga una ventaja frente a la alternativa tradicional. Siento desilusionaros.

Partimos una aplicación REST que devuelve ficheros zip pesados, generándolos como se ha hecho siempre, con un OutputStream. Esta solución funciona, pero a costa de almacenar en memoria todo el archivo antes de enviarlo. El problema vino cuando varios usuarios llamaban al mismo tiempo. En los tests se pudo comprobar cómo la aplicación, arrancada con 512 Mb de memoria, no soportaba las peticiones de 8 usuarios.

¿Cuál fue la solución? Devolver un stream reactivo alimentándolo con chunks (montoncitos) de bytes. El zip comenzaba a enviarse en el momento que se generaba el primer chunk –que dejaba de ocupar memoria tras ser enviado–. El resultado: la misma aplicación, levantada con 100 Mb de memoria, pudo aguantar sin problemas la carga de 30 usuarios. Dejo un enlace al código en su github, vale la pena echarle un vistazo.

Las conclusiones finales fueron las siguientes:

  • Ten en cuenta los requisitos no funcionales.
  • Si el disco y el tiempo de respuesta no son un problema, considera enviar un enlace al zip una vez generado y usa una cola para generarlos de uno en uno.
  • Si el escenario anterior no es posible, opta por la solución reactiva.

Micronaut Configurations

Greach-IvanLopez

Iván López (@ilopmar), anterior organizador de Greach, nos enseña diferentes maneras de crear configuraciones en Micronaut. Todas las integraciones con terceras partes (Kafka, MongoDB, Micrometer, etc.) necesitan una puerta de entrada –vía fichero de configuración– para que se puedan inyectar todos los objetos necesarios. Dependiendo del diseño de nuestra integración, esta asignación propiedades → objetos inyectados puede ser más o menos compleja.

En la charla se van revisando distintos mecanismos implicados en la creación de beans de Micronaut, como la anotación @Factory, la inyección de campos con @Value, la inyección condicional con @Requires, la inyección tipada de configuraciones con @ConfigurationProperties, configuraciones a nivel de paquete con @Configuration, y la generación de múltiples instancias empleando @EachProperty y @EachBean. Como todo se entiende mejor con ejemplos, Iván nos mostró código de las integraciones de Micronaut con Flyway y RabbitMQ.

En las conclusiones finales, recalcó la importancia de diseñar las configuraciones poniendo el foco en la facilidad de uso. Debemos ponernos en el lado del usuario de nuestro módulo hacernos la siguiente pregunta: ¿De qué manera me gustaría trabajar con esto?.

Automated Security Testing in a DevOps World

Kevin Wittek (@kiview) nos habla de la importancia de integrar la seguridad, de manera automatizada, a lo largo de las diferentes fases de nuestro ciclo de Integración Continua. El objetivo es, en palabras de Kevin, ir a por la fruta madura, aquellas vulnerabilidades conocidas y fáciles de detectar de forma automática; dejando el pentesting experto para los casos más complejos. Para cada una de las fases nos propone algunas herramientas que considera útiles:

  • Durante el empaquetado de la aplicación, que dará como resultado un artefacto, se puede analizar tanto el código como las dependencias. Para el código, tenemos Find Security Bugs –un plugin de SpotBugs–, y en la parte de las dependencias podemos usar herramientas como Dependency Check  o Snyk.
  • Para la fase de generación de la imagen de Docker disponemos de utilidades de escaneo de imágenes, como layered insight o clair.
  • Una vez que la aplicación está desplegada, entran en juego los escáneres dinámicos, como ZAP: un proxy que ataca a nuestra aplicación con una batería de pruebas basada en vulnerabilidades OWASP, probando diferentes combinaciones de parámetros para explotar inyecciones (SQL, XML, LDAP) y Cross Site Scripting (persistente, basado en DOM, basado en mutaciones).

Muchas de estas herramientas se encuentran incluidas en GitLab CI, integrándose de manera cómoda en el ciclo de DevOps.

The Battle of the IDEs

Ko Turk (@KoTurk77) nos sorprendió con una amena presentación llena de recursos (vídeo, escenografía, ilustraciones originales, participación de la audiencia, etc.), realizando una comparativa entre los IDEs más populares dentro del ecosistema de la JVM: IntelliJ, Eclipse, Visual Studio Code y NetBeans.

Tras mostrar los resultados de una completa encuesta de uso, que realizó a través de Twitter, pasó a listar las fortalezas de los diferentes IDEs. De Eclipse destacó, entre otras cosas, la gran variedad de plugins y la posibilidad de trabajar con varios proyectos desde la misma ventana. Respecto a IntelliJ, resaltó la cantidad de lenguajes soportados y el amplio abanico de opciones de refactorización y completado de código. VSCode brilló por su rendimiento y uso eficiente de los recursos. Como puntos fuertes de NetBeans, comentó su buena integración con Maven/Gradle y su naturaleza Open Source –aunque no es una característica exclusiva de este IDE–.

Los cuatro oponentes fueron comparados bajo diversos puntos de vista: rendimiento, memoria, tiempo de arranque, número de plugins, tamaño de sus comunidades, autocompletado de código e interfaz de depuración.

La conclusión fue que, pese a las fortalezas y debilidades de cada uno, se trata de una elección muy personal. Eso sí, elijas uno u otro, trata de exprimir al máximo su capacidad –vamos, que te aprendas los atajos–.

Conclusiones

Y estas han sido sólo algunas de las charlas. Estoy deseando que se publiquen los vídeos para poder ver las que dejé pendientes.

Mi impresión general es que los microservicios son uno de los enfoques más importantes en la industria del software actual y Java está realizando muchos avances en esa dirección. Hay que resaltar el papel que juega Micronaut en toda esta revolución, tirando del carro en muchos aspectos y marcando las pautas de los nuevos microframeworks de la JVM. Por otra parte, es destacable la meteórica carrera del lenguaje Kotlin, llegando a convertirse en la referencia del mundo Android, pese a su corta vida.

Y esto ha sido todo. Espero que, tras leer esta crónica, os sintáis tentados de asistir a la edición de Greach del año que viene.

Únete a nuestro equipo

Conócenos
Por Eduardo Sánchez 08 Apr 2019

¿Cómo podemos ayudarte?