
En 2018, nuestro equipo en Flowing Code armó una demo rápida y experimental para mostrar el entonces flamante Vaadin 10. Ideamos un proyecto alrededor del torneo de fútbol que se jugaba en Rusia en ese momento en lo que llamamos un hackathon mundialista. La aplicación fue diseñada como un dashboard en vivo para seguir el fixture de los partidos, los resultados en tiempo real y la tabla de posiciones de los grupos.
Con el inicio del torneo de 2026, nos hicimos una pregunta: ¿Sería posible actualizar este repositorio que ya tiene 8 años a Vaadin 25 y mostrar la información del evento actual? En lugar de hacer todo el trabajo pesado a mano, decidimos sumar a Claude como nuestro pair-programmer de IA (específicamente su modelo Opus). Esta es la historia de cómo resucitamos un proyecto de hackathon ocho años después, junto con todo lo que aprendimos en el camino sobre migraciones asistidas por Inteligencia Artificial.
El Primer entregable no fue código
Al enfrentarnos a una migración que abarca ocho años de breaking changes, el mayor riesgo es empezar a ciegas.
- Nuestra app original dependía de Vaadin 10, Java 8 y Spring Boot 2.0.
- Para llegar a Vaadin 25, teníamos que actualizar a Java 21 y Spring Boot 4.0.6, mientras dejábamos que el framework se encargara del enorme cambio interno hacia su moderno motor de frontend.
- Además, la exploración inicial de Claude verificó rápidamente que nuestra API de datos original (
worldcup.sfg.io) estaba permanentemente offline.
Debido a estos saltos masivos, le pedimos a Claude que escribiera una guía de migración antes de programar una sola línea de código. Este documento detallaba el estado actual, comparaba nuevas fuentes de datos y resaltaba las decisiones específicas que nuestro equipo humano debía tomar.
Convertir las incógnitas en un checklist revisable por humanos resultó ser lo más valioso que produjo la IA. Replanteó las expectativas de inmediato: esto no era solo un simple salto de versión; era una reescritura de la capa de datos y una renovación de la arquitectura.
El Humano en el proceso: Tomando las decisiones difíciles
Aunque Claude presentó las opciones y los trade-offs, fue el criterio humano lo que moldeó en qué se convertiría finalmente la aplicación.
- La restricción de la API de datos: Establecimos una regla estricta: “gratuita y sin API key“. Claude analizó el panorama y nos demostró que esta única restricción eliminaba las APIs de pago y las estadísticas detalladas (como las formaciones y la posesión) que incluía la aplicación original.
- Redefiniendo el producto: Al elegir una fuente de datos gratuita, redefinimos sutilmente el producto. Aceptamos que no podríamos tener analíticas avanzadas, acotando el alcance a una reconstrucción de la funcionalidad principal centrada en el fixture, resultados en vivo, posiciones de los grupos y las páginas de cada país. Fuente de datos elegida
worldcup26.ir. - Validando el ecosistema: La fecha de corte de conocimiento de Claude hizo que asumiera que Vaadin 25 usaba Spring Boot 3.x, pero se requirió nuestro conocimiento del entorno para corregir este dato a Spring Boot 4.
- Precaución con las marcas registradas: Debido a que algunos términos asociados con este evento global son marcas estrictamente registradas, fue necesario aplicar el criterio humano para renombrar la aplicación a “Global Football 2026 Stats” e incluir un descargo de responsabilidad (disclaimer) claro sobre nuestra falta de afiliación. La IA puede escribir el código, pero el humano es el responsable de las decisiones legales y de marca.
La Arquitectura que nos ahorró tiempo

A pesar del salto tecnológico masivo, la migración fue un rotundo éxito gracias a la capa MVP (Model-View-Presenter) de la aplicación original.
Como el contrato entre las vistas y los DTO era completamente agnóstico a la fuente de datos, solo tuvimos que reescribir el cliente del repositorio y los mappers del servicio. Los presenters, las pantallas y los DTO se mantuvieron completamente intactos. Fue un recordatorio perfecto de que una buena estructuración de la arquitectura es lo que más frutos rinde durante una migración importante.
Trabajando con Claude: Superpoderes y la curva de aprendizaje
Usar un pair-programmer de IA convirtió una excavación arqueológica de varios días en una sesión guiada y bien documentada. Sin embargo, también resaltó que, como desarrolladores, todavía estamos aprendiendo a manejar correctamente estas herramientas.
Dónde brilló la IA:
- Reconocimiento rápido: Claude navegó rápidamente por ocho años de APIs eliminadas y enumeró los breaking changes archivo por archivo.
- Verificación fundamentada: No se limitó a adivinar; inspeccionó los JARs resueltos, leyó los POMs de los starters oficiales y usó
curlpara probar el esquema de la API en vivo antes de escribir los mappers. - Trabajo tedioso a escala: La IA manejó sin esfuerzo los barridos mecánicos, como renombrar
javaxajakartay reemplazar componentes deprecados.
La curva de aprendizaje humana:
- El contexto lo es todo: Los comandos de desarrollo local fallaron inicialmente por la falta de una dependencia
vaadin-dev. Esto no fue necesariamente culpa de Claude; fue un recordatorio de que la IA solo conoce el contexto que le proporcionamos. - Estableciendo reglas de juego: En un momento dado, la IA editó un archivo mientras estábamos probando activamente la aplicación en ejecución, creando configuraciones conflictivas que rompieron el arranque. ¿La lección? Tienes que decirle explícitamente a tu agente de IA: “Estoy probando, no toques nada”, para que pueda terminar un cambio de forma atómica.
El epílogo: Conectando el MCP de Vaadin y descubriendo Signals
Nuestra migración logró exitosamente que la aplicación corriera en Vaadin 25. Sin embargo, más tarde nos dimos cuenta de que no habíamos utilizado el Model Context Protocol (MCP) específico de Vaadin durante el proceso inicial.
En retrospectiva, conectar el MCP desde el primer día nos habría salvado de algunos tropiezos de configuración iniciales. Por ejemplo, la falta de la dependencia vaadin-dev con la que nos topamos durante las pruebas locales es exactamente el tipo de conocimiento específico de versión que un MCP con conocimiento del dominio (domain-aware) ofrece out of the box.
Pero el verdadero valor del MCP salió a la luz cuando decidimos explorar las nuevas funcionalidades de Vaadin 25. Como desarrolladores, sabíamos de Signals, la nueva API de manejo de estado reactivo de Vaadin, y queríamos ver si nuestra demo podía beneficiarse de ella. Al darle a Claude acceso al MCP de Vaadin, la IA captó instantáneamente los matices técnicos de esta nueva funcionalidad. Le pedimos a Claude que analizara nuestro código base, y señaló exactamente dónde encajaba Signals.
En nuestro código migrado, habíamos portado fielmente un patrón de 2018 para enviar los resultados de los partidos en vivo a la UI: un broadcaster hecho a medida con un Set estático de tarjetas de partidos, que requería registros explícitos de attach/detach y llamadas manuales a UI.access().
Armado con el MCP, Claude nos mostró cómo el nuevo SharedMapSignal de Vaadin está construido exactamente para este tipo de estado compartido entre usuarios. Refactorizamos la capa de actualización en vivo, permitiendo que cada tarjeta de partido simplemente se enlazara a una señal. Cuando el proceso de polling programado actualiza la señal, cada UI que muestra ese partido se actualiza automáticamente. Ya no hay colecciones de listeners, ni código de conexión (plumbing) manual entre hilos y la UI, y todo el código redundante fue eliminado.
¿La conclusión? La IA es excelente para traducir código antiguo y hacer que compile en una nueva plataforma, pero cuando se combina con herramientas específicas del dominio como el MCP de Vaadin, se convierte en un poderoso aliado para validar ideas y ayudarte a modernizar tu arquitectura.
Pruébalo localmente
Si quieres explorar el código, ver cómo implementamos Signals, o revisar los cambios exactos que Claude nos ayudó a hacer, visita el repositorio disponible en nuestra organización de GitHub.
La mejor parte de cualquier implementación es verla finalmente en vivo. Puedes probar fácilmente nuestra aplicación modernizada en Vaadin 25 clonando el repositorio y ejecutándola en tu entorno local.
Simplemente clona el repositorio y ejecuta: mvn spring-boot:run. Una vez que compile y arranque, abre tu navegador y navega a http://localhost:8080 para verla en acción.
Como elegimos una API de datos gratuita y mantenida por la comunidad, ten en cuenta que a veces sufre con el tráfico masivo y experimenta caídas temporales. Si los datos tardan en cargar o fallan, la arquitectura de Vaadin está funcionando perfectamente, pero la fuente de datos puede estar temporalmente saturada.

El veredicto sobre Vaadin: De días a horas
Thanks for reading, and let’s keep the code flowing!
Si hay una gran conclusión para la comunidad de Vaadin, es esta: saltar de Vaadin 10 a 25 suena intimidante, pero con la configuración adecuada, es sumamente factible.
Para una aplicación de alcance reducido como es este demo, una migración que abarca ocho años de cambios (incluyendo la masiva evolución interna del frontend de Vaadin, una reescritura de la capa de datos y el cambio al namespace de Jakarta) normalmente tomaría días si se hiciera a mano. Con Claude, comprimimos esto en una sola tarde.
En total, el proceso de migración tomó alrededor de 3 a 4 horas de tiempo de sesión efectivo. El paso mecánico más lento ni siquiera fue la generación de código; fue Vite armando el bundle del frontend, lo que tomó unos 3 minutos. Por supuesto, esta velocidad solo fue posible gracias a que había un humano con conocimiento técnico supervisando el proceso para corregir las asunciones de la IA en tiempo real. Pero demuestra que, con una arquitectura limpia y un agente de IA encargándose del trabajo pesado, devolverle la vida a un sistema legacy es más rápido que nunca.
Esperamos que esta historia te anime a darle una oportunidad a la IA y a inyectarle nueva vida a tus propias aplicaciones legacy.
¡Gracias por leer, and let’s keep the code flowing!
(P.S. ¡Vamos Argentina! 🇦🇷)
¡Únete a la conversación!