tutorial quickly implementing example driven domain ddd java .net design-patterns oop domain-driven-design

java - implementing - domain driven design quickly



Cómo evitar tener objetos muy grandes con Domain Driven Design (6)

Aunque los humanos reales tienen muchas responsabilidades, te diriges hacia el objeto anti-patrón de Dios .

Como han sugerido otros, debe extraer esas responsabilidades en Repositorios y / o Servicios de Dominio separados. P.ej:

SecurityService.Authenticate(credentials, customer) OrderRepository.GetOrderHistoryFor(Customer) RefundsService.StartRefundProcess(order)

Sea específico con las convenciones de nombres (es decir, use OrderRepository o OrderService , en lugar de OrderManager )

Te has encontrado con este problema por conveniencia . es decir, es conveniente tratar un WebsiteUser como una raíz agregada y acceder a todo a través de él.

Si pone más énfasis en la claridad en lugar de conveniencia , debería ayudar a separar estas preocupaciones. Desafortunadamente, significa que los miembros del equipo ahora deben estar al tanto de los nuevos Servicios.

Otra forma de verlo: al igual que las Entidades no deben realizar su propia persistencia (por lo que usamos Repositorios ), su WebsiteUser no debe manejar Reembolsos / Segmentación / etc.

¡Espero que ayude!

Estamos siguiendo el diseño dirigido por dominios para la implementación de un sitio web grande.

Sin embargo, al colocar el comportamiento en los objetos del dominio, estamos obteniendo algunas clases muy grandes.

Por ejemplo, en nuestro objeto WebsiteUser, tenemos muchos métodos, por ejemplo, tratar con contraseñas, historial de pedidos, reembolsos, segmentación de clientes. Todos estos métodos están directamente relacionados con el usuario. Muchos de estos métodos delegan internamente a otro objeto secundario pero
Esto todavía resulta en algunas clases muy grandes.

Estoy dispuesto a evitar exponer muchos objetos secundarios, por ejemplo, user.getOrderHistory (). GetLatestOrder ().

¿Qué otras estrategias se pueden utilizar para evitar estos problemas?


Creo que su problema está realmente relacionado con los contextos acotados. Por lo que veo, "tratar con contraseñas, historial de pedidos, reembolsos, segmentación de clientes", cada uno de estos puede ser un contexto acotado. Por lo tanto, podría considerar dividir su WebsiteUser en múltiples entidades, cada una correspondiente a un contexto. Puede surgir alguna duplicación, pero usted se enfoca en su dominio y se deshace de clases muy grandes con múltiples responsabilidades.


Es posible que desee considerar invertir algunas cosas. Por ejemplo, un Cliente no necesita tener una propiedad de Pedido (o un historial de pedidos), puede dejarlos fuera de la clase de Cliente. Así que en lugar de

public void doSomethingWithOrders(Customer customer, Calendar from, Calendar to) { List = customer.getOrders(from, to); for (Order order : orders) { order.doSomething(); } }

en su lugar podrías hacer

public void doSomethingWithOrders(Customer customer, Calendar from, Calendar to) { List = orderService.getOrders(customer, from, to); for (Order order : orders) { order.doSomething(); } }

Este es un acoplamiento ''más suelto'', pero aún así puede obtener todos los pedidos que pertenecen a un cliente. Estoy seguro de que hay personas más inteligentes que yo que tienen los nombres y enlaces correctos que se refieren a lo anterior.


Los problemas que está viendo no son causados ​​por el diseño impulsado por dominio, sino más bien por una falta de separación de preocupaciones. Domain Driven Design no se trata solo de colocar datos y comportamientos juntos.

Lo primero que recomendaría es tomarse un día o más y leer el diseño impulsado por dominios, disponible rápidamente como una descarga gratuita desde Info-Q. Esto proporcionará una visión general de los diferentes tipos de objetos de dominio: entidades, objetos de valor, servicios, repositorios y fábricas.

Lo segundo que recomendaría es leer el Principio de Responsabilidad Única .

La tercera cosa que recomendaría es que comience a sumergirse en el desarrollo dirigido por pruebas . Si bien aprender primero a diseñar mediante la escritura de pruebas no necesariamente hará que los diseños sean excelentes, tienden a guiarlo hacia diseños acoplados libremente y revelar problemas de diseño antes.

En el ejemplo que proporcionó, WebsiteUser definitivamente tiene demasiadas responsabilidades. De hecho, es posible que no tenga la necesidad de WebsiteUser ya que los usuarios generalmente están representados por un ISecurityPrincipal .

Es un poco difícil sugerir exactamente cómo debe enfocarse en su diseño debido a la falta de contexto empresarial, pero primero recomendaría hacer una tormenta de ideas al crear algunas tarjetas de índice que representan cada uno de los nombres principales que tiene en su sistema (por ejemplo, Cliente, Pedido, Recibo, Producto, etc.). Escriba los nombres de las clases candidatas en la parte superior, qué responsabilidades cree que son inherentes a la clase que está a la izquierda y las clases con las que colaborará a la derecha. Si algún comportamiento parece que no pertenece a ninguno de los objetos, probablemente sea un buen candidato de servicio (es decir, AuthenticationService). Extienda las tarjetas sobre la mesa con sus universidades y discútalas. Sin embargo, no le dé demasiada importancia, ya que esto solo pretende ser un ejercicio de diseño de lluvia de ideas. Puede ser un poco más fácil hacer esto a veces que usar una pizarra porque puede mover las cosas.

A largo plazo, realmente deberías escoger el libro Dominio Diseño dirigido por Eric Evans. Es una gran lectura, pero vale la pena su tiempo. También te recomiendo que escojas Desarrollo de software ágil, Principios, patrones y prácticas o Principios, patrones y prácticas ágiles en C # según tu preferencia de idioma.


Me encontré con el mismo problema y descubrí que usar objetos "gestores" secundarios era la mejor solución en nuestro caso.

Por ejemplo, en su caso, podría tener:

User u = ...; OrderHistoryManager histMan = user.getOrderHistoryManager();

Entonces puedes usar el histMan para lo que quieras. Obviamente, pensaste en esto, pero no sé por qué quieres evitarlo. Separa las preocupaciones cuando tienes objetos que parecen hacer demasiado.

Piensa en ello de esta manera. Si tenía un objeto "humano" y tenía que implementar el método chew() . ¿Lo pondrías en el objeto Human o en el objeto hijo Mouth ?


Una regla de oro muy simple a seguir es que "la mayoría de los métodos en su clase TIENEN que usar la mayoría de las variables de instancia en su clase": si sigue esta regla, las clases serán automáticamente del tamaño correcto.