Me estoy sumergiendo en el diseño impulsado por dominio y algunos de los conceptos que estoy encontrando tienen mucho sentido en la superficie, pero cuando pienso más en ellos, me pregunto si esa es realmente una buena idea.
El concepto de agregados, por ejemplo, tiene sentido. Crea pequeños dominios de propiedad para no tener que lidiar con todo el modelo de dominio.
Sin embargo, cuando pienso en esto en el contexto de una aplicación web, con frecuencia estamos presionando la base de datos para retirar pequeños subconjuntos de datos. Por ejemplo, una página solo puede enumerar el número de pedidos, con enlaces para hacer clic para abrir el pedido y ver sus ID de pedido.
Si estoy en lo correcto entendimiento agregados, me suelen utilizar el patrón de repositorio para devolver un OrderAggregate que contendría los miembros GetAll
, GetByID
, Delete
, y Save
. OK eso suena bien. Pero...
Si llamo a GetAll para enumerar todos mis pedidos, me parecería que este patrón requeriría que se devuelva la lista completa de información agregada, pedidos completos, líneas de pedido, etc. Cuando solo necesito un pequeño subconjunto de esa información (solo información del encabezado).
¿Me estoy perdiendo de algo? ¿O hay algún nivel de optimización que usarías aquí? No puedo imaginar que alguien abogue por devolver agregados enteros de información cuando no la necesite.
Ciertamente, uno podría crear métodos en su repositorio como GetOrderHeaders
, pero eso parece anular el propósito de usar un patrón como repositorio en primer lugar.
¿Alguien puede aclarar esto para mí?
EDITAR:
Después de mucha más investigación, creo que la desconexión aquí es que un patrón de Repositorio puro es diferente de lo que la mayoría de la gente piensa que es un Repositorio.
Fowler define un repositorio como un almacén de datos que utiliza semántica de recopilación, y generalmente se mantiene en la memoria. Esto significa crear un gráfico de objeto completo.
Evans altera el repositorio para incluir raíces agregadas y, por lo tanto, el repositorio se amputa para admitir solo los objetos en un agregado.
La mayoría de las personas parecen pensar en los repositorios como objetos de acceso a datos glorificados, donde solo se crean métodos para obtener los datos que se desean. Esa no parece ser la intención descrita en los Patrones de arquitectura de aplicaciones empresariales de Fowler.
Aún otros piensan en un repositorio como una simple abstracción utilizada principalmente para facilitar las pruebas y las burlas, o para desacoplar la persistencia del resto del sistema.
Supongo que la respuesta es que este es un concepto mucho más complejo de lo que pensé al principio.
fuente
Respuestas:
No use su modelo de dominio y agregados para realizar consultas.
De hecho, lo que está preguntando es una pregunta lo suficientemente común como para que se haya establecido un conjunto de principios y patrones para evitar eso. Se llama CQRS .
fuente
Luché, y todavía estoy luchando, con la mejor manera de usar el patrón de repositorio en un diseño impulsado por dominio. Después de usarlo ahora por primera vez, se me ocurrieron las siguientes prácticas:
Un repositorio debe ser simple; solo es responsable de almacenar objetos de dominio y recuperarlos. Toda otra lógica debe estar en otros objetos, como fábricas y servicios de dominio.
Un repositorio se comporta como una colección como si fuera una colección en memoria de raíces agregadas.
Un repositorio no es un DAO genérico, cada repositorio tiene su interfaz única y estrecha. Un repositorio a menudo tiene métodos de búsqueda específicos que le permiten buscar en la colección en términos del dominio (por ejemplo: darme todas las órdenes abiertas para el usuario X). El repositorio en sí se puede implementar con la ayuda de un DAO genérico.
Idealmente, los métodos de búsqueda solo devolverán raíces agregadas. Si eso es demasiado ineficiente, también puede devolver objetos de valor de solo lectura que contengan exactamente lo que necesita (aunque es una ventaja si estos objetos de valor también se pueden expresar en términos del dominio). Como último recurso, el repositorio también se puede utilizar para devolver subconjuntos o colecciones de subconjuntos de una raíz agregada.
Las opciones como estas dependen de las tecnologías utilizadas, ya que necesita encontrar una manera de expresar de manera más eficiente su modelo de dominio con las tecnologías utilizadas.
fuente
No creo que su método GetOrderHeaders anule el propósito del repositorio en absoluto.
DDD se preocupa (entre otras cosas) de garantizar que obtenga lo que necesita a través de la raíz agregada (por ejemplo, no tendría un OrderDetailsRepository), pero no lo limita en la forma en que lo menciona.
Si un OrderHeader es un concepto de Dominio, entonces debe tenerlo definido como tal y tener los métodos de repositorio apropiados para recuperarlos. Solo asegúrese de pasar por la raíz agregada correcta cuando lo haga.
fuente
Mi uso de DDD puede no considerarse DDD "puro", pero he adaptado las siguientes estrategias del mundo real usando DDD contra un almacén de datos DB.
** No tiene que traer de vuelta un agregado completo. Sin embargo, si quieres más, tienes que preguntarle a la raíz, no a algún otro servicio o repositorio. Esta es una carga diferida y se puede hacer manualmente con una carga diferida (inyectando el repositorio / servicio apropiado en la raíz) o usando un ORM que lo admita.
En su ejemplo, probablemente proporcionaría una llamada al repositorio que traería solo los encabezados de los pedidos si quisiera cargar los detalles en una llamada separada. Tenga en cuenta que al tener un "OrderHeader" estamos introduciendo un concepto adicional en el dominio.
fuente
Su modelo de dominio contiene su lógica empresarial en su forma más pura. Todas las relaciones y operaciones que respaldan las operaciones comerciales. Lo que le falta a su mapa conceptual es la idea de la capa de servicio de aplicación, la capa de servicio se ajusta al modelo de dominio y proporciona una vista simplificada del dominio empresarial (una proyección si lo desea) que permite que el modelo de dominio cambie según sea necesario sin afectar directamente las aplicaciones que utilizan la capa de servicio.
Ir más lejos. La idea del agregado es que hay un objeto, la raíz del agregado, responsable de mantener la consistencia del agregado. En su ejemplo, el pedido sería responsable de manipular sus líneas de pedido.
Para su ejemplo, la capa de servicio expondría una operación como GetOrdersForCustomer que solo devolvería lo que se necesita para ver una lista resumida de los pedidos (como los llama OrderHeaders).
Finalmente, el patrón Repository no es SOLO una colección, sino que también permite consultas declarativas. En C # puede usar LINQ como objeto de consulta , o la mayoría de los otros O / RM también proporcionan una especificación de objeto de consulta.
Al ver que puede crear consultas en el repositorio, también tiene sentido proporcionar métodos convenientes que manejen consultas comunes. Es decir, si solo desea los encabezados de su pedido, puede crear una consulta que devuelva solo el encabezado y exponerlo desde un método conveniente en sus repositorios.
Espero que esto ayude a aclarar las cosas.
fuente
Sé que esta es una vieja pregunta, pero parece que he llegado a una respuesta diferente.
Cuando hago un repositorio, generalmente se envuelven algunas consultas en caché .
Mantenga esos repositorios en sus servidores ram. ¡No solo pasan objetos a la base de datos!
Si estoy en una aplicación web con una página de listado de pedidos, en la que puede hacer clic para ver los detalles, es probable que quiera que mi página de listado de pedidos tenga detalles sobre los pedidos (ID, Nombre, Cantidad, Fecha) para ayudar a un usuario a decidir cuál quiere mirar.
En este punto tienes dos opciones.
Puede consultar la base de datos y retirar exactamente lo que necesita para hacer la lista, luego consultar nuevamente para obtener los detalles individuales que necesitaría ver en la página de detalles.
Puede realizar 1 consulta que retire toda la información y la almacene en caché. En la página siguiente, solicite que lea de la RAM de los servidores en lugar de la base de datos. Si el usuario responde o selecciona la siguiente página, todavía no realiza ningún viaje a la base de datos.
En realidad, cómo lo implementa es solo eso, y detalles de implementación. Si mi mayor usuario tiene 10 pedidos, probablemente quiera ir con la opción 2. Si estoy hablando de 10,000 pedidos, entonces se necesita la opción 1. En los dos casos anteriores y en muchos otros casos, quiero que el repositorio oculte los detalles de la implementación.
En el futuro, si obtengo un ticket para decirle al usuario cuánto han gastado en pedidos ( datos agregados ) en el último mes en la página de listado de pedidos, preferiría escribir la lógica para calcular eso en SQL y hacer otro viaje de ida y vuelta a la base de datos o preferiría calcularlo utilizando los datos que ya están en el servidor ram?
En mi experiencia, los agregados de dominio ofrecen enormes beneficios.
fuente