La Arquitectura Hexagonal, también conocida como “Arquitectura de Puertos y Adaptadores”, es un modelo para crear sistemas desacoplados y fáciles de mantener, basándose en la separaración de las responsabilidades del núcleo del negocio, de los detalles técnicos (se considera detalles a todo lo externo al negocio… como la base de datos, la interfaz de usuario, servicios web).
Fue propuesta por Alistair Cockburn en 2005, como un conjunto de ideas, patrones, una filosofía de diseño de software, y poco a poco fue ganando popularidad (hoy es una arquitectura muy usada en microservicios).
El término “hexagonal” tiene que ver con la idea de que la lógica de negocio está en el centro de la aplicación y que cada lado representa un puerto de entrada/salida de la aplicación, y una forma poligonal expresa mejor que un círculo este principio.
Estos puertos son el punto de entrada o salida de detalles externos, mecanismos que interactúan con nuestro sistema, son las abstracciones (interfaces) de comunicación.
Cada uno de estos puertos tiene asignado uno o varios adaptadores, las implementaciones concretas, por ej. las querys para insertar en una base de datos MySQL.
Esto es más flexible que un modelo en capas tradicional, donde la interacción suele ser lineal y en un solo sentido.
Una de los grandes problemas de los sistemas de software es la inclusión de lógica de negocio en el código fuente de la interfaz de usuario, lo que origina que:
La arquitectura hexagonal propone hacer foco en estos temas, con la idea de facilitar el desarrollo, el mantenimiento y las pruebas. Que sea independiente de los posibles dispositivos y bases de datos para desarrollar… que se pueda adaptar a nuevos detalles externos sin tener que volver a codificar los casos de uso (plugins, conectar y desconectar detalles)… y que se pueda probar sin tener que disponer de todos los elementos.
Vemos una aplicación con dos puertos activos y varios adaptadores para cada puerto. Los dos puertos son el lado que controla la aplicación y el lado para recuperar datos.
Este dibujo muestra que la aplicación puede ser dirigida de igual manera por una suite de pruebas automatizadas de regresión a nivel de sistema, por un ser humano, por una aplicación http remota, o por otra aplicación local.
En el lado de los datos, la aplicación se puede configurar para ejecutarse desacoplada de bases de datos externas, utilizando una base de datos de sustitución MySQL en memoria, o mock, o se puede ejecutar con la base de datos de pruebas, o con la de producción.
La especificación funcional de la aplicación, puede que en casos de uso, se hace contra la interfaz del hexágono interno, y no contra ninguna de las tecnologías externas que se podrían utilizar.
En el siguiente artículo hablaremos de Arquitectura Limpia (Clean Architecture) y veremos que la arquitectura hexagonal es una de las implementaciones más puras que podemos encontrar de Clean Architecture.
La distribución de las capas, su contenido, y las reglas de dependencia, son practicamente las mismas.
Acá hago una pausa, no todo el mundo considera que la arquitectura hexagonal sigue la regla de la dependencia, que dice que las capas externas conocen a las internas, pero no al revés. Dependiendo de donde se coloquen los puertos puede que no se respete esta regla (si las reglas de negocio usan puertos, y los puertos se colocan afuera de la capa de negocio, no se respeta la regla de la dependencia). Personalmente considero que debe respetarse, pero queda a criterio de cada uno.
Si bien la arquitectura se dibuja como un hexágono, a la hora de implementarla se parece más a una arquitectura de capas, vamos a verlo con un ejemplo:
Pedido.java (Dominio)
package restaurante.dominio;
public class Pedido {
private Articulo articulo;
private int cantidad;
public Pedido(Articulo articulo, int cantidad) {
this.articulo = articulo;
this.cantidad = cantidad;
}
// Getters y otros métodos si son necesarios
}
Articulo.java (Dominio)
package restaurante.dominio;
public class Articulo {
private String nombre;
private double precio;
public Articulo(String nombre, double precio) {
this.nombre = nombre;
this.precio = precio;
}
// Getters y otros métodos si son necesarios
}
ServicioPedido.java (Aplicación)
package restaurante.aplicacion;
import restaurante.dominio.Pedido;
import restaurante.puerto.RepositorioPedidos;
public class ServicioPedido {
private RepositorioPedidos repositorioPedidos;
public ServicioPedido(RepositorioPedidos repositorioPedidos) {
this.repositorioPedidos = repositorioPedidos;
}
public void guardar(Pedido pedido) {
repositorioPedidos.guardarPedido(pedido);
}
}
RepositorioPedidos.java (Puerto)
package restaurante.puerto;
import restaurante.dominio.Pedido;
public interface RepositorioPedidos {
void guardarPedido(Pedido pedido);
// Otros métodos si son necesarios, como obtenerPedido, eliminarPedido, etc.
}
RepositorioPedidosMemoria.java (Adaptador)
package restaurante.adaptadores;
import restaurante.dominio.Pedido;
import restaurante.puerto.RepositorioPedidos;
public class RepositorioPedidosMemoria implements RepositorioPedidos {
@Override
public void guardarPedido(Pedido pedido) {
// Implementación de guardar en memoria
}
// Implementación de otros métodos si son necesarios
}
Main.java (Main)
package restaurante.main;
import restaurante.adaptadores.RepositorioPedidosMemoria;
import restaurante.aplicacion.ServicioPedido;
import restaurante.dominio.Articulo;
import restaurante.dominio.Pedido;
public class Main {
public static void main(String[] args) {
RepositorioPedidosMemoria repositorio = new RepositorioPedidosMemoria();
ServicioPedido servicioPedido = new ServicioPedido(repositorio);
Articulo articulo = new Articulo("Pizza Margarita", 8.99);
Pedido pedido = new Pedido(articulo, 2);
servicioPedido.guardar(pedido);
// Otros códigos para iniciar la aplicación
}
}
Este código refleja la estructura de directorios y las responsabilidades de cada componente dentro de la arquitectura hexagonal.
Cada clase está ubicada en el paquete correspondiente, y las clases de dominio, aplicación, puerto, adaptadores y main se encargan de sus roles específicos dentro del sistema.
La arquitectura hexagonal, como cualquier patrón de diseño arquitectónico, tiene sus desventajas y limitaciones, que son importantes considerar al decidir si es apropiada para un proyecto específico. Algunas de las desventajas incluyen:
Cuando se aplica bien, a un caso que realmente la requiera, puede mejorar el proceso de desarrollo:
Como arquitectura hexagonal es una guía, un enfoque, no hay una única manera de implementarlo, y Amazon propone la siguiente estructura de carpetas o proyectos:
Acá se puede ver el artículo completo: Amazon Arquitectura Hexagonal
La arquitectura hexagonal mantiene un enfoque claro en cuanto a la separación de la lógica de negocio y los detalles de implementación, lo que lleva a sistemas más limpios, mantenibles y evolutivos, algo sumamente valioso en aplicaciones complejas y en entornos en los que se espera actualizar las tecnologías externas con el tiempo.