Arquitectura Hexagonal en Laravel 12: Separando el Dominio del Framework sin Perder Productividad
Laravel es uno de los frameworks más productivos del ecosistema PHP. Su velocidad de desarrollo, ecosistema y simplicidad permiten construir aplicaciones completas en muy poco tiempo. Sin embargo, conforme un proyecto crece, el enfoque tradicional basado únicamente en MVC comienza a mostrar limitaciones importantes.
Controladores gigantes, lógica de negocio distribuida entre modelos y servicios, dependencia excesiva del framework y dificultad para testear correctamente son síntomas muy comunes en aplicaciones Laravel maduras.
Aquí es donde la arquitectura hexagonal comienza a tener sentido.
La arquitectura hexagonal no busca reemplazar Laravel. Busca evitar que el dominio de negocio dependa completamente del framework.
En este artículo explicaré cómo implementar arquitectura hexagonal real en Laravel 12 sin convertir el proyecto en una sobreingeniería innecesaria.
El Problema del MVC Tradicional en Laravel
Laravel promueve una estructura extremadamente cómoda:
Controllers
Models
Views
Services
El problema aparece cuando la aplicación empieza a crecer.
Muchos proyectos terminan así:
Controladores con cientos de líneas
Modelos Eloquent llenos de lógica de negocio
Servicios acoplados al framework
Dependencias imposibles de aislar
Testing lento y complejo
Laravel facilita mucho comenzar rápido, pero también facilita mezclar responsabilidades.
La productividad inicial muchas veces se convierte en deuda técnica silenciosa.
El verdadero problema no es usar Laravel. El problema es permitir que el framework se convierta en el centro absoluto de la arquitectura.
¿Qué Es Realmente la Arquitectura Hexagonal?
La arquitectura hexagonal, también conocida como Ports and Adapters, fue propuesta por Alistair Cockburn con una idea muy clara:
El dominio de negocio no debería depender de infraestructura externa.
Eso incluye:
Bases de datos
Frameworks
APIs
Colas
Sistemas de terceros
En lugar de que la lógica de negocio conozca Laravel, Laravel debería conocer la lógica de negocio.
Esto cambia completamente la dirección de las dependencias.
La Idea Central: Puertos y Adaptadores
La arquitectura hexagonal separa la aplicación en capas claramente definidas.
Dominio
Contiene las reglas reales del negocio.
Entidades
Value Objects
Contratos
Servicios de dominio
Esta capa no debería conocer Laravel.
Aplicación
Coordina casos de uso.
CreateUserUseCase
GenerateInvoiceUseCase
PublishArticleUseCase
Aquí vive la lógica operacional.
Infraestructura
Implementa detalles técnicos.
Eloquent
Redis
Queues
HTTP Clients
Storage
Esta capa depende del dominio, no al revés.
Cómo Organizar Carpetas en Laravel 12
Una de las decisiones más importantes es abandonar la organización puramente técnica.
En lugar de:
app/Models
app/Services
app/Http
app/Repositories
Prefiero algo más orientado al dominio:
app/Core
app/Core/User
app/Core/User/Domain
app/Core/User/Application
app/Core/User/Infrastructure
Dentro:
app/Core/User/Domain/User.php
app/Core/User/Domain/UserRepository.php
app/Core/User/Application/CreateUserUseCase.php
app/Core/User/Infrastructure/EloquentUserRepository.php
Esta estructura cambia completamente cómo evoluciona el proyecto.
Ahora el código está agrupado por contexto de negocio y no por tipo técnico.
Los Casos de Uso Son el Verdadero Centro
Uno de los mayores errores en Laravel es colocar lógica de negocio en controladores o modelos.
En arquitectura hexagonal, el verdadero corazón son los casos de uso.
Por ejemplo:
final class CreateUserUseCase
{
public function __construct(
private UserRepository $users
) {}public function execute(CreateUserCommand $command): User
{
// lógica de negocio
}
}
El controlador únicamente coordina:
public function store(Request $request)
{
return $this->createUserUseCase->execute(...);
}
Esto reduce enormemente el acoplamiento.
Eloquent Sigue Existiendo, Pero Aislado
Uno de los mayores malentendidos es pensar que arquitectura hexagonal significa dejar de usar Eloquent.
No realmente.
Eloquent sigue siendo extremadamente útil.
La diferencia es que deja de ser el núcleo del sistema.
Por ejemplo:
interface UserRepository
{
public function save(User $user): void;
}
Implementación:
final class EloquentUserRepository implements UserRepository
{
public function save(User $user): void
{
UserModel::query()->create([...]);
}
}
Ahora el dominio conoce un contrato, no Eloquent.
Eso permite:
Cambiar infraestructura fácilmente
Mockear dependencias
Mejorar testing
Reducir acoplamiento
Testing Mucho Más Limpio
Uno de los mayores beneficios reales aparece en testing.
En MVC tradicional muchas pruebas requieren:
Base de datos
Framework bootstrapped
Eloquent
Factories
En arquitectura hexagonal, los casos de uso pueden probarse aislados.
public function test_user_can_be_created()
{
$repository = Mockery::mock(UserRepository::class);$useCase = new CreateUserUseCase($repository);$result = $useCase->execute(...);$this->assertTrue($result->isActive());
}
Esto genera pruebas:
Más rápidas
Más estables
Más enfocadas
Y sobre todo:
Permite validar reglas reales de negocio sin depender del framework.
Cuándo Vale la Pena Aplicarla
Aquí es donde debo ser muy honesto.
No todos los proyectos necesitan arquitectura hexagonal.
Aplicarla indiscriminadamente puede generar complejidad innecesaria.
Para un CRUD pequeño probablemente no vale la pena.
Pero comienza a ser extremadamente útil cuando existen:
Múltiples desarrolladores
Reglas de negocio complejas
Integraciones externas
Procesos críticos
Escalabilidad a largo plazo
Testing avanzado
Mi opinión personal es que muchos proyectos Laravel medianos y grandes deberían adoptar al menos una versión parcial de este enfoque.
No necesariamente arquitectura hexagonal pura.
Pero sí separación real entre dominio e infraestructura.
El Error de Sobrearquitectura
Uno de los peligros más grandes es intentar replicar Java Enterprise dentro de Laravel.
He visto proyectos con:
Interfaces innecesarias
Capas absurdas
Abstracciones vacías
Factories para todo
Eso destruye la productividad.
Laravel sigue siendo valioso precisamente por su velocidad.
La clave está en encontrar equilibrio.
La arquitectura debe reducir complejidad, no multiplicarla.
Mi recomendación es introducir arquitectura hexagonal únicamente en áreas críticas del negocio.
No es necesario transformar absolutamente todo.
Laravel 12 Facilita Mucho Este Enfoque
Laravel moderno ya ofrece herramientas muy compatibles con arquitectura limpia:
Container poderoso
Dependency Injection
Actions
Pipelines
Events
Queues
El framework no impide aplicar buena arquitectura.
De hecho, Laravel 12 facilita muchísimo construir aplicaciones desacopladas.
El problema normalmente no es técnico.
Es organizacional.
Muchos equipos nunca definen límites claros entre dominio e infraestructura.
Conclusión
Arquitectura hexagonal no es una moda arquitectónica.
Es una forma de proteger el dominio del negocio contra el paso del tiempo.
Laravel seguirá evolucionando.
Las librerías cambiarán.
Las bases de datos también.
Pero las reglas reales del negocio deberían permanecer estables.
Ese es el verdadero objetivo de separar el dominio del framework.
Mi experiencia personal es que muchos proyectos Laravel colapsan no por problemas de rendimiento, sino porque la lógica termina completamente mezclada con infraestructura.
Cuando eso ocurre, cualquier cambio se vuelve riesgoso.
La arquitectura hexagonal ayuda precisamente a evitar ese problema.
No porque sea perfecta.
Sino porque obliga a pensar en límites, responsabilidades y dependencias desde el inicio.
Y en aplicaciones grandes, eso marca una diferencia enorme.