¿Cómo diseñar los límites agregados?

10

Me gustaría escribir una aplicación algo así como el comercio electrónico.

Y sabe que en aplicaciones similares los productos podrían tener diferentes propiedades y características. Para simular tal oportunidad, he creado las siguientes entidades de modelo de dominio:

Categoría : esto es algo así como "electrónica> computadoras", es decir, tipos de productos. Las categorías contienen una lista de propiedades (Lista <Propiedad>).

Propiedad : entidad independiente que contiene el nombre, unidades de medida, tipo de datos. Por ejemplo "nombre", "peso", "tamaño de pantalla". La misma propiedad puede tener diferentes productos.

Producto : solo contiene el nombre y la lista de valores relacionados con las propiedades. El valor es un objeto que contiene solo el campo de valor y el id de campo de la propiedad.

Originalmente decidí hacer la Categoría como agregado único en este esquema porque, por ejemplo, cuando agrego un nuevo producto, necesito conocer todos los datos relacionados con la categoría actual, incluidas las propiedades relacionadas con la categoría actual ( category.AddNewProduct (product) ). Pero, ¿qué debo hacer cuando solo necesito agregar una nueva propiedad que no pertenece a ninguna categoría? Por ejemplo, no puedo hacer esta categoría . Agregar propiedad nueva (propiedad) porque dice claramente que agregamos la propiedad a una categoría específica.

Ok, el siguiente paso decidí separar la propiedad en un agregado separado, pero luego será una lista con entidades simples.

Por supuesto, puedo crear algo como PropertyAggregate para mantener dentro de la lista de propiedades y reglas de negocios, pero cuando agrego un producto, necesito tener dentro de la categoría la lista completa de propiedades que pertenecen a esta categoría para verificar las invariantes. Pero también soy consciente de que mantener los enlaces dentro del agregado en otros agregados es una mala práctica.

¿Cuáles son las opciones para diseñar este caso de negocios?

cephei
fuente
¿Podría proporcionar un ejemplo más completo de una categoría, propiedad y producto? La electrónica o las computadoras serían una categoría, el iPhone X sería un ejemplo de un producto, y una propiedad sería exactamente. ¿Pantalla de 11 "pulgadas?
Neil
casi tienes razón
Agregué
Parece que está buscando un diseño agregado exclusivamente desde una perspectiva de "contenedor de datos". También es posible que desee pensar en los casos de uso de su aplicación, teniendo en cuenta aspectos transaccionales, colaboración / acceso concurrente, eventos que ocurren, transiciones de estado, etc.
guillaume31

Respuestas:

7

En la perspectiva DDD Category, Producty Propertyson entidades: todas corresponden a objetos que tienen su propia identidad.

Opción 1: su diseño original

Hiciste Categoryla raíz de un solo agregado. Por un lado, esto tiene sentido, porque el agregado debe garantizar la coherencia cuando se modifican sus objetos, y Productdebe tener el Propertiesde su Category:

ingrese la descripción de la imagen aquí

Pero, por otro lado, el agregado único significa que todos sus objetos están relacionados con una raíz que los posee, y todas las referencias externas deben hacerse a través de esta raíz agregada. Esto implica que:

  • uno específico Productpertenece a uno y solo uno Category. Si Categoryse elimina, también lo es Products.
  • un específico Propertypertenece a uno y solo uno Category. Dicho de otro modo, si "pantallas de TV" y "monitores de computadora" serían dos categorías, "pantallas de TV: tamaño" y "monitores de computadora: tamaño" serían dos propiedades diferentes.

El segundo punto no corresponde a su narrativa: " Pero, ¿qué debo hacer cuando necesito agregar un nuevo Propertyque no pertenece a ninguna categoría ". Y no está claro si Propertiesse puede usar lo mismo en diferentes Categories.

Opción 2: Propiedad fuera del agregado

Si a Propertyexiste independientemente del Categories, debe estar fuera del agregado. Y lo mismo si desea compartir Propertiesentre Categories(lo que tiene sentido para la altura, el ancho, los tamaños, etc.). Este parece ser definitivamente el caso.

La consecuencia está en el vínculo entre Propertyy las cosas que pertenecen al agregado: si bien puede navegar desde el interior del agregado hasta Property, ya no se le permite ir directamente de a Propertya los valores correspondientes. Esta restricción de navegabilidad se puede mostrar en un diagrama UML:

ingrese la descripción de la imagen aquí

Tenga en cuenta que este diseño no impide que usted pueda tener una List<Property>en Category, con una referencia semántica (por ejemplo Java): cada referencia en la lista se refiere a un compartible Propertyobjeto en un repositorio.

El único problema con este diseño es que podría cambiarlo Propertyo eliminarlo: como está fuera del agregado, el agregado no puede encargarse de la consistencia de sus invariantes. Pero esto no es un problema. Es la consecuencia de los principios DDD y la complejidad del mundo real. Aquí una cita de Eric Evans en su libro seminal " Diseño impulsado por dominio: abordar la complejidad en el corazón del software ":

No se esperará que ninguna regla que abarque AGREGADOS esté actualizada en todo momento. Mediante el procesamiento de eventos, el procesamiento por lotes u otros mecanismos de actualización, se pueden resolver otras dependencias dentro de un tiempo específico. Pero los invariantes aplicados dentro de un AGREGADO se aplicarán con la finalización de cada transacción.

Entonces, sí, si cambia una Property, deberá asegurarse de que un servicio verifique que las Categorías que se refieren a él se actualicen según sea necesario.

Opción 3: categoría, propiedad y producto en diferentes agregados

Solo me pregunto si se funda la suposición de que un Productpertenece a un solo Category:

  • Frecuentemente veo tiendas en línea proponiendo una Producten varias Categories. Por ejemplo, encontrará "Marca portátil X Modelo Y" en la categoría "Computadoras portátiles" y la categoría "Computadoras", y una "impresora multifunción Z" en la categoría "impresora", "escáner" y "fax".
  • ¿No es posible que alguien cree un Productprimero, y solo más tarde lo asigne a Categorías y complete los valores?
  • Si desea dividir una categoría, ¿realmente eliminaría sus Productos y luego los volvería a crear en las nuevas categorías?

No simplificará los agregados, y tendría incluso más reglas que abarcan los agregados. Pero su sistema sería mucho más a prueba de futuro.

Christophe
fuente
Muchas gracias, esta es una explicación muy útil. Pero me gustaría aclarar algunos puntos. Me gustaría comenzar con la segunda opción y quién sabe, tal vez llegue a la tercera. Si llevo Propertymás allá de los límites del Categoryagregado, ¿significa esto que se Propertyconvierte en un agregado en sí mismo y necesita un repositorio? Si es cierto, ¿cómo pasar el requisito List<Property>a la Categoryinstancia? A través del constructor? Estara bien? ¿Y cómo puedo encontrar la lista de PropertyID de una Categoryque aún no se ha creado?
cephei el
En resumen, @zetetic: sí, necesitará un repositorio de propiedades independiente. O pasa una lista de Propiedades existentes a la fábrica de la Categoría, o crea Categorías vacías y llena la lista con un método addProperty. Pregunta a cambio: imagine que desea tener propiedades "obligatorias" y "opcionales", y la característica obligatoria depende de la categoría. ¿Cómo manejarías esto?
Christophe
respondiendo a su pregunta, lo primero que me viene a la mente es que puedo crear una entidad especial Featurey solo pertenecerá a la Product. y esta entidad no participará en la búsqueda. Qué dices ?
cephei el
@zetetic por qué no! Hubiera dejado los valores tal como están actualmente en el producto, y habría asociado la función a la categoría. Una categoría tiene n características (parte de su agregado), una Propiedad define m Características (pero el enlace va a través de la característica Categoría->). Luego ha descompuesto la relación de muchos a muchos en elementos más manejables, aclarando el límite agregado. Finalmente sobre la inyección de repositorio: esto no es necesario si hace referencia a otros agregados por identidad (lea este artículo informit.com/articles/article.aspx?p=2020371&seqNum=4 )
Christophe
5

Tal como lo veo, puedes resolver esto de una de dos maneras:

La categoría es un tipo especial de producto.

Esto significa que para cualquier producto en su base de datos, contiene una clave foránea que apunta a la misma tabla de productos. Un producto es un producto solo si no existen productos cuya clave foránea sea igual a la identificación de dicho producto. En otras palabras, si no tiene productos debajo, es un producto.

Esto simplificaría un poco las cosas. Los productos a las propiedades tendrían una relación de uno a muchos y, por lo tanto, también sus categorías tienen una relación de uno a muchos, ya que también son productos. Agregar una propiedad a una categoría sería tan fácil como agregar una propiedad a un producto en su programa. Cargar todas las propiedades significaría combinar las propiedades del producto con las propiedades de su categoría de producto asociada y así sucesivamente hasta llegar a una categoría de producto sin padre.

Su aplicación de comercio electrónico necesitaría hacer esta distinción, pero si es probable que cargue productos de una categoría de todos modos, no es una pérdida de rendimiento saber si está tratando con una categoría o un producto. También se presta muy bien para buscar en forma de árbol al nivel de producto, ya que cada producto (categoría) se abriría a una lista de subproductos sin mucho trabajo adicional.

La desventaja de esto es, por supuesto, que la información adicional presente en el producto que no tiene sentido para una categoría crearía campos incómodos no utilizados en el producto. Si bien esta solución sería más flexible en su aplicación, también es algo menos intuitiva.

Relación de muchos a muchos

Los productos ya no están en una relación compuesta con la propiedad. Se crea una tabla ProductProperty con claves externas de la tabla de productos y la tabla de propiedades que vinculan las dos. Del mismo modo, tiene una tabla de categorías con una relación de muchos a muchos con la tabla de propiedades y una tabla CategoryProperty con claves externas de la tabla de categorías y la tabla de propiedades.

El producto en sí mismo tendría una relación de muchos a uno con la categoría, permitiéndole esencialmente crear una lista de propiedades únicas pertenecientes tanto al producto como a la categoría a través de una declaración de selección bien formalizada.

Desde el punto de vista de la base de datos, esto es definitivamente más limpio y más flexible. Su aplicación probablemente podría funcionar en su mayor parte sin tratar directamente con CategoryProperty o ProductProperty si la consulta se realiza correctamente. Sin embargo, tampoco debe tratar la categoría o el producto como propietario de la propiedad. Debe ser su propia entidad dentro de su programa. Esto también significa que la gestión de dichas propiedades sería una cuestión de crear la propiedad en sí misma, y ​​luego asociarla con una categoría o un producto en dos pasos separados. Ciertamente más trabajo que la primera solución, pero de ninguna manera más difícil.

Además de esto, también debería realizar una verificación adicional al eliminar la categoría o el producto si alguna de sus propiedades está siendo utilizada por otros (a diferencia de la primera solución, donde podría eliminar de forma segura todas las propiedades asociadas de un producto / categoría determinada) .

Conclusión

En un contexto profesional, iría a la categoría de millas y distancias adicionales del producto y el producto de la propiedad utilizando el enfoque de muchos a muchos. No habría posibilidad de superposición de datos y, en cierto sentido, es más fácil razonar cada uno de estos tres como su propia entidad. Sin embargo, de ninguna manera la primera solución es mala, ya que también le permite escribir una aplicación más simple. Solo sepa que si pensaba que podría necesitar cambiar eventualmente de una solución a otra, probablemente sería mejor para usted elegir la segunda.

¡Buena suerte!

Neil
fuente
Gracias por la respuesta detallada e interesante! en el nivel de la base de datos que ya he modelado como explicaste en el segundo caso, este patrón se llama entidad-atributo-valor pero estoy atascado en el nivel de código, es decir, la definición de agregados. En la mayoría de los casos, todas estas entidades se usan juntas. es posible combinarlo en un agregado, pero hay casos en los que les gusta llenar directorios que, por sentido, son eliminados del agregado.
cephei