En el tema anterior vimos que un agregado define un límite de consistencia. Dentro de ese límite puede haber entidades internas y objetos de valor, pero desde afuera debe existir un punto principal de acceso. Ese punto es la raíz de agregado.
La raíz de agregado es la entidad que representa al agregado completo frente al resto del modelo. Su responsabilidad principal es controlar las operaciones que modifican el agregado y proteger las reglas internas. Sin una raíz clara, el agregado puede quedar expuesto a cambios desordenados que rompen invariantes.
La raíz de agregado es la entidad principal de un agregado. Tiene identidad propia y es el único objeto del agregado que debería ser referenciado directamente desde afuera. Las demás entidades internas existen dentro del límite y se manipulan a través de la raíz.
Por ejemplo, si Pedido es la raíz, el resto del sistema no debería modificar directamente Ítems de pedido. Debe pedirle al Pedido que agregue, quite o cambie ítems, para que el pedido pueda validar cantidades, estado y total.
La responsabilidad principal de la raíz es proteger la consistencia del agregado. Esto incluye validar invariantes, controlar cambios internos, coordinar entidades internas y exponer operaciones con significado de negocio.
Una raíz no debe ser solo un contenedor pasivo. Si no controla nada y todas las reglas están afuera, el agregado pierde valor. Tampoco debe absorber reglas que pertenecen a otros agregados o servicios de dominio.
El acceso controlado significa que las modificaciones importantes del agregado pasan por la raíz. Esto evita que una parte externa altere una entidad interna sin aplicar reglas.
Por ejemplo, en un agregado Agenda, no conviene que un componente externo inserte una Franja horaria directamente. La operación debería ser algo como "agregar franja a agenda", para que Agenda revise superposición, vigencia, estado de publicación y otras reglas.
Pedido puede ser raíz de un agregado que contiene Ítems de pedido y valores como Total, Dirección de entrega o Estado. Las operaciones externas pueden ser Agregar ítem, Quitar ítem, Confirmar pedido o Cancelar pedido.
Cada operación debe respetar reglas. No se puede confirmar un pedido vacío. No se puede modificar un pedido enviado. No se puede agregar un ítem con cantidad inválida. La raíz Pedido protege esas reglas antes de cambiar su interior.
Agenda puede ser raíz cuando controla Franjas horarias, bloqueos y publicación. Desde afuera se solicita agregar una franja, bloquear un período o publicar la agenda. La raíz decide si la operación es válida.
Si Agenda protege el invariante de franjas sin superposición, ninguna operación externa debería saltear esa validación modificando franjas internas de forma directa.
La raíz tiene identidad propia porque representa al agregado completo. Cuando otro agregado necesita referenciarlo, normalmente referencia a la raíz, no a una entidad interna. Por ejemplo, un Turno puede referenciar una Agenda o una Franja según el modelo, pero si Franja es interna de Agenda, conviene revisar si esa referencia externa rompe el límite.
Esta decisión no es puramente técnica. Depende de si la entidad interna tiene significado independiente para el dominio y de qué reglas debe proteger el agregado.
Las entidades internas pueden tener identidad dentro del agregado, pero esa identidad no necesariamente se expone fuera de él. Un Ítem de pedido puede distinguirse dentro de un Pedido, pero normalmente no se busca ni se modifica como entidad independiente desde afuera.
La identidad interna sirve para organizar el agregado; la raíz conserva el control del conjunto.
Las operaciones de la raíz deben nombrarse con lenguaje del negocio. En lugar de exponer cambios genéricos como "setEstado" o "actualizarLista", conviene expresar acciones significativas: Confirmar pedido, Cancelar turno, Publicar agenda, Agregar franja o Registrar atención.
Los nombres claros ayudan a que las reglas queden cerca de las acciones que realmente tienen sentido para el dominio.
Cuando una operación importante se completa, la raíz puede producir eventos de dominio. Por ejemplo, Pedido confirmado, Agenda publicada, Turno cancelado o Franja bloqueada. Estos eventos representan hechos ocurridos después de validar reglas internas.
No todos los cambios internos necesitan evento. Conviene producir eventos cuando el hecho tiene importancia para el negocio o para otros procesos.
Una raíz puede colaborar con servicios de dominio cuando la operación requiere reglas que involucran varios agregados o conceptos externos. Por ejemplo, Agenda puede controlar sus franjas, pero un Calculador de disponibilidad puede coordinar agendas, turnos existentes, especialidades y bloqueos.
La raíz no debe convertirse en un objeto gigante que conoce todo el sistema. Debe proteger su propio límite y colaborar cuando una regla excede ese límite.
La siguiente tabla muestra raíces y responsabilidades posibles:
| Raíz de agregado | Elementos internos | Responsabilidad principal |
|---|---|---|
| Pedido | Ítems, total, estado. | Proteger reglas de confirmación, total y cambios permitidos. |
| Agenda | Franjas horarias, bloqueos. | Evitar superposiciones y controlar publicación. |
| Turno | Estado, franja, datos de reserva. | Controlar transiciones válidas del turno. |
| Factura | Detalles, importes, impuestos. | Mantener coherencia legal y económica. |
| Cuenta | Movimientos, saldo. | Proteger reglas de saldo y movimientos válidos. |
Estas preguntas ayudan a decidir cuál debe ser la raíz:
Algunas señales indican que la raíz puede estar mal elegida:
Al trabajar con raíces de agregado, suelen aparecer estos errores:
La raíz de agregado es la puerta de entrada al agregado y la responsable de mantener sus reglas internas. Elegirla bien permite controlar cambios, proteger invariantes y expresar operaciones significativas del negocio. Elegirla mal puede producir modelos frágiles, con reglas dispersas o agregados demasiado grandes.
En el próximo tema estudiaremos los repositorios conceptuales, que permiten recuperar y persistir agregados sin mezclar el modelo de dominio con detalles tecnológicos.