¿Qué es la Arquitectura Hexagonal?

La Arquitectura Hexagonal, también conocida como Ports & Adapters, es un estilo arquitectónico propuesto por Alistair Cockburn cuyo objetivo principal consiste en aislar completamente la lógica de negocio de cualquier detalle técnico.

En una aplicación tradicional es habitual encontrar reglas de negocio mezcladas con controladores REST, consultas SQL, anotaciones de frameworks o librerías externas. Con el paso del tiempo esto provoca un fuerte acoplamiento que dificulta el mantenimiento y hace que cualquier cambio tenga un impacto mayor del esperado.

La Arquitectura Hexagonal propone invertir esa dependencia. El dominio deja de conocer tecnologías como Spring Boot, Hibernate, Kafka o PostgreSQL y pasa a depender únicamente de abstracciones. De esta manera el negocio permanece estable mientras la infraestructura puede evolucionar libremente.

Arquitectura Hexagonal
Esquema general de Arquitectura Hexagonal basado en Puertos y Adaptadores.

¿Qué aprenderás en esta guía?

  • Qué problemas resuelve realmente la Arquitectura Hexagonal.
  • Diferencias respecto a la arquitectura tradicional por capas.
  • Cómo funcionan los Puertos y Adaptadores.
  • Cómo organizar un proyecto profesional con Spring Boot.
  • Cómo integrar DDD dentro de la arquitectura.
  • Errores habituales que cometen la mayoría de desarrolladores.
  • Cuándo utilizarla y cuándo no merece la pena.

"El dominio nunca debe depender de la infraestructura. La infraestructura debe depender siempre del dominio."

¿Qué problema resuelve la Arquitectura Hexagonal?

Antes de entender la solución, es necesario comprender el problema. La mayoría de aplicaciones Java comienzan con una arquitectura sencilla basada en capas: controladores, servicios, repositorios y base de datos.

Este enfoque funciona correctamente en proyectos pequeños, pero conforme la aplicación crece empiezan a aparecer dependencias entre capas, reglas de negocio repartidas por todo el código y una fuerte dependencia del framework utilizado.

Arquitectura tradicional por capas
Arquitectura tradicional basada en capas.

Los síntomas aparecen muy rápido

Acoplamiento elevado

Las reglas de negocio terminan dependiendo de Spring, Hibernate, anotaciones JPA o incluso consultas SQL.

Pruebas complicadas

Para probar una simple regla de negocio es necesario levantar Spring Boot, una base de datos o numerosos mocks.

Cambios costosos

Una modificación pequeña obliga a tocar controladores, servicios, repositorios y configuración.

Dependencia tecnológica

Cambiar JPA por MongoDB, Kafka por RabbitMQ o REST por GraphQL implica modificar gran parte de la aplicación.

En muchas empresas la lógica de negocio acaba dependiendo más del framework que del propio dominio del negocio.

El verdadero problema

El problema no es Spring Boot, Hibernate o cualquier otra tecnología. El problema aparece cuando el dominio conoce esos detalles técnicos.

Si nuestras entidades contienen anotaciones de persistencia, nuestros casos de uso llaman directamente a repositorios JPA y la lógica de negocio conoce cómo se almacenan los datos, el dominio deja de ser independiente y cualquier cambio tecnológico afecta directamente al corazón de la aplicación.

Comparativa de dependencias
La Arquitectura Hexagonal invierte completamente el sentido de las dependencias.

⚠ El error más habitual

Muchos desarrolladores creen que utilizar paquetes llamadosdomain, application oinfrastructure ya significa utilizar Arquitectura Hexagonal.

No es cierto.

Lo importante no es la estructura de carpetas sino la dirección de las dependencias. El dominio nunca debe depender de Spring, Hibernate, Kafka, RabbitMQ o cualquier otra tecnología externa.

¿Cómo funciona la Arquitectura Hexagonal?

La Arquitectura Hexagonal organiza toda la aplicación alrededor del dominio de negocio. En lugar de colocar la base de datos o el framework en el centro del diseño, el protagonista pasa a ser el propio negocio.

Todo aquello relacionado con tecnologías externas (REST, Kafka, PostgreSQL, MongoDB, Redis, RabbitMQ, servicios cloud, etc.) permanece fuera del núcleo de la aplicación y únicamente se comunica con él a través de contratos bien definidos llamados Puertos (Ports).

Arquitectura Hexagonal
El dominio permanece completamente aislado de la infraestructura.

El dominio siempre ocupa el centro

El dominio contiene únicamente las reglas del negocio. No conoce Spring Boot. No conoce Hibernate. No conoce PostgreSQL. No conoce Kafka. Tampoco sabe si la aplicación es una API REST, GraphQL o una aplicación de escritorio.

Regla número uno

El dominio nunca depende de la infraestructura.

Los Puertos (Ports)

Los puertos son interfaces que definen cómo el dominio necesita comunicarse con el exterior.

El dominio no sabe cómo se almacenan los datos. Simplemente define un contrato indicando qué necesita.

public interface CustomerRepository {

    Customer save(Customer customer);

    Optional<Customer> findById(Long id);

}

Obsérvese que esta interfaz no depende de Spring Data JPA, Hibernate ni ninguna otra librería.

Los Adaptadores (Adapters)

Los adaptadores implementan esos contratos utilizando una tecnología concreta.

@Repository
public class JpaCustomerRepository
        implements CustomerRepository {

    private final SpringCustomerRepository repository;

    @Override
    public Customer save(Customer customer){

        return repository.save(customer);

    }

}

Si mañana decides sustituir PostgreSQL por MongoDB, únicamente cambiará este adaptador. El dominio continuará exactamente igual.

❌ Arquitectura tradicional

  • El dominio depende de JPA.
  • Las entidades contienen anotaciones.
  • La lógica conoce la base de datos.
  • Difícil de probar.

✅ Arquitectura Hexagonal

  • El dominio no conoce tecnologías.
  • Todo depende del dominio.
  • Los adaptadores son intercambiables.
  • Muy sencilla de testear.
La Arquitectura Hexagonal no intenta organizar carpetas. Intenta organizar las dependencias.

Implementando Puertos y Adaptadores

Una vez comprendido el concepto de Arquitectura Hexagonal, llega el momento de trasladarlo a un proyecto real.

Uno de los errores más habituales consiste en pensar que basta con crear carpetas llamadas domain o application. En realidad, lo importante es respetar la dirección de las dependencias y mantener el dominio completamente aislado de cualquier tecnología externa.

Dependencias entre dominio e infraestructura
Organización recomendada para proyectos Java con Arquitectura Hexagonal.

Estructura recomendada

src/main/java

com.freelance.architecture

├── domain
│   ├── model
│   ├── ports
│   ├── services
│   └── exceptions
│
├── application
│   └── usecases
│
├── infrastructure
│   ├── persistence
│   ├── messaging
│   ├── configuration
│   └── security
│
└── adapters
    ├── inbound
    │   └── rest
    └── outbound
        ├── jpa
        └── kafka

Esta organización permite localizar rápidamente cada responsabilidad y evita que las tecnologías de infraestructura se mezclen con el dominio.

El caso de uso

Los Use Cases representan las acciones que el negocio puede realizar. No contienen detalles de infraestructura ni conocen cómo se almacenan los datos.

public class CreateCustomerUseCase {

    private final CustomerRepository repository;

    public CreateCustomerUseCase(CustomerRepository repository){

        this.repository = repository;

    }

    public Customer execute(CreateCustomerCommand command){

        Customer customer = new Customer(

            command.name(),
            command.email()

        );

        return repository.save(customer);

    }

}

💡 Observa un detalle importante

El caso de uso únicamente conoce la interfazCustomerRepository. Nunca sabe si la información se almacenará en PostgreSQL, MongoDB o cualquier otro sistema.

El adaptador de persistencia

El adaptador es el responsable de traducir el contrato definido por el dominio hacia una tecnología concreta.

@Repository
public class JpaCustomerRepositoryAdapter
        implements CustomerRepository {

    private final SpringDataRepository repository;

    @Override
    public Customer save(Customer customer){

        CustomerEntity entity = mapper.toEntity(customer);

        return mapper.toDomain(

            repository.save(entity)

        );

    }

}

Si el día de mañana decides sustituir JPA por MongoDB únicamente tendrás que crear un nuevo adaptador.

El controlador REST

El controlador deja de contener reglas de negocio y se limita a recibir la petición HTTP, construir el comando correspondiente y delegar en el caso de uso.

@RestController
@RequestMapping("/customers")
public class CustomerController {

    private final CreateCustomerUseCase useCase;

    @PostMapping
    public CustomerResponse create(

        @RequestBody CreateCustomerRequest request){

        return mapper.toResponse(

            useCase.execute(

                mapper.toCommand(request)

            )

        );

    }

}
Flujo completo de una petición REST
Recorrido de una petición HTTP dentro de una Arquitectura Hexagonal.
Cada componente conoce únicamente la responsabilidad que le corresponde. Esa separación es la clave para construir aplicaciones fáciles de evolucionar.

Implementación completa con Spring Boot

Uno de los mayores errores al adoptar Arquitectura Hexagonal consiste en pensar que Spring Boot desaparece de la aplicación. No es así.

Spring Boot sigue siendo una excelente herramienta para construir APIs, configurar la aplicación e integrar componentes externos. La diferencia es que deja de ocupar el centro del diseño y pasa a convertirse en un simple detalle de infraestructura.

En una aplicación correctamente diseñada, el dominio podría ejecutarse incluso sin Spring Boot. El framework únicamente conecta el mundo exterior con los casos de uso.

Cliente HTTPREST ControllerUse CasePortAdapterPostgreSQL

Dependencias Maven

La infraestructura depende de Spring Boot, mientras que el dominio no tiene ninguna dependencia del framework.

<dependencies>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>

    <dependency>
        <groupId>org.postgresql</groupId>
        <artifactId>postgresql</artifactId>
    </dependency>

</dependencies>

Configuración de Spring

Los casos de uso son clases Java normales. Spring únicamente se encarga de instanciarlas mediante configuración.

@Configuration
public class CustomerConfiguration {

    @Bean
    CreateCustomerUseCase createCustomerUseCase(
            CustomerRepository repository){

        return new CreateCustomerUseCase(repository);

    }

}

Ventajas de este enfoque

Dominio independiente

Ninguna clase del dominio necesita anotaciones de Spring.

Testing sencillo

Los casos de uso pueden probarse con JUnit sin levantar el contexto de Spring Boot.

Infraestructura sustituible

Cambiar PostgreSQL por MongoDB únicamente implica crear un nuevo adaptador.

Mayor mantenibilidad

Las reglas de negocio permanecen estables aunque cambien las tecnologías.

Una petición completa

Cuando un cliente realiza una petición HTTP, el flujo siempre es el mismo:

HTTP Request

↓

REST Controller

↓

Application Use Case

↓

Output Port

↓

Persistence Adapter

↓

Database

↓

Application Use Case

↓

REST Response
Spring Boot ya no es el corazón de la aplicación. Es simplemente una herramienta para conectar el dominio con el exterior.

Arquitectura Hexagonal y Domain-Driven Design

Uno de los mayores beneficios de la Arquitectura Hexagonal es que encaja de forma natural con Domain-Driven Design (DDD). Ambos enfoques persiguen exactamente el mismo objetivo: situar el dominio de negocio en el centro de la aplicación y evitar que las decisiones técnicas condicionen las reglas del negocio.

Mientras que la Arquitectura Hexagonal define cómo deben organizarse las dependencias, Domain-Driven Design proporciona un conjunto de patrones para modelar correctamente el dominio.

Las piezas del dominio

Entities

Objetos con identidad propia que evolucionan durante el ciclo de vida de la aplicación.

Value Objects

Objetos inmutables definidos únicamente por sus atributos y no por una identidad.

Aggregates

Agrupan varias entidades garantizando la consistencia del dominio.

Repositories

Interfaces del dominio que permiten recuperar y almacenar agregados sin conocer la infraestructura.

Una entidad de dominio

public class Customer {

    private CustomerId id;

    private Name name;

    private Email email;

    public Customer(Name name, Email email){

        this.name = name;

        this.email = email;

    }

    public void changeEmail(Email newEmail){

        this.email = newEmail;

    }

}

Observa que esta entidad no contiene anotaciones de Hibernate, Lombok ni Spring Boot. Es una clase Java pura cuyo único propósito consiste en representar reglas de negocio.

💡 Regla importante

Las entidades nunca deberían depender de tecnologías externas. El dominio debe poder ejecutarse incluso sin Spring Boot.

Value Objects

public record Email(String value){

    public Email{

        if(value == null || !value.contains("@")){

            throw new IllegalArgumentException();

        }

    }

}

Al encapsular la validación dentro del propio Value Object evitamos repetir reglas por toda la aplicación y conseguimos un dominio mucho más consistente.

¿Dónde viven los casos de uso?

Los casos de uso pertenecen a la capa de aplicación. Son los encargados de coordinar el dominio utilizando los puertos definidos por éste.

CreateCustomerUseCase

↓

CustomerRepository

↓

Customer Aggregate

↓

CustomerCreatedEvent

Eventos de dominio

En aplicaciones empresariales es muy habitual utilizar Domain Events para comunicar cambios importantes del negocio sin acoplar distintos módulos entre sí.

public record CustomerCreatedEvent(

    UUID customerId,

    Instant createdAt

){}

Más adelante estos eventos podrán publicarse mediante Kafka, RabbitMQ o cualquier otro mecanismo sin modificar el dominio.

Domain-Driven Design no sustituye a la Arquitectura Hexagonal. Ambos patrones se complementan para construir aplicaciones más mantenibles y preparadas para evolucionar.

Beneficios reales de la Arquitectura Hexagonal

La Arquitectura Hexagonal no es una moda ni una forma diferente de organizar carpetas. Su objetivo es reducir el impacto que tienen los cambios tecnológicos sobre el negocio y facilitar la evolución del software durante años.

En aplicaciones empresariales que permanecen activas durante mucho tiempo, el coste de mantenimiento suele superar ampliamente el coste del desarrollo inicial. Una buena arquitectura permite que ese crecimiento sea sostenible.

Comparativa Arquitectura Tradicional vs Hexagonal
Comparativa entre una arquitectura tradicional y una Arquitectura Hexagonal.

Mayor mantenibilidad

Separar claramente el dominio de la infraestructura permite localizar rápidamente cualquier cambio. Las reglas de negocio permanecen en un único lugar y no aparecen repartidas entre controladores, repositorios, filtros o configuraciones.

✔ Código más limpio

Cada componente tiene una única responsabilidad.

Testing mucho más sencillo

Los casos de uso pueden ejecutarse sin levantar Spring Boot ni conectar una base de datos.

CreateCustomerUseCase useCase =
        new CreateCustomerUseCase(fakeRepository);

Customer customer =
        useCase.execute(command);

assertEquals("Javier", customer.getName());

Esto reduce considerablemente el tiempo de ejecución de las pruebas y permite detectar errores mucho antes.

Independencia tecnológica

Cambiar una tecnología deja de ser una operación traumática. El dominio permanece estable mientras los adaptadores evolucionan.

Persistencia

PostgreSQL → MongoDB

Mensajería

RabbitMQ → Kafka

API

REST → GraphQL

Framework

Spring Boot → Quarkus

Preparada para Microservicios

La Arquitectura Hexagonal facilita enormemente la migración desde un monolito hacia microservicios. Los casos de uso ya se encuentran desacoplados de la infraestructura, por lo que resulta mucho más sencillo extraer funcionalidades hacia servicios independientes.

Escalabilidad del equipo

En proyectos grandes participan varios equipos de desarrollo de forma simultánea. Una arquitectura bien definida reduce conflictos, facilita las revisiones de código y acelera la incorporación de nuevos desarrolladores.

Arquitectura tradicionalArquitectura Hexagonal
Alto acoplamientoBajo acoplamiento
Difícil de probarMuy testeable
Dependencia del frameworkDominio independiente
Cambios costososEvolución sencilla
Mayor deuda técnicaMenor deuda técnica

💡 Mi recomendación

La Arquitectura Hexagonal aporta un enorme valor en aplicaciones empresariales con una vida útil larga, múltiples integraciones y equipos de desarrollo numerosos.

Para un pequeño CRUD con pocas pantallas probablemente suponga una sobreingeniería innecesaria.

Errores más comunes al implementar Arquitectura Hexagonal

Después de participar en proyectos de modernización de aplicaciones Java, uno de los patrones que más se repite es que muchas implementaciones dicen utilizar Arquitectura Hexagonal, pero en realidad únicamente han cambiado la organización de las carpetas.

La verdadera Arquitectura Hexagonal no consiste en mover clases entre paquetes, sino en controlar cuidadosamente la dirección de las dependencias.

❌ Error 1 — El dominio depende de Spring

Es habitual encontrar entidades anotadas con@Entity,@Component o incluso@Service.

El dominio debe ser completamente independiente del framework.

❌ Error 2 — Inyectar JpaRepository directamente

Muchos casos de uso reciben directamente un JpaRepository.

// Incorrecto

@Service
public class CreateCustomerUseCase {

    private final JpaCustomerRepository repository;

}

El caso de uso únicamente debería conocer un Puerto.

// Correcto

public class CreateCustomerUseCase {

    private final CustomerRepository repository;

}

❌ Error 3 — Pensar que la arquitectura son las carpetas

Cambiar el nombre de los paquetes adomain,application oinfrastructureno convierte automáticamente una aplicación en Hexagonal.

Lo importante es quién depende de quién.

❌ Error 4 — Crear un puerto para absolutamente todo

Algunos equipos generan decenas de interfaces innecesarias.

Los puertos únicamente deben existir cuando realmente representan una dependencia del dominio hacia el exterior.

❌ Error 5 — Abusar de los DTO

Es frecuente encontrar cinco o seis objetos diferentes para mover exactamente la misma información entre capas.

Utiliza DTO únicamente cuando exista un límite claro entre el dominio y el exterior.

❌ Error 6 — Convertir todo en un microservicio

Arquitectura Hexagonal no significa Microservicios.

Un monolito bien diseñado suele ser mucho mejor que decenas de microservicios mal diseñados.

❌ Error 7 — Sobreingeniería

No todas las aplicaciones necesitan esta arquitectura.

Para un pequeño CRUD interno probablemente sea suficiente una arquitectura tradicional.

¿Cuándo utilizar Arquitectura Hexagonal?

✔ Recomendada❌ No recomendable
Aplicaciones empresarialesCRUD sencillos
MicroserviciosProyectos temporales
Integraciones complejasPOCs
Equipos grandesAplicaciones de una sola pantalla
Software de larga duraciónProyectos académicos
La mejor arquitectura no es la más compleja. Es la más sencilla capaz de resolver el problema.

Conclusiones

La Arquitectura Hexagonal no pretende sustituir Spring Boot, Hibernate, JPA o cualquier otra tecnología. Su objetivo consiste en proteger el conocimiento más importante de una organización: las reglas de negocio.

A lo largo de esta guía hemos visto cómo separar el dominio de la infraestructura mediante Puertos y Adaptadores, consiguiendo aplicaciones más fáciles de mantener, probar y evolucionar.

Este cambio de perspectiva permite que tecnologías como bases de datos, brokers de mensajería o frameworks puedan cambiar con el paso del tiempo sin obligar a reescribir la lógica de negocio.

Resumen Arquitectura Hexagonal
La Arquitectura Hexagonal protege el dominio y desacopla la infraestructura del negocio.

Checklist antes de adoptar Arquitectura Hexagonal

✅ El dominio no depende de Spring Boot.
✅ Las entidades no contienen anotaciones JPA.
✅ Los casos de uso sólo conocen Puertos.
✅ Los adaptadores implementan los Puertos.
✅ Es posible sustituir la persistencia sin modificar el dominio.
✅ El dominio puede probarse sin levantar Spring.
✅ La lógica de negocio permanece aislada.
✅ La infraestructura es un detalle.

¿Cuándo utilizar Arquitectura Hexagonal?

✔ Muy recomendable

  • Aplicaciones empresariales.
  • Microservicios.
  • Sistemas críticos.
  • Equipos numerosos.
  • Software con muchos años de vida.
  • Integraciones complejas.

✖ Probablemente no sea necesaria

  • CRUD sencillos.
  • Aplicaciones temporales.
  • Pruebas de concepto.
  • Proyectos académicos pequeños.

Próximos pasos

La Arquitectura Hexagonal suele combinarse con otros patrones que permiten construir plataformas empresariales robustas y preparadas para evolucionar.

1

Domain-Driven Design

Modelado del dominio mediante Entities, Value Objects, Aggregates y Repositories.

2

Event Driven Architecture

Comunicación desacoplada mediante eventos utilizando Kafka o RabbitMQ.

3

Microservicios

Separación de capacidades de negocio independientes y despliegues autónomos.

4

Cloud Native

Contenedores, Kubernetes, observabilidad y escalabilidad sobre plataformas cloud.

Continúa aprendiendo

Si este artículo te ha resultado útil, los siguientes temas que te recomiendo son:

  • Spring AI + RAG
  • Virtual Threads en Java 21
  • Observabilidad con OpenTelemetry
  • Arquitecturas Event Driven con Kafka
  • Domain-Driven Design
Javier García Pérez
SOBRE EL AUTOR

Javier García Pérez

Java Backend Developer · Consultor IT Freelance

Especializado en Spring Boot, Quarkus, Arquitectura Hexagonal, Domain-Driven Design y Microservicios, AWS, IA Generativa. Comparto artículos prácticos sobre desarrollo backend, arquitectura de software y buenas prácticas para ayudar a construir aplicaciones mantenibles, escalables y preparadas para entornos empresariales.

¿Te gustaría aplicar esta arquitectura en tu empresa?

Diseño arquitecturas Java modernas, escalables y cloud-native para proyectos empresariales.