Arquitectura Hexagonal en Spring Boot

Elliot Luque
2 min

La Arquitectura Hexagonal, también conocida como arquitectura de Ports and Adapters, es un patrón de diseño que tiene como objetivo principal aislar la lógica central de una aplicación de las preocupaciones técnicas externas, como las bases de datos, las interfaces de usuario o los servicios de terceros.

En el ecosistema de Spring Boot, es común ver proyectos donde la lógica de negocio está fuertemente acoplada a las anotaciones de JPA o a las dependencias de controladores web. Este artículo explora cómo romper ese acoplamiento.

¿Por qué Hexagonal?

Imagina que tu aplicación es un “hexágono”. En el centro reside el Dominio, que contiene las reglas de negocio puras. Nada del exterior debería contaminar este núcleo. La comunicación con el mundo exterior se realiza a través de:

  1. Puertos (Ports): Interfaces que definen qué quiere hacer el dominio pero no cómo.
  2. Adaptadores (Adapters): Implementaciones concretas que traducen las llamadas del exterior hacia el dominio (Adaptadores Primarios) o del dominio hacia el mundo exterior (Adaptadores Secundarios).

Estructura del Proyecto

Una estructura típica siguiendo este patrón se vería así:

com.ejemplo.proyecto
├── domain
│ ├── model (Clases POJO puras)
│ ├── service (Lógica de negocio)
│ └── ports (Interfaces de entrada y salida)
├── infrastructure
│ ├── adapters
│ │ ├── input (REST Controllers, CLI)
│ │ └── output (Repositorios JPA, Clientes HTTP)
│ └── config (Configuración de Spring)

1. El Núcleo de Dominio (Domain Core)

Aquí es donde reside la “verdad” de tu aplicación. Evitamos usar anotaciones como @Entity o @Table aquí para no depender de JPA.

public class Pedido {
private UUID id;
private List<Producto> productos;
private EstadoPedido estado;
public void confirmar() {
if (productos.isEmpty()) {
throw new BusinessException("No se puede confirmar un pedido vacío");
}
this.estado = EstadoPedido.CONFIRMADO;
}
}

2. Los Puertos (Ports)

Definimos interfaces para lo que necesitamos. Por ejemplo, un puerto de salida para guardar pedidos:

public interface PedidoRepositoryPort {
Pedido guardar(Pedido pedido);
Optional<Pedido> buscarPorId(UUID id);
}

3. Los Adaptadores (Adapters)

Un adaptador secundario implementaría el puerto de salida usando JPA:

@Component
public class JpaPedidoAdapter implements PedidoRepositoryPort {
private final SpringDataPedidoRepository repository;
@Override
public Pedido guardar(Pedido pedido) {
PedidoEntity entity = PedidoMapper.toEntity(pedido);
return PedidoMapper.toDomain(repository.save(entity));
}
}

Beneficios de este enfoque

  1. Facilidad de Pruebas: Puedes testear la lógica de negocio sin levantar un contexto de Spring o una base de datos real.
  2. Independencia Tecnológica: Si decides cambiar de MySQL a MongoDB, solo cambias el adaptador de infraestructura; el dominio permanece intacto.
  3. Mantenibilidad a largo plazo: El código es más fácil de leer y las responsabilidades están claramente delimitadas.

Conclusión

Implementar Arquitectura Hexagonal en Spring Boot requiere un esfuerzo inicial mayor debido a la creación de mappers y múltiples capas. Sin embargo, para aplicaciones que crecerán y evolucionarán a lo largo de los años, es una de las mejores inversiones que un desarrollador puede hacer.