¿Se supone que los objetos de dominio en el diseño impulsado por dominio solo son de escritura?

13

Llevo casi dos años leyendo sobre el diseño impulsado por dominios y he estado introduciendo con cautela algunos conceptos en mi trabajo diario o al menos haciendo planes sobre cómo se pueden hacer las cosas que hago regularmente dentro de un diseño impulsado por dominios.

Una conclusión a la que he empezado a llegar especialmente en respuesta a la lectura más sobre el abastecimiento de eventos y la segregación de responsabilidad de consulta de comandos (CQRS) de que quizás los objetos de dominio están destinados a ser utilizados solo con fines de escritura. Para ser más claro, parece que lo que la gente sugiere sutilmente en gran parte de la documentación que he leído es que los objetos de dominio son responsables de realizar operaciones / cálculos centrados en el dominio, validación, y luego están allí principalmente para proporcionar un camino hacia la persistencia a través de La infraestructura proporcionada dentro de una implementación de repositorio. Aunque me gusta el hecho de que esto puede simplificar enormemente el modelo de dominio, ya que elimina la responsabilidad de exponer el estado.

Si es correcto que los objetos de dominio se usen principalmente como objetos de solo escritura, entonces eso plantea algunas preguntas para mí que espero que alguien pueda responder.

  1. ¿Cómo se realizan pruebas unitarias en un objeto que tiene setters, o métodos que modifican el estado de un objeto pero que no proporcionan una interfaz pública externa para leer el estado, como los captadores de propiedades en C #? ¿Está bien exponer el estado únicamente con el fin de hacer que ese objeto sea comprobable?
  2. ¿Cómo se le muestra a un usuario los resultados de los cálculos u operaciones realizados en el dominio sin tener que persistirlos y luego extraer los resultados del almacén persistente fuera del contexto del dominio? ¿Está bien exponer el estado únicamente con el fin de mostrar resultados?

¿Es la regla general que los únicos captadores de propiedades (obtener accesores) deben ser los que también se pueden escribir en el dominio? O dicho de otra manera, ¿las propiedades de solo lectura deberían ser lo único que se debe evitar, ya que solo están allí para fines de lectura y, por lo tanto, no juegan un papel necesario en el modelo de dominio real?

Material relacionado:

  1. TDD, DDD y encapsulación
jpierson
fuente

Respuestas:

9

No estoy seguro de que haya una respuesta de "una sola forma verdadera" para un enfoque de diseño que, para ser justos, todavía está evolucionando. Primero, DDD y CQRS no son lo mismo, aunque la gente de CQRS parece haberse derivado de un punto de partida influenciado por DDD.

La mentalidad DDD está sucediendo mucho y gran parte tiene que ver con los límites de problemas definidos adecuadamente, la comunicación entre las partes interesadas y la interacción entre sistemas, no necesariamente una implementación específica en el código, por lo que no creo que sea demasiado difícil. El núcleo es una virtud.

Quizás esté viendo algo del debate sobre si los objetos de dominio deberían ser cambiables y cómo, y qué función cumple un objeto de dominio en un sistema en su conjunto. CQRS divide un sistema en rutas de lectura y escritura, por lo que es sensato concluir que en realidad no necesita acceso de lectura cuando está en la ruta de escritura. Entonces, la lectura se convierte en algo que haces contra los eventos generados por algunos objetos de dominio y consumidos (manejados) por otros. Si retrocede un poco en el historial de CQRS, encontrará argumentos de que los objetos de dominio no deberían tener setters, solo getters y un solo método 'controlador'. La lógica aquí es que solo los eventos de consumo deberían dar como resultado un cambio de estado, y ese cambio es manejado completamente internamente por el objeto de dominio.

Puede mostrar los resultados del cambio tratándolos como artefactos de cambio separados, colocándolos en una estructura separada, plana y persistente (por ejemplo, una tabla) y leyéndolo como si estuviera leyendo un informe sobre el estado actual e histórico del sistema. . Por ejemplo, podría consumir un evento extrayendo los datos que necesita leer y guardándolos en una tabla de base de datos que se corresponda con una vista única (por ejemplo, una pantalla) de su sistema.

Si experimenta con este estilo, tenga en cuenta que es probable que otros programadores no estén familiarizados con este enfoque, y que hay relativamente pocos (pero interesantes) escenarios en los que sea justificable como un enfoque de diseño.

Para las pruebas unitarias, hay un par de enfoques que pueden funcionar para usted. El primero, y más natural, es verificar que los eventos que espera ver generados por los objetos de su dominio sean correctos. Un objeto de dominio puede generar un evento genérico modificado que contiene información sobre el cambio. Podrías verificar eso. Puede verificar el hecho de que el evento se generó y que otros eventos no se generaron.

Otro enfoque es utilizar Test Spies que expongan atributos legibles en su objeto de dominio para que pueda verificar los cambios de estado. Por ejemplo, puede heredar de su objeto de dominio, agregar algunos accesos para leer lo que de otro modo sería el estado encapsulado y verificar que sea correcto.

De nuevo, estás confundido porque estos enfoques son confusos. Si está buscando adoptar algunas buenas ideas en su programación, tome primero las partes jugosas. Los límites de DDD y la explicitación de roles son cambios en su forma de pensar acerca de la comunicación con su código. Como mínimo, CQRS sugiere que leer datos y escribir datos son operaciones segregables. Esa información lo lleva a pensar muy claramente sobre cuál es el papel de los datos que necesita presentar, cuánto necesita realmente, quién lo consume, qué tan fresco debe ser, etc. No necesita un Implementación completa de Event Sourcing para adoptar una mejor encapsulación en su codificación. Puede comenzar simplemente enfocándose en las operaciones atómicas dentro de su objeto, los enfoques "Tell, Don't Ask" para el diseño de la interfaz del objeto,

pfries
fuente
1
+1 para comenzar con los bits jugosos. Además: morder solo el CQS (omitiendo la parte de 'eventos' por ahora) podría ser un buen lugar para comenzar.
cottsak
1

¿Se supone que los objetos de dominio en el diseño impulsado por dominio solo son de escritura?

No. CQRS puede usarse junto con DDD.

NimChimpsky
fuente
Pero, ¿la parte de consulta de CQRS se trata de consultar datos que usa el modelo de dominio para escribir cambios en el modelo o puede usarse para consultar datos para la capa de aplicación que podría decir mostrar los valores al usuario? Algunos me dicen que DDD se trata de coordinar cambios y no se debe usar para leer para ningún otro propósito que no sea coordinar cambios a otro objeto dentro del modelo de dominio. La decisión de una forma u otra significaría un diseño de modelo radicalmente diferente, ya que los datos expuestos en los objetos de dominio variarían de forma limitada si solo se consumen en el dominio.
jpierson
0

Las pruebas de unidad del modelo de dominio deben verificar que para cada comando ejecutado se generen los eventos de dominio correctos. Los comandos de su dominio y los eventos capturados pueden ser interrogados por estado.

También puede anular ToString()los comandos y eventos de su dominio para proporcionar informes de estado automáticos y legibles por humanos.

Para responder a su segunda pregunta, para mostrar los resultados de los comandos, debe organizar los eventos de dominio para que se 'publiquen' en su modelo de lectura.

Ed James
fuente
¿Podría explicar un poco si esto todavía se aplica cuando no está utilizando el abastecimiento de eventos?
jpierson
1
Sin el abastecimiento de eventos, tal vez mi sugerencia no funcione; No sé cómo funciona tu código. Para un objeto de dominio que idealmente no expone ninguna propiedad, quizás pueda implementar explícitamente una interfaz de prueba que exponga las propiedades que desea probar. Solo su código de prueba "sabrá" lanzar tales objetos de dominio a la interfaz de prueba.
Ed James
Gracias por esa sugerencia. Me siento un poco incómodo con la idea de modificar mis clases de dominio específicamente para la comprobabilidad, pero supongo que esta puede ser una de esas áreas grises que aún se encuentran en el Diseño impulsado por dominio si desea que sea comprobable. Otro pensamiento es que si uno exponga la estabilización y la capacidad de prueba a través de la misma interfaz, entonces al menos solo introduciría una dependencia de infraestructura en lugar de dos. ¿Qué piensan los demás de eso?
jpierson