Aplica Rich Model en Clean Architecture para encapsular lógica de negocio y mejorar tu calidad de código 🐿️
Hey devs, en este artículo les enseñaré cómo pueden aplicar el principio de DDD "Rich model" a un proyecto cuando estás utilizando Clean Architecture, comencemos!
Introducción
Clean Architecture es un enfoque que organiza el código en capas concéntricas (dominio, aplicación, infraestructura, Presentation) para separar la lógica de negocio de los detalles técnicos, garantizando que las capas internas (como el dominio) no dependan de las externas (regla de dependencia).
Un error común en su implementación es el modelo anémico, donde las entidades son meras estructuras de datos y la lógica se dispersa en servicios o casos de uso, lo que genera acoplamiento y fragilidad. Para evitarlo, se recomienda aplicar el Rich Model (inspirado en Domain-Driven Design), donde las entidades encapsulan tanto datos como comportamiento (reglas de negocio), promoviendo cohesión y mantenibilidad.
Sin embargo, no todas las entidades deben ser complejas: en dominios sencillos, un modelo semi-anémico puede ser viable. Además, para maximizar su efectivo, el modelo rico debe complementarse con conceptos como agregados, value objects y repositorios bien diseñados (en este artículo te explico más esto). La clave está en equilibrar la riqueza del dominio con la simplicidad, siempre alineado con las necesidades del negocio y las capas definidas por Clean Architecture.
Qué es Rich Model?
Rich Model (o Modelo Rico) es un enfoque derivado del Domain-Driven Design (DDD) donde las entidades no solo almacenan datos, sino que también encapsulan la lógica de negocio asociada a su responsabilidad directa (por ejemplo, validaciones, cálculos o reglas específicas). Esto fortalece la cohesión y reduce la dispersión de lógica en servicios externos, evitando la duplicación y garantizando que las reglas de negocio sean únicas y mantenibles.
Por otro lado, el Anemic Model (Modelo Anémico), considerado un anti-patrón en DDD, separa radicalmente datos y lógica: las entidades actúan como meros DTOs (Data Transfer Objects), mientras que toda la lógica reside en servicios de aplicación. Esto genera alto acoplamiento, dificulta el seguimiento de reglas de negocio y puede derivar en código duplicado o inconsistente, especialmente en sistemas complejos.
Estructura de un Proyecto con Clean Architecture
En Clean Architecture, las capas principales son:
Domain: Contiene las entidades de negocio con su lógica y reglas.
Application: Contiene los casos de uso, que orquestan la aplicación pero no contienen lógica de dominio, sí contienen lógica de la aplicación.
Infrastructure: Implementa detalles técnicos como persistencia y proveedores externos.
Presentation: Maneja la interfaz con el usuario o las API controllers.
Para aplicar Rich Model, debemos centrarnos en la capa de Domain y asegurarnos de que la lógica de negocio esté en sus entidades.
Implementando Rich Model en Clean Architecture
Paso 1: Definir una entidad con Lógica de negocio
En lugar de una clase anémica como esta:
public class Order
{
public int Id { get; set; }
public decimal Total { get; set; }
public bool IsPaid { get; set; }
}
Aplicamos Rich Model incluyendo reglas de negocio:
public class Order
{
public int Id { get; private set; }
public decimal Total { get; private set; }
public bool IsPaid { get; private set; }
public Order(decimal total)
{
if (total <= 0)
throw new ArgumentException("El monto total debe ser mayor a 0.");
Total = total;
IsPaid = false;
}
public void Pay()
{
if (IsPaid)
throw new InvalidOperationException("La orden ya está pagada.");
IsPaid = true;
}
}
Paso 2: Emplea Value objects para mayor encapsulación
En DDD, los Value Objects ayudan a evitar estados inconsistentes. En lugar de manejar precios como decimal, podemos definir un tipo específico:
public record Money(decimal Amount)
{
public Money EnsurePositive()
{
if (Amount <= 0)
throw new ArgumentException("El monto debe ser entero positivo y mayor a cero.");
return this;
}
}
Y usarlo en Order:
public class Order
{
public Money Total { get; private set; }
public bool IsPaid { get; private set; }
public Order(Money total)
{
Total = total.EnsurePositive();
IsPaid = false;
}
}
Paso 3: Mantener la lógica del negocio en el dominio
Los casos de uso en la capa de Application deben orquestar el flujo o contener la lógica de la aplicacion (que no es lo mismo que la lógica del negocio) sin contener reglas de negocio:
public class PayOrderHandler
{
private readonly IOrderRepository _orderRepository;
public PayOrderHandler(IOrderRepository orderRepository)
{
_orderRepository = orderRepository;
}
public async Task Handle(int orderId)
{
var order = await _orderRepository.GetByIdAsync(orderId);
order.Pay();
await _orderRepository.UpdateAsync(order);
}
}
Beneficios de emplear Rich Model en Clean Architecture
✅ Encapsulación: La lógica está en el dominio y no dispersa en servicios.
✅ Consistencia: Se evitan estados inválidos al asegurar reglas en las entidades.
✅ Mantenibilidad: Las reglas de negocio están centralizadas y son fáciles de modificar.
✅ Independencia de infraestructura: Se evita el acoplamiento con ORMs o frameworks.
Conclusiones
Así que ya sabes dev, si estás implementando Clean Architecture, te recomiendo usar Rich Model para mantener la lógica de negocio en la capa de dominio. Aunque el modelo anémico es común en muchas implementaciones, el modelo rico es una opción más robusta y alineada con los principios de DDD y Clean Architecture.
Ahora que sabes esto, sal con tus amigos a divertirte. Foto de Helena Lopes en Unsplash