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?
Respuestas:
En la perspectiva DDD
Category
,Product
yProperty
son entidades: todas corresponden a objetos que tienen su propia identidad.Opción 1: su diseño original
Hiciste
Category
la raíz de un solo agregado. Por un lado, esto tiene sentido, porque el agregado debe garantizar la coherencia cuando se modifican sus objetos, yProduct
debe tener elProperties
de suCategory
: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:
Product
pertenece a uno y solo unoCategory
. SiCategory
se elimina, también lo esProducts
.Property
pertenece a uno y solo unoCategory
. 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
Property
que no pertenece a ninguna categoría ". Y no está claro siProperties
se puede usar lo mismo en diferentesCategories
.Opción 2: Propiedad fuera del agregado
Si a
Property
existe independientemente delCategories
, debe estar fuera del agregado. Y lo mismo si desea compartirProperties
entreCategories
(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
Property
y las cosas que pertenecen al agregado: si bien puede navegar desde el interior del agregado hastaProperty
, ya no se le permite ir directamente de aProperty
a los valores correspondientes. Esta restricción de navegabilidad se puede mostrar en un diagrama UML:Tenga en cuenta que este diseño no impide que usted pueda tener una
List<Property>
enCategory
, con una referencia semántica (por ejemplo Java): cada referencia en la lista se refiere a un compartibleProperty
objeto en un repositorio.El único problema con este diseño es que podría cambiarlo
Property
o 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 ":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
Product
pertenece a un soloCategory
:Product
en variasCategories
. 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".Product
primero, y solo más tarde lo asigne a Categorías y complete los valores?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.
fuente
Property
más allá de los límites delCategory
agregado, ¿significa esto que seProperty
convierte en un agregado en sí mismo y necesita un repositorio? Si es cierto, ¿cómo pasar el requisitoList<Property>
a laCategory
instancia? A través del constructor? Estara bien? ¿Y cómo puedo encontrar la lista deProperty
ID de unaCategory
que aún no se ha creado?Feature
y solo pertenecerá a laProduct
. y esta entidad no participará en la búsqueda. Qué dices ?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!
fuente