Desarrollador Backend · Java 25 + Spring Boot 4 · Optimización de rendimiento en producción
Experiencia real en entornos de producción: –98% de latencia en endpoints críticos, –99% en procesos de migración multihilo. Especializado en arquitecturas Java modernas, integración de IA y sistemas distribuidos.
Backend developer especializado en el ecosistema Java moderno (Java 25, Spring Boot 4, Virtual Threads) con experiencia real en optimización y modernización de sistemas en producción.
Actualmente en Atlantis Technology como Desarrollador Backend (Spring Boot), modernizando sistemas legacy con impacto medible: –98% de latencia en endpoints críticos (2.2s → 35ms, reconocido por el cliente), –99% en procesos de migración multihilo (5h → 3min) y erradicación de N+1 en cientos de consultas. Paralelamente, como Coordinador Digital en la Asociación Juvenil Proyecto Dubini, diseñé la arquitectura de la infraestructura interna priorizando compilación nativa (GraalVM) para operar en instancias cloud de recursos mínimos.
En paralelo, desarrollo mods para Minecraft Forge como campo de práctica de conceptos avanzados de Java: Mixins, sistemas de estado persistente, integración con APIs de terceros y diseño event-driven.
📍 La Laguna, Santa Cruz de Tenerife
¿Te parecen números demasiado optimistas? Haz clic en cada tarjeta para ver el desglose técnico y la arquitectura detrás de estas métricas.
Plataforma empresarial de gestión de inventario para economatos de escuelas culinarias. Diseñado bajo un patrón de Monolito Modular con Arquitectura Hexagonal (Ports & Adapters) como núcleo principal (`inventory-service`) en Spring Boot 4.0 & Java 25 (aprovechando hilos virtuales, ZGC Generational y ScopedValue). Integra servicios satélites políglotas: un agente conversacional de IA en NestJS 11 que implementa el Model Context Protocol (MCP) con un Grafo de Memoria Semántica (SMG) y soporte multi-proveedor (OpenAI, Anthropic, DeepSeek, etc.), y un microservicio en Python/FastAPI con Meta Prophet para predicción de demanda de consumo a 14 días.
Hitos Técnicos Clave:
La arquitectura está intencionadamente sobredimensionada para el caso de uso real. Cada patrón elegido (Hexagonal, CQRS, Kafka, MCP) tiene una justificación técnica y documenta cómo se aplica en un contexto cohesionado. Es un ejercicio de arquitectura, no de productividad mínima.
Repositorio Backend API // Repositorio Frontend // Documentación Técnica (+200 págs.)
Digitalización completa de la infraestructura de TI de la Asociación Juvenil Proyecto Dubini (AJPD), sustituyendo el flujo de trabajo manual basado en Excel por una aplicación de gestión robusta, eficiente y segura.
Arquitectura y Backend (Java 21 & Spring Boot 3.4.1): Diseñado con un enfoque modular y optimizado para compilación AOT (GraalVM Native Image). Utiliza Spring Data JDBC para evitar la magia reflexiva y sobrecarga en runtime de JPA/Hibernate tradicional, garantizando total compatibilidad nativa y reduciendo el consumo a solo 128 MB de RAM. Cuenta con login mediante Google OAuth2 y firmas JWT seguras.
Frontend e Interfaz (Angular v22.0.0 Zoneless): Desarrollado con componentes standalone y cambio de estado Zoneless, optimizando el rendimiento. Utiliza vanilla CSS con transiciones de estado y micro-animaciones personalizadas, PWA para funcionamiento offline y RxJS para flujos de datos.
Características Destacadas de la UI:
Desarrollo end-to-end de una plataforma de publicaciones con arquitectura distribuida. El sistema cuenta con un proveedor frontend que sirve archivos estáticos y cachea los contenidos, y un Backoffice para edición y administración de contenido.
La comunicación entre servicios es asincrónica mediante WebFlux y está protegida con JWT. Implementación de un sistema de caché de doble capa (Caffeine en memoria + persistente en disco), circuit breaker e invalidación por eventos. Gracias a este enfoque, el consumo de ancho de banda se redujo en un 89.7%, operando fluidamente en entornos cloud limitados.
Visita la web // Repositorio frontend provider // Repositorio backoffice
Plataforma de mensajería en tiempo real desarrollada con Node.js, con autenticación JWT, roles Admin/Usuario, hash de contraseñas con bcryptjs y rutas protegidas mediante middleware. Endpoints RESTful en Express.js y conexión a MySQL mediante connection pooling.
Comunicación en tiempo real con WebSockets usando Socket.io, con persistencia básica de mensajes y seguimiento del estado en línea. Se aplicaron buenas prácticas de seguridad como validación de entradas con express-validator y manejo de errores asincrónico.
Campo de práctica de conceptos avanzados de Java: Mixins para modificación de bytecode, integración con APIs de terceros, diseño de sistemas de estado persistente y arquitecturas event-driven bajo restricciones de rendimiento.
Bridge y expansión de combate táctico entre Epic Fight y Scorched Guns. Diseña un sistema híbrido de animación en el cual la cámara en primera persona mantiene la inmersión clásica del shooter mientras que la tercera persona aprovecha el motor de animaciones de Epic Fight.
Mod de Minecraft que sincroniza el loot de cofres individuales (generados por Lootr) para que sea compartido por equipos de FTB Teams. Resuelve la desconexión del juego cooperativo en servidores masivos sin perder la seguridad de cofres.
Reemplazo completo de la regeneración natural de Minecraft por un sistema de fatiga acumulable de estilo Soulslike (UHC-style natural healing block).
Refactorización del acceso a datos que abarca la capa de persistencia, servicios y entidades. El desarrollo estuvo orientado a eliminar la mayor parte de la lógica duplicada bajo principios DRY, mitigar cuellos de botella estructurales producidos por estrategias de carga ineficientes y optimizar la complejidad algorítmica de las consultas.
La aplicación presentaba una degradación relevante del rendimiento con tiempos de respuesta superiores a los 2 segundos en sus endpoints principales. El origen del problema radicaba en la sobrecarga en la transferencia de datos debido al comportamiento Eager Loading implícito en las relaciones @ManyToOne, la proliferación del problema de consultas N+1, y una ineficiente estrategia de paginación procesada en memoria (mediante el uso de subList de Java), lo que ponía en riesgo la estabilidad del sistema al escalar el volumen de datos.
El sistema implementa una reestructuración de las capas de persistencia, servicios y entidades de la aplicación, abstrayendo la lógica redundante y delegando la carga pesada de datos directamente al motor de la base de datos de manera eficiente.
JOIN FETCH y EntityGraphs en la capa de persistencia, reduciendo los accesos recursivos al motor relacional.@Transactional(readOnly = true) en métodos de consulta para optimizar los flujos de lectura en gran medida y reducir de forma significativa el proceso de dirty checking de Hibernate en operaciones de lectura.Se delega la paginación nativa al motor de la BD. El sistema filtra e identifica primero únicamente los IDs de los registros correspondientes al segmento solicitado, reduciendo la transferencia inicial de datos.
Una vez obtenidos los identificadores únicos, se recuperan los datos completos de las entidades en lotes agrupados, reordenando los resultados directamente en memoria para garantizar la consistencia del orden de resultados.
Las consultas repetitivas de datos maestros o estáticos obtienen una respuesta en decenas de milisegundos mediante una Caché de Segundo Nivel (L2).
El impacto del rediseño multicapa se evidencia en la reducción de los tiempos de respuesta y en la previsibilidad de la carga en todo el sistema de la aplicación:
| Segmento de Endpoint / Operación | Latencia ANTES | Latencia AHORA | Factor Impacto (Speedup) | Estado de Fluidez |
|---|---|---|---|---|
| Búsqueda Relevante (Expedientes) | 1.18s - 2.24s | 35ms - 50ms | ~x42.0 | Baja latencia |
| Búsqueda Media (Registros) | 0.8s - 1.03s | 20ms - 50ms | ~x10.0 | Estabilizada |
| Procesos Rápidos (Pre-optimizados) | 48ms | 18ms | ~x2.6 | Optimización adicional |
Nota sobre la consistencia: Incluso en procesos que ya contaban con un rendimiento óptimo (<100ms), se logró una reducción del 50% en el tiempo de respuesta, favoreciendo una experiencia de usuario predecible y con una latencia más consistente.
Rediseño de procesos ETL para migración, transformación y anonimización en paralelo de datos históricos a gran escala, eliminando cuellos de botella de red y base de datos mediante concurrencia y caché de relaciones en memoria JVM.
Migración de un histórico acumulado de más de 10 millones de registros con 15 años de recorrido. El proceso original secuencial tardaba más de 5 horas en completarse. El motor de base de datos sufría por la ejecución recursiva de subconsultas dinámicas lookup (aproximadamente 38 millones de subconsultas select) destinadas a resolver claves foráneas e integridad referencial en caliente para cada fila insertada, bloqueando la base de datos durante las ventanas de mantenimiento técnico.
La solución implementada redujo las consultas de base de datos tipo N+1 durante el bucle de inserción, resolviendo todas las dependencias relacionales en caliente dentro de la JVM.
Se consultan las tablas maestras origen una sola vez y se construyen mapas asociativos en memoria. El costo inicial es bajo a cambio de la eliminación de los lookups dentro del bucle principal.
Se lanzan tareas concurrentes a través de un pool dinámico de hilos. Cada hilo escribe de forma aislada en su propio script SQL en disco, evitando bloqueos de I/O y mezcla de sentencias.
El script SQL generado contiene valores literales puros precalculados. La base de datos destino ejecuta los inserts secuenciales de forma directa sin resolver índices dinámicamente, logrando una respuesta en decenas de milisegundos.
ANTES: SQL Generado con Subconsultas Lookup Recursivas
INSERT INTO DETALLE_TRANSACCION (transaccion_fk, cod_detalle, info_pago, fecha_creacion) VALUES ( (SELECT MAX(id) FROM TRANSACCIONES t WHERE t.usuario_fk = (SELECT id FROM USUARIOS u WHERE u.token_acceso = 'USR-2026-X98A')), 'DET-90234', 'INFO_MOCK', '2026-07-05 13:00:00' );
AHORA: SQL Generado con Identificadores Directos Precalculados
INSERT INTO DETALLE_TRANSACCION (transaccion_fk, cod_detalle, info_pago, fecha_creacion) VALUES ( 3489102, -- ID precalculado de forma eficiente en memoria Java (O(1)) 'DET-90234', 'INFO_MOCK', '2026-07-05 13:00:00' );
El tiempo total del proceso varía según la latencia de red al servidor de base de datos debido al volumen de subconsultas lookup del método anterior. A continuación se detallan los tres escenarios analizados:
| Escenario (Latencia) | Tiempo ANTES | Tiempo AHORA | Aceleración (Speedup) | Reducción de Tiempo |
|---|---|---|---|---|
| Baja Latencia (SSD Local - 0.1 ms) | ~1.1 horas | ~8.5 minutos | ~7.7x | -87.0% |
| Media Latencia (LAN Corporativa - 0.5 ms) | ~5.3 horas | ~8.5 minutos | ~37.4x | -97.3% |
| Alta Latencia (Conexión VPN - 3.0 ms) | ~31.6 horas | ~8.5 minutos | ~223.0x | -99.5% |
Nota sobre el cálculo: En el entorno real, el tiempo de procesamiento se redujo de 5 horas a 3 minutos para el lote de datos ejecutado bajo una latencia media de red corporativa (~1.1 ms promedio por consulta lookup).
La optimización del proceso ETL no solo mejoró el tiempo de ejecución en un 99%, sino que cambió la dinámica de trabajo del equipo. Al reducir el tiempo de 5 horas a 3 minutos, pudimos iterar y validar la migración más de 60 veces durante la fase de pruebas. Esto nos ahorró semanas de trabajo manual y nos permitió detectar inconsistencias en los datos que, de otra forma, habrían sido catastróficas en el entorno de producción
⚠️ Información sobre Anonimización: Las referencias a nombres de bases de datos, esquemas relacionales, nombres de tablas, columnas y formatos de datos representados en esta sección han sido modificados significativamente y reemplazados con estructuras transaccionales genéricas.
Sistema de tolerancia a fallos para un backend con 4 servicios de infraestructura (PostgreSQL Primary, PostgreSQL Replica, Redis, Kafka). Diseñado para que la aplicación continúe operativa para los casos soportados aunque uno o varios servicios tengan incidencias, con detección proactiva, degradación controlada y notificación en tiempo real al frontend.
Un backend con CQRS (escritura en Primary, lecturas en Replica), caché distribuida en Redis y eventos de auditoría via Kafka tiene múltiples puntos de fallo. Un timeout de Redis o una caída de la réplica no deberían provocar errores 500 al usuario.
4 Circuit Breakers independientes (Resilience4j) monitorizan cada servicio. Un HealthChecker proactivo testea las conexiones cada 3-5 segundos y abre el circuit breaker antes de que una petición real falle. Al levantar una incidencia o recuperación, se publica un Spring Event que un WebSocketNotificationService traduce a alertas STOMP al frontend.
ScopedValue (Java 25), sin cambiar una línea de
código de negocio.
CircuitBreakerAwareCacheManager envuelve cada
operación Redis. Con el CB abierto, toda operación de caché se
convierte en cache-miss: la app sigue funcionando sin caché.
Cada 3-5s se testean DB, Replica, Redis y Kafka. Si falla, se abre el Circuit Breaker inmediatamente.
Resilience4j emite un evento de transición (CLOSED→OPEN). Un
listener lo traduce a CircuitBreakerOpenEvent.
El servicio de notificaciones envía un código de alerta
(DB_FAILURE, REDIS_FAILURE...) vía
STOMP a /topic/alerts. Al reconectar, el
frontend recibe el estado actual de todos los CBs.
Cada 10-15s se testea la recuperación del servicio afectado. Si
responde, se cierra el CB y se envía
_RECOVERED al frontend.
El impacto de una incidencia se gestiona de forma aislada para favorecer la alta disponibilidad parcial:
DB_FAILURE,
REDIS_RECOVERED, etc.).
@Cacheable no lanza excepción con Redis CB abierto.
Arquitectura diseñada para una degradación controlada / alta disponibilidad parcial: la aplicación continúa operativa para los casos soportados aunque ocurran fallos en servicios auxiliares. La detección proactiva (health checks cada 3s) reduce el tiempo medio de detección frente al enfoque reactivo tradicional, y el WebSocket permite al frontend mostrar banners informativos en vez de errores genéricos.
Sistema de caché multicapa diseñado para reducir peticiones al backend, optimizar el uso de ancho de banda y mantener la experiencia del usuario durante incidencias o mantenimiento del backoffice. Pensado para Proyecto Dubini (Asociación medioambiental juvenil): menor tráfico → menor consumo energético.
Doble capa de caché: Caffeine en memoria para acceso inmediato y una caché persistente en disco como respaldo. El frontend provider precarga contenido relevante al arranque para operar de forma autónoma si el backoffice no está disponible.
Primera consulta a Caffeine para acceso inmediato.
Solicitud al backoffice y almacenamiento en caché cuando no existe el dato en memoria.
Fallback desde disco si la memoria y el backoffice no responden.
El endpoint api/news/last compara ETags
precalculadas para indicar si hay cambios. Respuestas mínimas:
304 Not Modified (sin transferencia) o
200 OK
si hay contenido nuevo. Las ETags se almacenan localmente para
reducir la latencia de cálculo.
Service Worker que cachea recursos estáticos (HTML, CSS, JS) y datos esenciales, habilitando funcionamiento offline y reduciendo peticiones repetidas.
El sistema reduce el consumo de ancho de banda gracias a que el contenido se sirve frecuentemente desde caché. El cálculo es el siguiente:
Peso primera carga: 60 KB.
Peso cargas posteriores: 200 B.
Para 30 000 usuarios, cada uno realizando 10 visitas:
Consumo total ≈ 1.85 GB.
En un sistema sin caché estructurada, cada visita costaría 60 KB:
Reducción: 18 GB → 1.85 GB (≈ −89.7%).
Esto justifica el porcentaje de mejora reportado en las métricas.
Arquitectura diseñada para el desacoplamiento y la eficiencia: el frontend puede funcionar con contenido cargado previamente y el frontend provider opera de forma independiente del backoffice. Prioriza la resiliencia, simplicidad y reducción de huella energética.
Se mejoraron los tiempos de despliegue y arranque en frío de un servicio Spring Boot mediante técnicas de compilación nativa y automatización de pipelines.
Inicialmente, el proyecto tenía tiempos de despliegue de 5 minutos y arranque en frío de 1,5 minutos, causando excepciones por timeout y una experiencia de despliegue ineficiente.
Workflow de CI/CD: GitHub Actions .
Imagen Docker optimizada: Docker Hub .
Dockerfile utilizado: Dockerfile.native-simple .
(Este es uno de los servicios optimizados; ambos tienen configuraciones similares.)
La combinación de compilación nativa, ajustes de compatibilidad y pipeline automatizado permitió despliegues en pocos segundos y arranques en frío eficientes. Esta optimización demuestra capacidad para diseñar soluciones que integran rendimiento, DevOps y arquitectura de servicios de manera más eficiente.
No dudes en contactarme a través de mis redes sociales.