Comunicación entre dos contextos delimitados en DDD

Tengo pocos contextos delimitados diferentes en el dominio. La validación de una operación CRUD se construye en cada contexto delimitado.

Por ejemplo, puedo crear una entidad llamada GAME solo si la persona que la crea es un Líder de grupo .

Tengo dos Contextos Limitados (BC) en este ejemplo. Uno es el Juego BC y el otro es el Usuario BC . Para resolver el problema, en el Juego BC , tengo que hacer una llamada de servicio de dominio como IsGroupLeader () al Usuario BC antes de continuar con la creación del Juego.

No creo que este tipo de comunicación sea recomendada por DDD. También puedo tener una entidad de Usuario en el Juego BC , pero no quiero porque la misma entidad de Usuario se está usando de manera diferente en un contexto diferente en un BC diferente.

Mis preguntas son:

  1. ¿Debo usar los eventos de Dominio donde el Juego BC tiene que enviar un evento al Usuario BC preguntando el estado del Usuario ? Con este enfoque, no hago una llamada sincrónica como IsGroupLeader sino un evento llamado is_group_leader . Luego, Game BC debe esperar a que el Usuario BC procese el evento y regrese el estado. The Game BC creará la entidad Game solo después de que el Usuario BC procese el evento.

  2. ¿Es CQRS una solución a mi problema?

Cualquier idea apreciada.

Al integrar BC, tiene algunas opciones. La razón por la cual se desaconseja llamar a un BC externo es porque requiere que ambos BC estén operativos al mismo tiempo. Sin embargo, esto a menudo es bastante aceptable y es más simple que la alternativa. Una alternativa es hacer que Game BC se suscriba a los eventos de User BC y conservar copias locales de los datos que necesita, que en este caso es información sobre si un usuario es un líder de grupo. De esta forma, cuando Game BC necesita determinar si un usuario es un líder de grupo, no necesita llamar al Usuario BC, solo lee los datos almacenados localmente. El desafío de esta alternativa impulsada por eventos es sincronizar los eventos. Usted tiene la garantía de que el Game BC reciba todos los eventos apropiados del Usuario BC. Otro desafío es lidiar con la consistencia eventual , ya que los BC pueden estar ligeramente desincronizados en cualquier punto dado en el tiempo.

CQRS es algo ortogonal a este problema.

Así es como razonaría al respecto.

Yo diría que el Juego BC no conoce a los “Usuarios”, sin embargo, podría saber sobre “Jugadores”.

Si el Juego BC depende de un jugador activo / actual, entonces debe pasarse al BC al crear la instancia del Juego BC.

p.ej.

  Player currentPlayer = GetPlayerSomehow...(); GameBC gameBC = new GameBC(currentPlayer); gameBC.DoStuff(); 

Ahora sus dos BC todavía están separados, puede probarlos por separado, etc.

Y para que todo funcione, simplemente haz algo como:

  User currentUser = GetCurrentUser(); Player currentPlayer = new Player(); currentPlayer.IsGroupLeader = currentUser.IsGroupLeader; GameBC gameBC = new GameBC(currentPlayer); gameBC.DoStuff(); 

Esto sirve como una capa anticorrupción entre el UserBC y el GameBC, puede mover y validar el estado que desea del UserBC al estado que necesita para su GameBC.

Y si su GameBC necesita acceder a muchos usuarios, aún puede pasar algún tipo de servicio de mapas en el juego BC que hace este tipo de transformación internamente.

Creo que ya casi estás allí. Cerca de una buena solución. No estoy tan seguro de que tenga que dividir estos dos en dos BC. Su User Aggregateroot (?) Y Game quizás pertenezcan a un BC y dependan el uno del otro. Un usuario “tiene una” Membresía “para uno o muchos” Juegos “(simplemente adivinando las relaciones de su entidad). Pero solo estoy haciendo una lluvia de ideas ahora. Intenta seguir 🙂 Siguen diferentes enfoques:

First GameBC tiene un método Create () que realmente toma una membresía de usuario como param. Crear (Membresía de usuario). A continuación, a través de la entidad de membresía de usuario sabe qué tipo de membresía y usuario es esta. Si es aceptado, se crea el juego. Si no se emite una excepción o Game recibe un mensaje de regla roto, depende de qué enfoque quiera comunicar al cliente. La coordinación se puede hacer en la capa de aplicación sin pérdida de conocimiento del dominio.

Segundo lo haces como una de las otras respuestas. Usted levanta un CreateGameEvent dentro del método Game.Create (UserId). Ese Evento es capturado por un Manejador de Eventos (registrado por IoC en el inicio de la Aplicación) que reside en la capa de Aplicación y busca Membresía de Usuario a través del repository. La pequeña fuga de conocimiento de dominio es esa regla de negocio que sabe a quién se le permite hacer lo que se verifica en la capa de aplicación. Esto se puede resolver permitiendo que CreateGameEventHandler tome UserId y RuleRef (puede ser la cadena “CAN_CREATE_GAME” o enum) y permitiendo que un objeto UserPermission verifique el permiso. Si no. La excepción se arroja y atrapa en la capa de aplicación. El inconveniente puede ser que usted no desea que las cadenas de referencia de permisos estén codificadas en el método Crear.

Tercero … continúa donde termina el segundo enfoque. Usted sabe que GameBC puede no ser el lugar adecuado para realizar búsquedas de permisos de usuario si sigue el principio de SRP. Pero la acción se desencadena alrededor de ese método de alguna manera. Una alternativa y ser un Create (usuario de GroupLeader). O puede tener Game.Create (User user) luego validar que User es GroupLeader type. Create (GroupLeader) le dice lo que necesita para llamar a este método.

Last Tal vez una alternativa que me gusta más ahora cuando escribo esto. Cuando desea crear una entidad, generalmente dejo que el método Crear (Guardar) esté en el repository. La interfaz IGameRepository se encuentra junto a Game Entity en el proyecto de ensamblaje de dominio. Pero también puede crear una GameFactory que sea responsable de comenzar el ciclo de vida de Game Entity. Aquí también hay un buen lugar para poner el método Create … GameFactory.Create (GroupLeader) {return new Game.OwnerUserId = GroupLeader.Id; } Entonces simplemente lo guarda IGameRepository.Save (Juego)

Luego tiene una forma intuitiva y autodescriptiva de decirle a otros desarrolladores que “Debe tener una instancia de GroupLeader para crear un juego”.

Finalmente, espero que se dé cuenta de que conoce el dominio y descubrirá qué le conviene más. Sé pragmático y no vayas duro con Eric Evan. Hay tantos desarrolladores que están atrapados en una “religión” en cómo se van a hacer las cosas. El tamaño del proyecto, el dinero, el tiempo y las dependencias con otros sistemas, etc. también afectan cuán bien puede ser estricto al hacer DDD.

Buena suerte.

Para lidiar con el tipo de problemas que enfrenta, utilizamos roles acotados, un patrón de modelado que surgió a lo largo de los años y que demostró funcionar muy bien. Los contextos delimitados se definen después de unidades semánticas que a menudo, en organizaciones empresariales, se pueden asignar a roles específicos.

Eso debería ser obvio teniendo en cuenta que los diferentes roles se enfrentan a problemas diferentes y, por lo tanto, hablan un poco (o totalmente) idiomas diferentes.

Por lo tanto, siempre modelamos los roles que interactúan con nuestra aplicación como un punto de unión entre los requisitos de aplicación (infraestructura, persistencia, UI, localización, etc.) y las reglas de negocios (el dominio) y los codificamos en diferentes módulos (también conocidos como ensamblajes o paquetes).

En cuanto a su segunda pregunta, CQRS puede ser una forma de codificar el tipo de interacciones entre BC que usted está describiendo, pero no me gusta en este contexto particular.

Creo que tendré que seguir un enfoque diferente en el que haré que la entidad del usuario forme parte del Juego BC (la misma entidad también forma parte del Usuario BC ). Usaré el Repositorio para leer el indicador IsGroupLeader del db en el Juego BC . De esta forma, se elimina la dependencia del User BC y no se necesita comunicación con el Usuario BC .

¿Qué piensas?

    Intereting Posts