Cómo encaja Spring Boot en una empresa que ya tiene sistemas
La mayoría de proyectos no empiezan en blanco: empiezan al lado de algo que ya funciona y no se puede parar.
El planteamiento habitual no es migrar la aplicación entera, sino levantar los servicios nuevos en Spring Boot y dejar que convivan con lo anterior. Eso permite entregar valor desde la primera semana sin poner en riesgo lo que ya está en producción, y deja la decisión de qué se mueve para cuando haya datos en lugar de intuiciones.
Lo que hace que esa convivencia funcione no es el framework, son las fronteras: quién llama a quién, con qué contrato y qué pasa si una de las dos partes cambia. Cuando esas fronteras no existen, acaban siendo dos sistemas acoplados por la base de datos, que es lo peor de las dos opciones. Por eso el trabajo de diseño de las APIs va por delante del de infraestructura.
Spring Boot aporta aquí algo concreto: arranque autónomo, configuración por entorno y un modelo de pruebas que permite levantar el contexto real de la aplicación. Eso último es lo que más cambia el día a día de un equipo, porque convierte las pruebas de integración en algo que se ejecuta en cada cambio y no una vez al mes.
Qué se construye en un proyecto de este tipo
- Servicios backend con su propia configuración por entorno, sin valores fijados en el código.
- APIs REST con contrato documentado y pruebas que fallan si la respuesta cambia de forma.
- Acceso a datos con Spring Data JPA, revisando el SQL que se genera y no solo el código que lo pide.
- Seguridad declarada por recurso, no solo a la entrada del servicio.
- Pruebas de integración sobre el contexto real de la aplicación y contra base de datos, no contra dobles.
- Trazas, métricas y comprobaciones de salud desde el primer despliegue, no cuando aparece la primera incidencia.
- Empaquetado y despliegue reproducibles, con los mismos pasos en todos los entornos.
El orden importa: la observabilidad y las pruebas se montan al principio, cuando cuestan poco, no al final, cuando ya hay algo que arreglar y ninguna forma de ver qué pasa.
Decisiones iniciales que condicionan el resto del proyecto
Son baratas al principio y caras después. Conviene tomarlas de forma consciente, no por defecto.
Sobre qué versión de Spring Boot usar
Para un desarrollo nuevo, la versión con soporte más reciente. Para un proyecto que ya existe, la decisión depende de la versión de Java: Spring Boot 3 exige Java 17 como mínimo y arrastra el cambio de javax a jakarta en toda la aplicación.
Eso convierte el salto en un proyecto con entidad propia, no en una actualización de dependencia. Cuando hay una aplicación en Spring Boot 2 que hay que mover, el camino y el orden están explicados en la página sobre la migración hacia Spring Boot.
Tropiezos habituales en proyectos Spring Boot
Ninguno es un fallo del framework: son comportamientos que sorprenden si no se conocen de antemano.
Un método transaccional que no abre transacción
Causa: La llamada viene de otro método de la misma clase. El proxy que aplica @Transactional solo intercepta las llamadas que entran desde fuera del bean.
Qué se hace: Mover el método a otro componente, para que la llamada atraviese el proxy. Es donde más tiempo se pierde depurando, porque el código parece correcto.
La suite de pruebas tarda minutos en arrancar
Causa: Cada clase de prueba levanta un contexto distinto, porque cambian las anotaciones o la configuración y Spring no puede reutilizar el que tenía en memoria.
Qué se hace: Unificar la configuración de las pruebas de integración para que compartan contexto. Reducir el número de contextos distintos suele dividir el tiempo total entre tres o cuatro.
Una propiedad de configuración que se ignora en silencio
Causa: La clave está mal escrita o pertenece a un perfil que no está activo. No hay error: se aplica el valor por defecto y el servicio arranca.
Qué se hace: Validar la configuración en el arranque, de forma que un valor obligatorio que falte impida levantar el servicio en lugar de dejarlo en pie con datos incorrectos.
Se agotan las conexiones del pool bajo carga
Causa: Hay transacciones abiertas mientras se espera a un sistema externo, o el tamaño del pool se quedó en el valor por defecto sin medir nada.
Qué se hace: Sacar las llamadas externas fuera de la transacción y dimensionar el pool a partir de la concurrencia real. Subir el número sin entender la causa solo retrasa el problema.