¿Dónde trazamos la línea entre la delegación y la encapsulación de la lógica empresarial? Me parece que cuanto más delegamos, más anémicos nos volvemos. Sin embargo, la delegación también promueve la reutilización y el director DRY. Entonces, ¿qué es apropiado delegar y qué debe permanecer en nuestros modelos de dominio?
Tome las siguientes preocupaciones como ejemplos:
Autorización . ¿Debería el objeto de dominio ser responsable de mantener sus reglas de control de acceso (como una propiedad CanEdit) o debería delegarse en otro componente / servicio exclusivamente responsable de administrar el acceso, por ejemplo, IAuthorizationService.CanEdit (objeto)? ¿O debería ser una combinación de los dos? ¿Quizás el objeto de dominio tiene una propiedad CanEdit que delega a un IAuthorizationService interno para realizar el trabajo real?
Validación . La misma discusión que la anterior se relaciona con la validación. ¿Quién mantiene las reglas y quién es responsable de evaluarlas? Por un lado, el estado del objeto debe pertenecer a ese objeto y la validez es un estado, pero no queremos reescribir el código utilizado para evaluar las reglas para cada objeto de dominio. Nosotros podríamos utilizar la herencia en este caso ...
Creación de objetos . Clase de fábrica versus métodos de fábrica versus 'novedad' en una instancia. Si utilizamos una clase de fábrica separada, podemos aislar y encapsular la lógica de creación, pero a expensas de abrir el estado de nuestro objeto a la fábrica. Esto se puede administrar si nuestra capa de dominio está en un ensamblaje separado al exponer un constructor interno utilizado por la fábrica, pero esto se convierte en un problema si hay múltiples patrones de creación. Y, si todo lo que hace la fábrica es llamar al constructor correcto, ¿cuál es el punto de tener la fábrica?
Los métodos de fábrica en la clase eliminan el problema de abrir el estado interno del objeto, pero como son estáticos, no podemos romper las dependencias mediante la inyección de una interfaz de fábrica como podemos hacerlo con una clase de fábrica separada.
Persistencia . Se podría argumentar que si nuestro objeto de dominio va a exponer CanEdit mientras se delega la responsabilidad de realizar la verificación de autorización a otra parte (IAuthorizationService), ¿por qué no tener un método Save en nuestro objeto de dominio que haga lo mismo? Esto nos permitiría evaluar el estado interno del objeto para determinar si la operación se puede realizar sin romper la encapsulación. Por supuesto, requiere que inyectemos la instancia del repositorio en nuestro objeto de dominio, lo que me huele un poco, así que, ¿generamos un evento de dominio y permitimos que un controlador realice la operación de persistencia?
¿Ves a dónde voy con esto?
Rockford Lhotka tiene una gran discusión sobre sus razones para seguir la ruta de la Clase a Cargo para su marco CSLA y tengo un poco de historia con ese marco y puedo ver su idea de los objetos de negocios paralelos a los objetos de dominio de muchas maneras. Pero tratando de ser más adherente a los buenos ideales DDD, me pregunto cuándo la colaboración se vuelve demasiado.
Si termino con un IAuthorizationService, IValidator, IFactory e IRepository para mi raíz agregada, ¿qué queda? ¿Es suficiente tener un método de publicación que cambie el estado del objeto de borrador a publicado para considerar que la clase es un objeto de dominio no anémico?
¿Tus pensamientos?
fuente
Respuestas:
La mayor parte de la confusión parece estar relacionada con la funcionalidad que no debería existir en absoluto en el modelo de dominio:
La persistencia nunca debe estar en el modelo de dominio. Nunca jamás. Esa es la razón por la que confía en los tipos abstractos, como
IRepository
si parte del modelo alguna vez necesita hacer algo como recuperar una parte diferente del modelo y usar inyección de dependencia o alguna técnica similar para conectar la implementación. Así que elimínalo del registro.La autorización generalmente no es parte de su modelo de dominio, a menos que sea parte del dominio, por ejemplo, si está escribiendo software de seguridad. La mecánica de quién puede realizar qué en una aplicación normalmente se maneja en el "borde" del nivel de negocio / dominio, las partes públicas con las que las partes de la interfaz de usuario y la integración realmente pueden hablar: el controlador en MVC, los servicios o el sistema de mensajería en sí mismo en una SOA ... obtienes la imagen.
Las fábricas (y supongo que se refiere a fábricas abstractas aquí) no son exactamente malas para tener en un modelo de dominio, pero casi siempre son innecesarias. Normalmente solo tienes una fábrica cuando la mecánica interna de la creación de objetos puede cambiar. Pero solo tiene una implementación del modelo de dominio, lo que significa que solo habrá un tipo de fábrica que siempre invoque los mismos constructores y otro código de inicialización.
Puede tener fábricas de "conveniencia" si lo desea, clases que encapsulan combinaciones comunes de parámetros de constructor, etc., pero honestamente, en términos generales, si tiene muchas fábricas en su modelo de dominio, entonces solo está desperdiciando líneas de código
Entonces, una vez que elimines todo eso, eso solo deja la validación. Ese es el único que es un poco complicado.
La validación es parte de su modelo de dominio, pero también es parte de todos los demás componentes de la aplicación. Su interfaz de usuario y su base de datos tendrán sus propias reglas de validación similares pero diferentes, basadas en un modelo conceptual similar pero diferente. No se especifica realmente si los objetos necesitan o no un
Validate
método, pero incluso si lo tienen, generalmente lo delegarán a una clase de validador (no a la interfaz; la validación no es abstracta en el modelo de dominio, es fundamental).Tenga en cuenta que el validador sigue siendo técnicamente parte del modelo; no necesita estar conectado a una raíz agregada porque no contiene ningún dato o estado. Los modelos de dominio son elementos conceptuales, que generalmente se traducen físicamente en un conjunto o una colección de conjuntos. No se preocupe por el problema "anémico" si su código de delegación reside muy cerca del modelo de objetos; Todavía cuenta.
Lo que todo esto realmente se reduce a es que si vas a hacer DDD, usted tiene que entender lo que el dominio es . Si todavía estás hablando de cosas como la persistencia y la autorización, entonces estás en el camino equivocado. El dominio representa el estado de ejecución de un sistema: los objetos y atributos físicos y conceptuales. Cualquier cosa que no sea directamente relevante para los objetos y las relaciones en sí no pertenece al modelo de dominio, punto.
Como regla general, al considerar si algo pertenece o no en el modelo de dominio, hágase la siguiente pregunta:
"¿Puede esta funcionalidad cambiar alguna vez por razones puramente técnicas?" En otras palabras, ¿no se debe a algún cambio observable en el negocio o dominio del mundo real?
Si la respuesta es "sí", entonces no pertenece al modelo de dominio. No es parte del dominio.
Existe una muy buena posibilidad de que, algún día, cambie sus infraestructuras de persistencia y autorización. Por lo tanto, no son parte del dominio, son parte de la aplicación. Esto también se aplica a algoritmos, como ordenar y buscar; no debe ir e introducir una implementación de código de búsqueda binaria en su modelo de dominio, porque su dominio solo se ocupa del concepto abstracto de búsqueda, no de cómo funciona.
Si, después de haber eliminado todas las cosas que no importan, encuentra que el modelo de dominio es realmente anémico , entonces eso debería servir como una buena indicación de que DDD es simplemente el paradigma incorrecto para su proyecto.
Algunos dominios son realmente anémicos. Las aplicaciones de marcadores sociales realmente no tienen mucho de un "dominio" para hablar; Todos sus objetos son básicamente datos sin funcionalidad. Un sistema de ventas y CRM, por otro lado, tiene un dominio bastante pesado; cuando carga una
Rate
entidad, existe una expectativa razonable de que realmente puede hacer cosas con esa tasa, como aplicarla a una cantidad de pedido y hacer que descubra los descuentos por volumen y los códigos de promoción y todas esas cosas divertidas.Objetos de dominio que acaba de celebrar los datos por lo general no significa que usted tiene un modelo de dominio anémico, pero eso no necesariamente significa que se ha creado un mal diseño - que sólo podría significar que el dominio de sí mismo es anémica y que usted debe utilizar una metodología diferente
fuente
No. La autorización es una preocupación en sí misma. Los comandos que no serían válidos debido a la falta de permisos deben rechazarse antes del dominio, lo antes posible, lo que significa que a menudo incluso querremos verificar la autorización de un comando potencial para construir la interfaz de usuario (para no incluso mostrarle al usuario la opción de editar).
Compartir estrategias de autorización entre capas (en la interfaz de usuario y más arriba en un controlador de servicio o comando) es más fácil cuando la autorización se compone por separado del modelo de dominio.
Una parte difícil que se puede encontrar es la autorización contextual, donde un comando puede o no permitirse no solo en función de los roles de los usuarios sino también de los datos / reglas de la empresa.
También diría que no, no en el dominio (principalmente). La validación ocurre en diferentes contextos, y las reglas de validación a menudo difieren entre contextos. Rara vez existe un sentido simple y absoluto de válido o no válido cuando se consideran los datos encapsulados por un agregado.
Además, al igual que la autorización, utilizamos la lógica de validación en todas las capas: en la interfaz de usuario, en el servicio o en el controlador de comandos, etc. Una vez más, es más fácil emplear DRY con validación si es un componente separado. Desde un punto de vista práctico, la validación (particularmente cuando se usan frameworks) requiere exponer datos que de otro modo deberían encapsularse y a menudo requiere que se adjunten atributos personalizados a campos y propiedades. Prefiero que estos estén en otras clases que mis modelos de dominio.
Prefiero duplicar algunas propiedades en un par de clases similares que intentar forzar los requisitos para un marco de validación en mis entidades. Eso inevitablemente termina haciendo un desastre de las clases de entidad.
Yo uso una capa de indirección. En mis proyectos más recientes, este es un comando + controlador para crear algo, es decir
CreateNewAccountCommand
. Una alternativa podría ser usar siempre una fábrica (aunque eso puede ser incómodo si el resto de las operaciones de una entidad están expuestas por una clase de servicio que está separada de la clase de fábrica).En general, sin embargo, trato de ser más flexible con las opciones de diseño para la creación de objetos.
new
Es fácil y familiar, pero no siempre es suficiente. Creo que usar el juicio aquí y permitir que diferentes partes de un sistema usen diferentes estrategias según sea necesario es importante.Rara vez es una buena idea; Creo que hay mucha experiencia compartida para respaldar eso.
Quizás un modelo de dominio no sea la opción correcta para esta parte de su aplicación.
fuente
Vale, aquí va por mí. Voy a evitar esto diciendo que:
La optimización prematura (y eso incluye el diseño) a menudo puede causar problemas.
IANMF (no soy Martin Fowler);)
Un pequeño secreto sucio es que en proyectos de pequeño tamaño (incluso posiblemente medianos), lo que importa es la consistencia de su enfoque.
Autorización
Para mí, la autenticación y la autorización siempre es una preocupación transversal. En mi pequeño y feliz mundo Java, eso se delega a Spring Security o al marco Apache Shiro.
Validación Para mí, la validación es parte del objeto, ya que lo veo como la definición del objeto.
Por ejemplo, un objeto Car tiene 4 ruedas (OK, hay algunas excepciones raras, pero ignoremos el extraño Car de 3 ruedas por ahora). Un automóvil simplemente no es válido a menos que tenga 4 (en mi mundo), por lo que la validación es parte de la definición de un automóvil. Eso no significa que no pueda tener una clase de validación auxiliar.
En mi feliz mundo Java uso marcos de validación de Bean y uso anotaciones simples en la mayoría de mis campos de Bean. Es fácil validar su objeto sin importar en qué capa se encuentre.
Creación de objetos
Veo las clases de Fábrica con precaución. Demasiado a menudo he visto la
xyxFactoryFactory
clase;)Tiendo a crear un
new
objeto según sea necesario, hasta que me encuentro con un caso en el que se justifica la inyección de dependencia (y dado que trato de seguir un enfoque TDD, esto aparece con mayor frecuencia).En mi feliz mundo Java, eso es cada vez más Guice, pero de Spring sigue siendo el Rey aquí.
Persistencia
Así que este es un debate que se desarrolla en círculos y rotondas y siempre tengo dos ideas al respecto.
Algunos dicen que si miras el objeto de una manera "pura", la persistencia no es una propiedad central, es simplemente una preocupación externa.
Otros consideran que sus objetos de dominio implementan implícitamente una interfaz 'persistente' (sí, sé que me estoy estirando aquí). Por lo tanto, está bien tener varios métodos
save
,delete
etc. en ellos. Esto se ve como un enfoque pragmático y muchas tecnologías ORM (JPA en mi feliz mundo Java) tratan los objetos de esta manera.Por una cuestión de seguridad transversal, me aseguro de que los permisos de edición / eliminación / agregar / lo que se establezcan correctamente en el servicio que llama al método guardar / actualizar / eliminar en el objeto. Si soy realmente paranoico, incluso podría establecer los permisos en el objeto de dominio en sí.
HTH!
fuente
Jimmy Nilsson toca este tema en su libro sobre DDD. Comenzó con un modelo anémico, pasó a modelos no anémicos en un proyecto posterior y finalmente se decidió por modelos anémicos. Su razonamiento fue que los modelos anémicos podrían reutilizarse en múltiples servicios con diferentes lógicas comerciales.
La compensación es la falta de capacidad de descubrimiento. Los métodos que puede utilizar para operar en sus modelos anémicos se extienden a través de un conjunto de servicios ubicados en otros lugares.
fuente
Esta pregunta se hizo hace mucho tiempo, pero está etiquetada con Diseño controlado por dominio. Creo que la pregunta en sí contiene un malentendido fundamental de toda la práctica y las respuestas, incluida la respuesta aceptada, perpetúan un malentendido fundamental.
No existe "el modelo de dominio" en una arquitectura DDD.
Tomemos la autorización como ejemplo. Déjame pedirte que pienses en una pregunta: imagina que dos usuarios diferentes se autentican con tu sistema. Un usuario tiene permiso para cambiar una determinada entidad, pero el otro no. Por qué no?
Odio los ejemplos simples y artificiales porque a menudo confunden más de lo que iluminan. Pero supongamos que tenemos dos dominios diferentes. Primero es una plataforma CMS para una agencia de marketing. Esta agencia tiene muchos clientes que tienen contenido en línea que debe ser administrado por redactores y artistas gráficos. El contenido incluye publicaciones de blog, así como páginas de destino para diferentes clientes.
El otro dominio es la gestión de inventario para una empresa de calzado. El sistema gestiona el inventario desde el momento en que llega desde el fabricante en Francia, a los centros de distribución en los Estados Unidos continentales, a las tiendas minoristas en los mercados locales y, finalmente, al cliente que compra los zapatos en el comercio minorista.
Si cree que las reglas de autorización son las mismas para ambas compañías, entonces sí, sería un buen candidato para un servicio fuera del dominio. Pero dudo que las reglas de autorización sean las mismas. Incluso los conceptos detrás de los usuarios serían diferentes. Ciertamente, el lenguaje sería diferente. La agencia de marketing probablemente tiene funciones como autor de publicaciones y propietario de activos, mientras que la compañía de zapatos probablemente tiene funciones como empleado de envío o gerente de almacén o gerente de tienda.
Estos conceptos probablemente tienen todo tipo de reglas de permisos asociadas con ellos que deben modelarse en el dominio. Pero eso no significa que todos sean parte del mismo modelo, incluso dentro de la misma aplicación. Porque recuerda que hay diferentes contextos limitados.
Entonces, tal vez se podría considerar que un modelo de dominio no anémico en el contexto de Autorización es diferente del contexto de enrutamiento de envíos de calzado a tiendas con poco inventario o enrutamiento de visitantes del sitio a la página de destino apropiada, según el anuncio en el que hicieron clic.
Si se encuentra con modelos de dominio anémico, tal vez simplemente necesite pasar más tiempo en el mapeo de contexto antes de comenzar a escribir código.
fuente