Los agregados son uno de los conceptos más difíciles en DDD. Usted tiene la mayor parte de la razón. Sugiero que expresar el concepto en términos de "membresía" en un agregado sea más sencillo que introducir el término "subobjetos".
Sí, un objeto no puede ser miembro de más de un agregado. ¿Cuál sería el ejecutor final? Una raíz agregada podría invalidar fácilmente otra al eliminar miembros y al orfanar a otros miembros en el otro agregado. Está en lo correcto, en los escenarios donde un objeto parece necesitar membresía en múltiples agregados, ese objeto debe ser una entidad independiente, es decir, se convierte en la raíz de un agregado nuevo. (Puede o no tener miembros adicionales, pero si no lo hace, por supuesto, se convierte en su propio agregado de uno).
Y sí, es absolutamente cierto que existe un agregado para imponer invariantes. También es una sola unidad de trabajo o una sola transacción en términos de persistencia. Una raíz agregada es en última instancia responsable de todas las invariantes en toda su membresía, debe ser porque, por ejemplo, la falla de un invariante puede provocar la falla de la persistencia, y el agregado es responsable de mantener el agregado como una sola unidad viable de trabajo de persistencia .
Sin embargo, y esta es la parte sutil y difícil, que la responsabilidad última no implica que el agregado es también el principal ejecutor también. Al igual que lo que tenemos en el sistema judicial, el tribunal es en última instancia el lugar final donde se determinan los asuntos de derecho y donde se impone la regla de la ley final, se aplica el invariante. Pero la aplicación real (y el cumplimiento) ocurre en muchos niveles del sistema. De hecho, en una sociedad bien ordenada, la mayoría de las actividades que imponen el imperio de la ley -la aplicación de las invariantes- deben ocurrir mucho antes de que llegue al tribunal, y usted no debería tener que depender de ir al tribunal de manera rutinaria. (Aunque en DDD siempre querrá tener una raíz agregada, realice un barrido invariante final antes, por ejemplo, persistencia).
Lo que está sugiriendo es bastante diferente, esencialmente toda la sociedad a excepción del tribunal está encarcelado, y usted parece incluso proponer que otros ni siquiera puedan visitar, solo pueden transmitir un mensaje al tribunal y esperar que actúe de manera apropiada.
Veamos lo que le sucede a su dominio si sigue el camino que ha sugerido. El objetivo es crear un modelo de dominio rico y expresivo.En términos del lenguaje omnipresente significativo, ha reducido su vocabulario de trabajo a solo las raíces agregadas. Se supone que una entidad debe ser accedida por la raíz agregada debido a invariantes, pero también porque si el diseño es correcto, la entidad tiene una identidad significativa que surge de su membresía dentro del contexto de su raíz agregada. Pero su propuesta una entidad ni siquiera tiene identidad de tipo fuera de su raíz global. Evans dice específicamente que es parte del propósito de una raíz agregada: permitir que los objetos obtengan referencias a los miembros por cruce. Pero no puede obtener una referencia útil porque otro objeto ni siquiera es consciente de que existen sus tipos de miembro. O puede alterar los espacios de nombres, pero eso no es mejor si no permite el cruce. Ahora su dominio completo conoce los tipos, pero los tipos de objetos que nunca se pueden obtener.
Peor aún es lo que le sucede a su raíz agregada. Una raíz agregada generalmente debe tener su propio motivo de existencia, además de mantener la integridad global. Pero ahora esa identidad ya no está clara. Está oscurecido por la necesidad de tener un método de envoltura para todos los diversos elementos y sus atributos. Lo que obtienes son raíces agregadas que ya no tienen una expresividad o incluso una identidad clara, solo grandes objetos difíciles de Dios.
Su ejemplo de Order y OrderLine es un caso interesante. La orden no está proporcionando el cumplimiento de alguna invariante requerida por OrderLine en nombre de OrderLine. Está controlando la acción en este caso para hacer cumplir su propia invariante. Esa es una acción válida para poner el control de la raíz de agregado. Sin embargo, más típicamente los agregados están principalmente relacionados con la creación y/o destrucción de objetos.
No hay ningún requisito para imponer un modelo donde todos los cambios de estado se deben aplicar automáticamente por la raíz agregada y nunca directamente. De hecho, esto es a menudo por lo que la raíz agregada permite el cruce para obtener referencias a miembros, por lo que un objeto externo puede aplicar un cambio de estado, pero en un contexto donde el agregado controla el ciclo de vida de la entidad miembro que se está modificando.
No solo la visibilidad, sino también la interacción real con el dominio más grande a menudo es fundamental para desarrollar un modelo rico y expresivo. El agregado sirve para controlar ese acceso, pero no para eliminarlo por completo.
Espero que esto ayude, es un concepto difícil de discutir.
¿Podría elobarate lo que quiere decir con "subobjetos"? ¿Te refieres a las implementaciones concretas de tus entidades? ¿Consideraste las clases privadas anidadas para lograr la separación limpia? –
+1, Interesante, pero la pregunta no fue clara inmediatamente cuando la leí. ¿Podrías reformularlo un poco y cambiar el título? Esta es la pregunta que destilé: ¿Cómo logro una separación limpia entre las raíces agregadas en el mismo ensamblaje .NET? – Marijn