Cómo se deben manejar los comandos Agregar / Crear * en la arquitectura CQRS + Event Sourcing

11

Quiero implementar mi primera aplicación usando el patrón CQRS junto con Event Sourcing. Me pregunto cómo se debe manejar adecuadamente la creación de raíces agregadas. Digamos que alguien envía el comando CreateItem. ¿Cómo se debe manejar? ¿Dónde debe almacenarse el evento ItemCreated? ¿Como primer evento de un nuevo artículo? ¿O debería tener algún tipo de entidad ItemList que agregue todos los elementos y su lista de eventos consista solo en eventos ItemCreated?

Udi Dahan sugiere no crear raíces agregadas y usar siempre algún tipo de método de recuperación. Pero cómo puedo obtener algo que es nuevo y ciertamente no tiene ninguna identificación asignada. Entiendo la idea detrás y es bastante razonable pensar que un nuevo objeto es un objeto que tiene su estado compuesto de cero eventos respondidos. ¿Pero cómo debo usarlo? ¿Debería tener un método distinto en mi repositorio getNewItem()o hacer que mi get(id)método acepte en su Optional<ItemId>lugar?

Editar: Después de un tiempo de excavación, encontré una implementación realmente interesante de los patrones antes mencionados utilizando actores. El autor, en lugar de crear el agregado, lo recupera de algún tipo de repositorio con UUID recién creado. El inconveniente de este enfoque es que permite un estado de inconsistencia temporal. También me pregunto cómo puedo implementar el deletemétodo con ese enfoque. ¿Simplemente agregue Evento eliminado a la lista de eventos del agregado?

Mequrel
fuente
1
Sospecho que el post-título de Udi es engañoso. En mi humilde opinión, parece que su objetivo real es que los AR recién hechos siempre deben ser accesibles desde otro lugar, de una manera que capture el contexto sobre por qué / cómo / quién decidió que era necesario crear el nuevo AR. Todo lo demás se trata de cómo una implementación particular (¿NHibernate?) Podría facilitar su administración.
Darien
2
Tenga en cuenta que el artículo de Udi Dahan al que hace referencia específicamente menciona que su consejo puede no aplicarse al abastecimiento de eventos: udidahan.com/2009/06/29/dont-create-aggregate-roots/…
EZ Hart

Respuestas:

13

La idea en la publicación de Udi, según tengo entendido, es que ningún tipo de artículo aparece de la nada. Hay (casi) siempre algo, o más específicamente, alguna operación de dominio, que causó la creación del elemento. Al igual que el ejemplo de Udi de un usuario que realmente nació de un visitante que se registra en el sitio. En ese punto y en ese contexto acotado, Visitor es la raíz agregada, que es recuperada por su dirección IP. Este visitante crea el nuevo "elemento", un usuario en este punto, a través de una operación de dominio llamada Registro . Lo mismo ocurre con el paso anterior, que es otro contexto acotado: el referente es el AR, que es recuperado por la URL y que tiene una operación de dominio llamada BroughtVisitorWithIp , donde nace el visitante.

Udi también escribe muy bien sobre la eliminación: http://www.udidahan.com/2009/09/01/dont-delete-just-dont/ . La idea principal es que nunca elimines nada. Siempre hay una operación de dominio detrás, que queremos capturar. Como un pedido que se cancela, en lugar de eliminarse. Léelo, es una muy buena publicación.

El punto principal aquí en ambas cuentas, haciendo DDD y especialmente Event Sourcing, es que nunca debes hacer operaciones CRUD directas. Si se encuentra en una situación en la que realmente necesita insertar, actualizar o eliminar algunos datos, y realmente no hay una operación de dominio detrás de ellos, entonces tal vez DDD y Event Sourcing no sean una buena opción para ese contexto limitado . Usted es libre de combinar estos dos como desee, siempre y cuando un contexto limitado se adhiera a un principio. De esta forma, el contexto acotado de estilo CRUD podría crear una fila en la base de datos, que se convierte en una entidad y una raíz Agregada en otro contexto acotado, donde ahora puede recuperar el AR y no tener que crearlo.

Tuukka Haapaniemi
fuente
2
"Quizás DDD y Event Sourcing no encajen bien en ese contexto limitado". Entiendes bien el punto de DDD. No debe implementarse en todos los casos solo para la gloria de Satanás, sino solo cuando uno necesita lidiar con un dominio complejo lleno de reglas inciertas. Personalmente, lo hice para software legal donde los requisitos no están impulsados ​​por la lógica.
Yegor Chumakov
2
+1 solo para esta oración "para ese contexto acotado". :)
Songo
2
+1 el uso de los verbos 'Agregar' y 'Crear' sugiere que todavía estás pensando en tu dominio en términos de interacción con una buena base de datos tabular. Sin conocer su dominio / contexto acotado, no puedo decir si esto es apropiado o no. Ignore la persistencia, enfóquese primero en los COMANDOS y EVENTOS (también conocidos como INTENCIONES y RESULTADOS) que son exclusivos de su dominio, luego preocúpese por cómo persistir el estado, que es un problema que se ha resuelto cientos de miles de veces antes.
Matt
"El uso de los verbos 'Agregar' y 'Crear' sugiere que todavía estás pensando en tu dominio en términos de interacción con una buena y antigua base de datos tabular" Hmmm. Cuando tienes un diseño de interfaz de usuario que tiene un gran botón 'Agregar algo', entonces esa es la intención; literalmente para agregar algo nuevo. Generalmente estoy de acuerdo con usted, pero no estamos hablando de nivel de base de datos aquí, a veces Agregar o Crear son en realidad las palabras correctas para usar.
designermonkey
1
@designermonkey Cuando tienes esos botones en la interfaz de usuario, ¿realmente tienes una operación de dominio detrás de ellos? Quizás, pero 9 de cada 10 veces realmente no hay necesidad de una operación de dominio compleja en ese contexto acotado. Y la operación CRUD pura es solo eso, una operación CRUD pura, y debe manejarse como tal. Solo cuando se necesite la complejidad del modelo de dominio, debe usarse. Así, los diferentes contextos limitados con diferentes principios de diseño.
Tuukka Haapaniemi