¿Dónde encajan estas consultas en una buena arquitectura?

Aug 17 2020

He estado pensando en un problema por un tiempo y realmente no siento que haya acertado cómo abordarlo.

Estoy tratando de trabajar con DDD tanto como sea posible, pero algunos escenarios de presentación realmente no encajan con esto en términos de rendimiento.

Digamos que tenemos un sistema para autos de alquiler, y allí tenemos una vista que debería mostrar todos los autos y la cantidad de veces que se han alquilado.

En un mundo DDD, supongo que tendría un depósito para mis autos de alquiler y algún depósito para "rent outs". También supongo que podría haber un servicio que maneje la interacción entre ellos, creando acuerdos, etc.

Pero cuando se trata de presentar la vista con autos de alquiler y el número de salidas de alquiler, no estoy muy seguro de dónde poner esto. Dado que los requisitos son muy específicos para esta vista, supongo que la versión más eficaz sería tener algún tipo de objeto "RentalCarsOverview" devuelto por el repositorio. Pero esto "contaminaría" los repositorios con consultas que son muy específicas de la vista.

Entonces, me pregunto si alguien ha enfrentado los mismos problemas y cómo se resolvió. He estado buscando en CQRS para separar esto, usando consultas para este tipo de vistas y mi modelo de dominio para actualizaciones. ¿Es este un buen enfoque?

Además, ¿estaría "bien" tener SQL sin procesar en estos controladores de consultas o también se abstraería con un repositorio subyacente?

Respuestas

3 VoiceOfUnreason Aug 17 2020 at 19:44

En estos días, la respuesta habitual es que las rutas de su código de consulta omitirán el "modelo de dominio" y trabajarán directamente con copias de su información.

El argumento aquí es que una consulta no cambia la información almacenada en el modelo de dominio y, por lo tanto, no nos beneficiamos de un montón de ceremonias que colocan esa información en objetos de dominio solo para sacarlos de nuevo.

Por ejemplo, si toda su información se almacena en la misma base de datos relacional, es muy probable que consulte la base de datos y transforme la información en los conjuntos de resultados en la forma correcta y la envíe de vuelta al cliente.

Cuando la información que necesita para responder la consulta se distribuye en varios sistemas, entonces hay más trabajo personalizado para generar el informe. Cuando el tiempo requerido para generar el informe supera sus objetivos de latencia, entonces comienza a buscar diseños en los que pueda almacenar en caché las partes costosas del informe. En algunos casos, esto significará que todo el informe se almacena en caché.

2 RikD Aug 17 2020 at 17:07

CQRS y DDD son una combinación perfecta.

Los comandos van a través de sus repositorios y modelos DDD. Las consultas pueden ser SQL sin procesar o un ORM liviano, con modelos separados específicamente para cada vista.

La arquitectura de su sistema de esta manera le brinda una forma sólida de manejar reglas comerciales complejas, con el mejor rendimiento posible para las lecturas.

2 CarmineIngaldi Aug 17 2020 at 19:38

Comencemos señalando que tener consultas inteligentes es un olor a código DDD. La mayoría de las veces, todo lo que tienes que hacer es

  • recuperar un agregado por su ID (hablando RESTful: GET /users/xyz)
  • recuperar todos los agregados con una raíz determinada ( /users?page=0&limit=10)
  • recuperar un subconjunto de agregados con un filtro simple (hablando RESTful: GET /users?username_startsWith=johnd&page=0&limit=10 )

Las aplicaciones complejas necesitan hacer cosas complejas, por supuesto, por lo que es posible que necesite crear proyecciones a partir de su agregado. Obviamente, su agregado no debería tener ninguna idea de lo que es una proyección, pero allí puede encontrar todos los datos necesarios para construirlos, porque está diseñando su dominio no solo para mutar constantemente, sino también para ser observado.

Este es un enfoque razonable incluso sin introducir los conceptos de CQRS. La mayoría de nuestras aplicaciones son aplicaciones CRUD + algunas reglas de validación de dominio. Si encuentra palabras como " descripción general " " informe " " estadísticas " " resumen " " historial " solo unas pocas veces en sus requisitos/historias/código, sabe que puede administrarlos simplemente cargando agregados en la memoria a través de consultas específicas, llamando a alguna agregación método (recuentos, sumas, promedios) e hacer el mapeo contra alguna proyección DTO

Cuando los casos antes mencionados son prominentes en su proyecto, cuando cargar agregados para recuperar solo alguna información agregada es una gran carga para su sistema, entonces sí, se encuentra con uno de los dos casos de uso en los que CQRS es útil.

Proporcionará a su agregado (es decir, el agregado del lado de escritura) la capacidad de desencadenar eventos de dominio cada vez que se haya cometido una mutación de estado notable.

Creará un módulo diferente en el que tendrá repositorios específicos de proyección y controladores de eventos (en su caso, algo como onEvent(CarRentedOutEvt evt) ) para actualizar y guardar sus proyecciones.

Tendrá (nuevamente hablando tranquilamente) una API de administración GET /rents/overview que se comportará de manera muy tonta. Toda la complejidad se descarga en el momento de la actualización

Merrion Sep 08 2020 at 17:48

Puede tener más de un modelo de lectura y, en este caso, un modelo de lectura de "Informes" desnormalizado que solo se suscribe a los eventos necesarios para actualizarse cuando recibe un evento "Alquilado".