Table of Contents
En el campo del desarrollo de software, los microservicios, la arquitectura hexagonal y el DDD (Domain Driven Design) son los temas más populares.
Estos paradigmas son ahora el sello distintivo de las aplicaciones empresariales escalables, mantenibles y sólidas. Pero cada vez hay más malentendidos: Para utilizar arquitectura hexagonal o DDD es necesario utilizar microservicios.
Este mito ha llevado a muchos desarrolladores a elegir sistemas complejos y distribuidos porque creen que son la única forma de conseguir una arquitectura limpia y modelar un dominio correctamente. El hecho es que ni siquiera se necesitan microservicios para utilizar la arquitectura hexagonal o el DDD. Estos patrones son independientes de los modelos de implementación, pero se basan en principios de diseño.
Y podemos acabar con un monolito modular y seguir recibiendo todas las ventajas de estos patrones arquitectónicos sin añadir el coste y la complejidad de un sistema distribuido.
Este artículo disipará el mito, pasando por la arquitectura hexagonal y el DDD incluso sin la presencia de microservicios, e ilustrando cómo los monolitos, cuando se hacen bien, son igual de potentes.
Ahora, echemos un vistazo a la arquitectura hexagonal y a el DDD e inspeccionemos cuáles son sus principios básicos antes de ver cómo se aplican estos conceptos al más allá de los microservicios.
Arquitectura hexagonal y el DDD
¿Qué es el DDD?
El diseño orientado al dominio (DDD) es una tecnología de desarrollo de aplicaciones informáticas que aúna lo técnico y el dominio. El objetivo es implantar en el software reglas empresariales y flujos de trabajo complejos basados en comportamientos y conceptos del mundo real.
Los elementos clave de el DDD son los siguientes
- Entidades: Objetos con una identidad propia que persiste en el tiempo.
- Objetos de valor: Objetos inmutables que describen aspectos del dominio.
- Agregados: Agrupaciones de entidades y objetos de valor tratados como una sola unidad.
- Repositorios: Abstracciones para recuperar y almacenar agregados.
- Eventos de dominio: Eventos que reflejan algo importante ocurrido en el dominio.
- Contextos delimitados: Límites explícitos dentro de los cuales se define y aplica un determinado modelo de dominio.
DDD trata de un lenguaje común, entendimiento y modularidad, no de cómo se construye el software.
¿Qué es la arquitectura hexagonal?
La arquitectura hexagonal (o de puertos y adaptadores) fue concebida por primera vez por Alistair Cockburn como una metáfora espacial para ayudar a describir interfaces independientes para una aplicación desde su implementación y uso. El punto principal es tener una arquitectura limpia no atada a la entrega (HTTP APIs, UIs), persistencia (bases de datos), y completamente comprobable.
La arquitectura consta de:
- Núcleo (Interior): El modelo de dominio y las reglas de negocio.
- Puertos: Interfaces que definen cómo se comunica el núcleo con el mundo exterior.
- Adaptadores (externos): Implementaciones de los puertos que conectan la aplicación a bases de datos, APIs, UIs, etc.
Esto permite un sistema extremadamente modular y flexible en el que las normas empresariales están separadas de los aspectos técnicos.
Esto permite a los desarrolladores:
- Sustituye piezas de infraestructura sin afectar a la lógica empresarial.
- Prueba únicamente la lógica empresarial.
- Mantén los temas separados.
Tampoco hay nada aquí que requiera microservicios. Se trata de una estructura, no de una implementación.
¿Por qué la confusión?
La aparición de la computación nativa en la nube y el movimiento DevOps ha hecho de los microservicios la arquitectura estándar para construir software escalable. Mucha información y discusiones tienden a agrupar DDD y arquitectura hexagonal, así como microservicios, por lo que la asociación es algo implícito.
Pero esta relación es correlacional, no causal.
- DDD y la arquitectura hexagonal son especialmente adecuadas para los microservicios porque permiten hacer frente a la complejidad y mantener una separación de preocupaciones.
- Dicho esto, los microservicios no son DDD ni arquitectura hexagonal.
En realidad, el intento de DDD y la arquitectura hexagonal en la mayoría de las arquitecturas de servicios distribuidos es a menudo suficiente para causar más dolor del que resuelve si no conoces el dominio bastante bien. La orquestación compleja, la consistencia de datos complicada y la depuración difícil se convierten en la nueva normalidad.
Desmontando el mito de los microservicios
1. La arquitectura hexagonal y el DDD se centran en la modularidad, no en la distribución.
Pros y contras de la arquitectura hexagonal. Esto significa que dividir la aplicación en diferentes servicios no es la única manera. Lo mismo ocurre con DDD – los contextos delimitados son una definición de límites lógicos, no son necesariamente límites físicos de servicio.
2. Las aplicaciones monolíticas se benefician de los principios DDD y hexagonal.
- El beneficio de tener monolitos bien implementados con arquitectura hexagonal y DDD es:
- Mejor separación de preocupaciones: la lógica del dominio es independiente de otros sistemas.
- Mejor capacidad de prueba: Las reglas de negocio pueden probarse sin base de datos ni API.
- Reducción del mantenimiento y los dolores de cabeza: Un modelo de dominio limpio es más fácil de refactorizar.
- Transición a los servicios a lo largo del tiempo: La modularidad dentro de un monolito es un camino hacia los microservicios a medida que un sistema evoluciona.
3. Los microservicios introducen complejidad
Sin embargo, los microservicios tienen sus propios retos:
- Complejidad operativa: necesita orquestar, registrar y supervisar muchos servicios diferentes.
- Consistencia distribuida: Las transacciones entre microservicios implican patrones para el patrón Saga.
- Gastos de infraestructura: Los servicios adicionales aumentan los costes de implantación y mantenimiento.
Personalmente, creo que para la mayoría de los proyectos, empezar con un monolito bien organizado es mejor que con microservicios.
El caso del monolito modular
El monolito modular es el sistema desplegado como un todo, pero con una clara costura entre sus distintos componentes y con separación a nivel lógico. Cada módulo representa un dominio/subdominio y sigue los principios de la arquitectura DDD y hexagonal.
Ventajas:
- Simplicidad: Todo muy sencillo para depurar, probar, desplegar y supervisar.
- Rendimiento en tiempo de ejecución: Sin llamadas de red entre módulos.
- Cohesión: Puedes seguir teniendo modelos de dominio ricos y contextos delimitados.
- Evolución: Los módulos pueden evolucionar a microservicios siempre y cuando sea necesario.
Lo que empieza con un monolito modular:
- Prueba tu modelo de dominio.
- Manténlo limpio, literalmente.
- Simplificar la infraestructura.
Si tu equipo no puede comprender la complejidad de un monolito modular, no está preparado para los microservicios.
Implantación de la arquitectura hexagonal y el DDD en un sistema monolítico
1. Definir contextos claramente delimitados
Incluso las bases de código monolíticas deberían definir Contextos acotados para organizar bien la lógica del dominio. Por ejemplo:
- Contexto de gestión de usuarios (gestiona la autenticación y los perfiles de los usuarios)
- Contexto de procesamiento de pedidos (gestiona pedidos, pagos y envíos)
- Contexto de facturación (gestiona facturas y transacciones financieras)
Debe haber un modelo de dominio por Contexto Delimitado, que debe estar aislado de otros modelos de dominio.
2. Utiliza puertos y adaptadores para mayor flexibilidad
Introducir puertos y adaptadores para separar la lógica empresarial de la infraestructura.
Ejemplo:
Define un puerto (interfaz):
public interface IOrderRepository
{
void Save(Order order);
Order FindById(Guid orderId);
}
Implanta un adaptador (capa de infraestructura):
public class OrderRepository : IOrderRepository
{
private readonly DbContext _context;
public OrderRepository(DbContext context)
{
_context = context;
}
public void Save(Order order) => _context.Orders.Add(order);
public Order FindById(Guid orderId) => _context.Orders.Find(orderId);
}
De este modo, la lógica principal del dominio sólo depende de las interfaces y no de las implementaciones reales de la base de datos.
3. Separar la lógica de aplicación de la lógica de dominio
Se supone que la orquestación de casos de uso debe ser gestionada por los Servicios de Aplicación, pero las reglas de negocio pertenecen al modelo de dominio.
public class OrderService
{
private readonly IOrderRepository _orderRepository;
public OrderService(IOrderRepository orderRepository)
{
_orderRepository = orderRepository;
}
public void PlaceOrder(Guid customerId, List<OrderItem> items)
{
var order = new Order(customerId, items);
_orderRepository.Save(order);
}
}
4. Garantiza la comprobabilidad con la inyección de dependencias
Separar la lógica de negocio de la infraestructura hace posible la prueba unitaria de la lógica de dominio en la separación.
[Fact]
public void Should_Create_Order_Successfully()
{
var repositoryMock = new Mock<IOrderRepository>();
var service = new OrderService(repositoryMock.Object);
service.PlaceOrder(Guid.NewGuid(), new List<OrderItem> { new OrderItem("Product1", 2) });
repositoryMock.Verify(r => r.Save(It.IsAny<Order>()), Times.Once);
}
Cuándo (y cómo) evolucionar a los microservicios
Si tu monolito ha sido diseñado adecuadamente -arquitectura DDD y hexagonal por ejemplo- la extracción a microservicios será más sencilla:
- Descubre contextos delimitados que cambian a ritmos diferentes.
- Extraerlos como servicios independientes con la infraestructura de dominios y adaptadores que ya existe.
- Introduce la comunicación de servicios (REST, mensajería, etc.).
- Y garantizar la atomicidad si necesita utilizar el evento o transacciones distribuidas.
Pero no lo hagas demasiado pronto. Extraiga sólo cuando:
- La escalabilidad tiene un límite evidente.
- La frecuencia de despliegue de un módulo a otro varía.
- El módulo también es estable y valioso por sí mismo.
Conclusión
Cuando diseñas tus soluciones de software utilizando arquitectura hexagonal y DDD, puedes hacerlas más potentes y fáciles de mantener de forma estructurada y organizada. Pero son filosofías de diseño, no planes de implantación.
No es necesario adoptar inmediatamente los microservicios para disfrutar de las ventajas de estos patrones. Puedes hacer un monolito que sea fácil de gestionar y probar siguiendo los principios de DDD, que es una forma de diseñar software que se centra en el dominio o el problema que resuelve el software. Empezar con un monolito modular bien diseñado no sólo es suficiente, sino que a menudo es el enfoque óptimo. Este método permite a los equipos desarrollar un conocimiento profundo del tema, definir límites precisos y retrasar los costosos gastos relacionados con los sistemas distribuidos hasta que sean necesarios.
Los microservicios pueden dar lugar a un sistema complejo y disperso, por lo que sólo deben utilizarse cuando sea necesario. Cuando utilizas contextos delimitados, puertos, adaptadores y un modelo de dominio bien definido, puedes hacer monolitos modulares que pueden convertirse en microservicios cuando sea necesario.
– Evita que tu dominio se vea envuelto en problemas de infraestructura.
– Aumenta la capacidad de prueba y la flexibilidad.
– Prepara el escenario para un cambio fluido a microservicios cuando el momento lo requiera.
La forma de diseñar el software, tanto si se trata de un único gran sistema como de muchos más pequeños, influye mucho en su funcionamiento. En resumen, da prioridad a la creación de un sistema bien estructurado antes de implantar uno distribuido. Empieza por lo sencillo y amplíalo según sea necesario.
Si estás interesado en aprender más sobre arquitectura de software, no deje de consultar ApiumAcademy, que ofrece cursos y talleres especializados para empresas que buscan reforzar sus equipos técnicos.
Author
-
I am a Computer Engineer by training, with more than 20 years of experience working in the IT sector, specifically in the entire life cycle of a software, acquired in national and multinational companies, from different sectors.
View all posts
More to Explore