quickly example driven domain ddd domain-driven-design aggregate root entities

domain driven design - example - Lo que pertenece a la raíz agregada



domain driven design pdf (7)

Depende. ¿Algún cambio / adición / eliminación de una violación cambia alguna parte del empleado? Por ejemplo, ¿está almacenando recuento de violación o recuento de violación dentro de los últimos 3 años contra el empleado?

Esta es una pregunta práctica de Diseño Dirigido por el Dominio:

Conceptualmente, creo que obtengo raíces Agregadas hasta que voy a definir una.

Tengo una entidad Employee, que ha surgido como una raíz de agregado. En el Negocio, algunos empleados pueden tener Violaciones relacionadas con el trabajo registradas en su contra:

Empleado ----- * Violaciones

Dado que no todos los empleados están sujetos a esto, creo que las violaciones no serían parte del agregado de empleados, ¿correcto?

Entonces, cuando quiero trabajar con empleados y sus violaciones relacionadas, ¿son estas dos interacciones separadas del repositorio por parte de algún servicio?

Por último, cuando agrego una violación, ¿es ese método en la entidad del empleado? ¡Gracias por la ayuda!


Después de hacer MÁS investigación, creo que tengo la respuesta a mi pregunta.

Paul Stovell tuvo esta respuesta ligeramente editada a una pregunta similar en el tablero de mensajes DDD . Sustituya "Cliente" por "Empleado" y "Orden" por "Infracción" y obtendrá la idea.

El hecho de que el Cliente haga referencia al Pedido no significa necesariamente que el Pedido esté dentro de la raíz del agregado del Cliente. Las direcciones del cliente podrían, pero las órdenes pueden ser independientes (por ejemplo, podría tener un servicio que procese todas las nuevas órdenes sin importar quién sea el cliente. Tener que ir al Cliente-> Pedidos no tiene sentido en este escenario).

Desde el punto de vista del dominio, incluso puede cuestionar la validez de esas referencias (el Cliente tiene referencia a una lista de Pedidos). ¿Con qué frecuencia necesitará todos los pedidos de un cliente? En algunos sistemas, tiene sentido, pero en otros, un cliente puede hacer muchos pedidos. Lo más probable es que desee pedidos para un cliente entre un rango de fechas, o pedidos para un cliente que aún no se hayan procesado, o pedidos que no se hayan pagado, y así sucesivamente. El escenario en el que los necesitará a todos podría ser relativamente poco común. Sin embargo, es mucho más probable que al tratar con un Pedido, desee la información del cliente. Por lo tanto, en el código, Order.Customer.Name es útil, pero Customer.Orders[0].LineItem.SKU - probablemente no tan útil. Por supuesto, eso depende totalmente del dominio de tu negocio.

En otras palabras, Actualizando Cliente no tiene nada que ver con la actualización de Pedidos. Y las órdenes o infracciones en mi caso podrían concebirse independientemente de Clientes / Empleados.

Si las infracciones tuvieran líneas de detalle, entonces la línea de Violación y Violación sería una parte del mismo agregado porque cambiar una línea de infracción probablemente afectaría una Infracción.

EDITAR ** La arruga aquí en mi dominio es que las violaciones no tienen ningún comportamiento. Básicamente son registros de un evento que sucedió. Aún no estoy seguro sobre las implicaciones que tiene.


Eric Evan afirma en su libro, Diseño impulsado por el dominio: abordar la complejidad en el corazón del software ,

Un AGREGADO es un conjunto de objetos asociados que tratamos como una unidad con el propósito de cambios en los datos .

Hay 2 puntos importantes aquí:

  1. Estos objetos deben tratarse como una "unidad".
  2. Con el propósito de "cambio de datos".

Creo en su escenario, Empleado y Violación no son necesariamente una unidad juntos, mientras que en el ejemplo de Order y OrderItem, son parte de una sola unidad.

Otra cosa que es importante al modelar los límites agregados es si tiene invariantes en su agregado. Los invariantes son reglas comerciales que deberían ser válidas dentro del agregado "total". Por ejemplo, en cuanto al ejemplo de Order y OrderItem, puede tener un invariante que indique que el costo total del pedido debe ser menor que un importe predefinido. En este caso, cada vez que desee agregar un artículo de pedido al pedido, este invariante debe aplicarse para asegurarse de que su pedido sea válido. Sin embargo, en su problema, no veo invariantes entre sus entidades: Empleado y Violación.

Respuesta tan corta:

Creo que Employee and Violation cada uno pertenece a 2 agregados separados. Cada una de estas entidades son también sus propias raíces agregadas. Entonces necesita 2 repositorios: EmployeeRepository y ViolationRepository.

También creo que debes tener una asociación unidireccional de Violación a Empleado. De esta forma, cada objeto de Violación sabe a quién pertenece. Pero si desea obtener la lista de todas las infracciones para un empleado en particular, puede solicitarla al ViolationRepository:

var list = repository.FindAllViolationsByEmployee(someEmployee);


Generalmente estoy de acuerdo con Mosh en este caso. Sin embargo, tenga en cuenta la noción de transacciones desde el punto de vista comercial. Por lo tanto, tomo "con el propósito de cambios en los datos" en el sentido de "con el propósito de transacción (es)".

Los repositorios son vistas del modelo de dominio. En un entorno de dominio, estas "vistas" realmente respaldan o representan una función o capacidad comercial: una transacción. Por ejemplo, el Empleado puede tener una o más infracciones, y si es así, son aspectos de una transacción (es) en un punto en el tiempo. Considere sus casos de uso.

Escenario: "Un empleado comete un acto que es una violación del lugar de trabajo". Este es un tipo de evento comercial (es decir, transacción, o parte de una transacción mayor, tal vez distribuida) que ocurrió. El objeto raíz del dominio afectado en realidad se puede ver desde más de una perspectiva, por lo que es confuso. Pero lo que hay que recordar es el comportamiento en lo que respecta a una transacción comercial, ya que desea que sus procesos comerciales modelen el mundo real de la manera más precisa posible. En términos de relaciones, al igual que en una base de datos relacional, su modelo de dominio conceptual ya debería indicar esto (es decir, la asociatividad), que a menudo se puede leer en cualquier dirección:

Empleado <---- comete un ------- cometido por ----> Violación

Entonces, para este caso de uso, sería justo decir que se trata de una transacción que trata con violaciones, y que la raíz - o entidad "primaria" - es una Violación. Eso, entonces, sería su raíz agregada a la que haría referencia para esa actividad empresarial o proceso comercial en particular. Pero eso no quiere decir que, para una actividad o proceso diferente, no pueda tener una raíz agregada de Empleado, como el "nuevo proceso de empleado". Si se cuida, no debería haber un impacto negativo de las referencias cíclicas, o ser capaz de atravesar su modelo de dominio de múltiples maneras. Advertiré, sin embargo, que el control de esto debe ser pensado y manejado por su parte controladora de su dominio comercial, o cualquier equivalente que tenga.

Aparte: Pensando en términos de patrones (es decir, MVC), el repositorio es una vista, los objetos de dominio son el modelo, y por lo tanto uno también debería emplear alguna forma de patrón de controlador. Típicamente, el controlador declara la implementación concreta y el acceso a los repositorios (colecciones de raíces agregadas).

En el mundo de acceso a datos ...

Usando LINQ-To-SQL como ejemplo, DataContext sería el controlador que expondría una vista de las entidades de Cliente y Orden. La vista es un tipo de tabla orientada al marco no declarativa (equivalente aproximado al repositorio). Tenga en cuenta que la vista guarda una referencia a su controlador principal y, a menudo, pasa por el controlador para controlar cómo y cuándo se materializa la vista. Por lo tanto, el controlador es su proveedor, que se encarga de la cartografía, la traducción, la hidratación de objetos, etc. El modelo es entonces su POCO de datos. Prácticamente un patrón típico de MVC.

Utilizando N / Hibernate como ejemplo, la ISession sería el controlador que expondría una vista de las entidades Customer y Order a través de la sesión. Inumerable (string query) o session.Get (object id) o session.CreateCriteria (typeof (Customer) ).Lista()

En el mundo de la lógica de negocios ...

Customer { /*...*/ } Employee { /*...*/ } Repository<T> : IRepository<T> , IEnumerable<T> //, IQueryable<T>, IQueryProvider //optional { /**/ } BusinessController { Repository<Customer> Customers { get{ /*...*/ }} //aggregate root Repository<Order> Orders { get{ /*...*/ }} // aggregate root }

En pocas palabras, permita que sus procesos de negocio y transacciones sean la guía, y permita que su infraestructura empresarial evolucione de forma natural a medida que los procesos / actividades se implementan o refactorizan. Además, prefiere la capacidad de compilación sobre el diseño tradicional de caja negra. Cuando llegue a la informática orientada a servicios o en la nube, se alegrará de haberlo hecho. :)


Me preguntaba cuál sería la conclusión?

Las ''violaciones'' se convierten en una entidad raíz. Y las ''violaciones'' serían referenciadas por la entidad raíz ''empleado''. es decir, repositorio de violaciones <-> repositorio de empleados

Pero no está seguro de convertir las violaciones en una entidad raíz porque no tiene ningún comportamiento.

Pero, ¿el ''comportamiento'' es un criterio para calificar como una entidad raíz? No lo creo.


Usted dice que tiene infracciones y entidades de empleados y que cada infracción no tiene ningún comportamiento en sí mismo. Por lo que puedo leer arriba, me parece que puede tener dos raíces agregadas:

  • Empleado
  • EmployeeViolations (llámelo EmployeeViolationCard o EmployeeViolationRecords)

EmployeeViolations se identifica con la misma ID de empleado y contiene una colección de objetos de violación. Obtienes comportamiento por empleado y violaciones separadas de esta manera y no obtienes entidad Violación sin comportamiento.

Ya sea que la violación sea una entidad o un objeto de valor, debe decidir en función de sus propiedades.


una pregunta ligeramente ortogonal para probar la comprensión aquí, volviendo al orden ... Ejemplo de OrderItem, puede haber un módulo analítico en el sistema que quiera buscar directamente en OrderItems, es decir, obtener todos los artículos de pedido para un producto en particular o todos los artículos de pedido superiores a algún valor dado, etc., si tener un montón de casos de uso así y conducir "raíz agregada" al extremo podríamos argumentar que OrderItem es una raíz agregada diferente en sí misma?