Pregunta

Una parte del diseño controlado por dominio en el que no parece haber muchos detalles, es cómo y por qué debe aislar su modelo de dominio de su interfaz. Estoy tratando de convencer a mis colegas de que esta es una buena práctica, pero parece que no estoy avanzando mucho ...

Usan entidades de dominio donde les plazca en las capas de presentación e interfaz. Cuando les digo que deberían usar modelos de visualización o DTO para aislar la capa de dominio de la capa de interfaz, responden que no ven el valor empresarial de hacer algo así, porque ahora tienes un objeto de IU que mantener. así como el objeto de dominio original.

Así que estoy buscando algunas razones concretas que puedo usar para respaldar esto. Específicamente:

  1. ¿Por qué no deberíamos usar objetos de dominio en nuestra capa de presentación?
    (Si la respuesta es obvia, "desacoplamiento", explique por qué esto es importante en este contexto)
  2. ¿Debemos usar objetos o construcciones adicionales para aislar nuestros objetos de dominio de la interfaz?
¿Fue útil?

Solución

En pocas palabras, la razón es una de implementación y deriva. Sí, su capa de presentación necesita conocer sus objetos comerciales para poder representarlos correctamente. Sí, inicialmente parece que hay mucha superposición entre la implementación de los dos tipos de objetos. El problema es que, a medida que pasa el tiempo, las cosas se agregan en ambos lados. La presentación cambia y las necesidades de la capa de presentación evolucionan para incluir elementos que son completamente independientes de la capa de su negocio (color, por ejemplo). Mientras tanto, los objetos de su dominio cambian con el tiempo y, si no tiene el desacoplamiento adecuado de su interfaz, corre el riesgo de arruinar su capa de interfaz haciendo cambios aparentemente benignos en sus objetos de negocio.

Personalmente, creo que la mejor manera de abordar las cosas es a través del paradigma de interfaz estrictamente aplicado; es decir, su capa de objeto de negocio expone una interfaz que es la única manera de comunicarse con ella; no se exponen detalles de implementación (es decir, objetos de dominio) sobre la interfaz. Sí, esto significa que tiene que implementar los objetos de su dominio en dos ubicaciones; su capa de interfaz y en su capa BO. Pero esa reimplementación, mientras que inicialmente puede parecer un trabajo extra, ayuda a hacer cumplir el desacoplamiento que ahorrará TONELADAS de trabajo en algún momento en el futuro.

Otros consejos

He luchado con esto yo mismo. Hay casos en los que un DTO tiene sentido para usar en la presentación. Digamos que quiero mostrar un menú desplegable de Compañías en mi sistema y necesito su ID para vincular el valor a.

Bueno, en lugar de cargar un CompanyObject que podría tener referencias a suscripciones o quién sabe qué más, podría enviar un DTO con el nombre y la identificación. Este es un buen uso IMHO.

Ahora toma otro ejemplo. Tengo un objeto que representa una Estimación, esta estimación podría estar compuesta de mano de obra, equipo, etc., podría tener muchos cálculos definidos por el usuario que toma todos estos elementos y los resume (cada estimación puede ser diferente con diferentes tipos de cálculos). ¿Por qué debería tener que modelar este objeto dos veces? ¿Por qué no puedo simplemente tener mi UI enumerar sobre los cálculos y mostrarlos?

Generalmente, no uso DTO para aislar mi capa de dominio de mi interfaz de usuario. Los uso para aislar mi capa de dominio de un límite que está fuera de mi control. La idea de que alguien ponga información de navegación en su objeto comercial es ridícula, no contamine su objeto comercial.

¿La idea de que alguien pondría validación en su objeto de negocio? Bueno, yo digo que esto es algo bueno. Su UI no debe tener la responsabilidad exclusiva de validar sus objetos comerciales. Su capa empresarial DEBE hacer su propia validación.

¿Por qué pondría el código de generación de UI en un objeto de busienss? En mi caso, tengo objetos separados que generan el código de UI por separado de la UI. Tengo objetos delimitados que convierten mis objetos comerciales en Xml, la idea de que tiene que separar sus capas para evitar este tipo de contaminación es tan ajena para mí porque, ¿por qué incluiría el código de generación HTML en un objeto comercial ...

Editar A medida que pienso un poco más, hay casos en los que la información de IU puede pertenecer a la capa de dominio. Y esto podría nublar lo que se llama una capa de dominio, pero trabajé en una aplicación multiusuario, que tenía un comportamiento muy diferente tanto en el aspecto como en la interfaz de usuario y en el flujo de trabajo funcional. Dependiendo de diversos factores. En este caso teníamos un modelo de dominio que representaba a los inquilinos y su configuración. Su configuración pasó a incluir información de IU (etiquetas para campos genéricos, por ejemplo).

Si tuviera que diseñar mis objetos para hacerlos persistentes, ¿también debería duplicar los objetos? Tenga en cuenta que si desea agregar un nuevo campo ahora tiene dos lugares para agregarlo. Quizás esto plantea otra pregunta si su uso de DDD, ¿son todas las entidades persistentes objetos de dominio? Sé que en mi ejemplo eran.

Lo haces por el mismo motivo por el que mantienes a SQL fuera de tus páginas ASP / JSP.

Si mantiene solo un objeto de dominio, para usar en la capa de dominio de presentación Y, entonces ese objeto pronto se vuelve monolítico. Comienza a incluir el código de validación de la interfaz de usuario, el código de navegación de la interfaz de usuario y el código de generación de la interfaz de usuario. Luego, pronto agregarás todos los métodos de capa de negocios además de eso. Ahora, su capa de negocios y la interfaz de usuario están mezcladas, y todas se están confundiendo en la capa de la entidad de dominio.

¿Quieres reutilizar ese ingenioso widget de interfaz de usuario en otra aplicación? Bueno, tienes que crear una base de datos con este nombre, estos dos esquemas y estas 18 tablas. También debe configurar Hibernate y Spring (o los marcos de su elección) para hacer la validación comercial. Oh, también debe incluir estas otras 85 clases no relacionadas porque están referenciadas en la capa empresarial, que se encuentra en el mismo archivo.

No estoy de acuerdo.

Creo que la mejor manera de comenzar es comenzar con los objetos de dominio en la capa de presentación HASTA QUE TENGA SENTIDO DE HACER OTRA MANERA.

Contrariamente a la creencia popular, " Objetos de dominio " y " Objetos de valor " felizmente puede coexistir en la capa de presentación. Y esta es la mejor manera de hacerlo: obtienes el beneficio de ambos mundos, la duplicación reducida (y el código de repetición) con los objetos del dominio; y la adaptación y simplificación conceptual del uso de objetos de valor en todas las solicitudes.

Estamos utilizando el mismo modelo en el servidor y en la interfaz de usuario. Y es un dolor. Tenemos que refactorizarlo algún día.

Los problemas se deben principalmente a que el modelo de dominio se debe cortar en partes más pequeñas para poder serializarlo sin tener referencia a toda la base de datos. Esto hace que sea más difícil de usar en el servidor. Faltan enlaces importantes. Algunos tipos tampoco son serializables y no se pueden enviar al cliente. Por ejemplo 'Tipo' o cualquier clase genérica. Deben ser no genéricos y el tipo debe transferirse como una cadena. Esto genera propiedades adicionales para la serialización, son redundantes y confusas.

Otro problema es que las entidades en la interfaz de usuario realmente no encajan. Estamos utilizando enlaces de datos y muchas entidades tienen muchas propiedades redundantes solo para fines de la interfaz de usuario. Además, hay muchos 'atributos de navegación' y otros en el modelo de entidad. Esto es realmente malo.

Al final, creo que es solo una cuestión de qué manera es más fácil. Puede haber proyectos donde simplemente funciona bien y donde no es necesario escribir otro modelo DTO.

La respuesta depende de la escala de su aplicación.


Aplicación CRUD simple (crear, leer, actualizar, eliminar)

Para las aplicaciones básicas no tiene ninguna funcionalidad. Agregar DTO sobre las entidades sería una pérdida de tiempo. Aumentaría la complejidad sin aumentar la escalabilidad.

 ingrese la descripción de la imagen aquí


Aplicación no CRUD moderadamente complicada

En este tamaño de aplicación, tendrá pocas entidades que tengan un ciclo de vida real y alguna lógica comercial asociada.

Agregar DTO en este caso es una buena idea por varias razones:

  • La capa de presentación solo puede ver el subconjunto de campos que tiene la entidad. Encapsulas Entidades
  • Sin acoplamiento entre backend y frontent
  • Si tiene métodos de negocios dentro de entidades, pero no en DTO, agregar DTO significa que el código externo no puede arruinar el estado de su entidad.

 ingrese la descripción de la imagen aquí


Aplicación Enterprise Complicada

Una sola entidad puede necesitar múltiples formas de presentación. Cada uno de ellos necesitará diferentes conjuntos de campos. En este caso, tiene los mismos problemas que en el ejemplo anterior, además de la necesidad de controlar la cantidad de campos visibles para cada cliente. Tener un DTO separado para cada cliente te ayudará a elegir lo que debería estar visible.

 ingrese la descripción de la imagen aquí

Se trata de dependencias en su mayor parte. La estructura funcional central de la organización tiene sus propios requisitos funcionales, y la interfaz de usuario debe permitir a las personas modificar y ver el núcleo; pero el núcleo en sí no debe ser requerido para acomodar la interfaz de usuario. (Si tiene que suceder, generalmente es una indicación de que el núcleo no está diseñado para la propiedad).

Mi sistema de contabilidad tiene una estructura y contenido (y datos) que se supone que deben modelar el funcionamiento de mi empresa. Esa estructura es real y existe independientemente del software de contabilidad que use. (Inevitablemente, un paquete de software dado contiene estructura y contenido por su propio bien, pero parte del desafío es minimizar esta sobrecarga).

Básicamente una persona tiene un trabajo que hacer. El DDD debe coincidir con el flujo y el contenido del trabajo. DDD se trata de hacer explícitos todos los trabajos que deben realizarse de manera completa e independiente como sea posible. Entonces, con suerte, la interfaz de usuario facilita la realización del trabajo de la manera más transparente posible, lo más productivamente posible.

Las interfaces se refieren a las entradas y vistas proporcionadas para el núcleo funcional invariable y modelado correctamente.

Maldición, juro esto dijo persistencia.

De todos modos, es una instancia más de lo mismo: la ley de Parnas dice que un módulo debe guardar un secreto, y el secreto es un requisito que puede cambiar. (Bob Martin tiene una regla que es otra versión de esto). En un sistema como este, la presentación puede cambiar independientemente del dominio . Como, por ejemplo, una empresa que mantiene los precios en euros y utiliza el francés en las oficinas de la empresa, pero desea presentar los precios en dólares con texto en mandarín. El dominio es el mismo; La presentación puede cambiar. Por lo tanto, para minimizar la fragilidad del sistema & # 8212; es decir, la cantidad de cosas que se deben cambiar para implementar un cambio en los requisitos & # 8212; separas las preocupaciones.

Su presentación puede hacer referencia a su capa de dominio, pero no debe haber enlace directamente desde su ui a los objetos de su dominio. Los objetos de dominio no están diseñados para el uso de la interfaz de usuario ya que a menudo, si están diseñados adecuadamente, se basan en comportamientos y no en representaciones de datos. Debe haber una capa de mapeo entre la interfaz de usuario y el dominio. MVVM, o MVP, es un buen patrón para esto. Si intenta vincular directamente su IU al dominio, probablemente creará muchos dolores de cabeza. Tienen dos propósitos diferentes.

Tal vez no esté conceptualizando la capa UI en términos suficientemente amplios. Piense en términos de múltiples formas de respuesta (páginas web, respuestas de voz, letras impresas, etc.) y en términos de múltiples idiomas (inglés, francés, etc.).

Ahora suponga que el motor de voz para el sistema de llamadas telefónicas se ejecuta en un tipo de computadora completamente diferente (Mac, por ejemplo) de la computadora que ejecuta el sitio web (quizás Windows).

Por supuesto, es fácil caer en la trampa "Bueno, en mi empresa solo nos importa el inglés, ejecutamos nuestro sitio web en LAMP (Linux, Apache, MySQL y PHP) y todos usamos la misma versión de Firefox". Pero ¿qué pasa en 5 o 10 años?

Consulte también la sección " Propagación de datos entre capas " en lo siguiente, que creo que presenta argumentos convincentes:

http: // galaxy .andromda.org / docs / andromda-documentation / andromda-getting-started-java / java / index.html

Con la ayuda de herramientas como ' Value Injecter ' y el concepto de 'Mappers' en la capa de presentación Al trabajar con vistas, es mucho más fácil entender cada pieza de código. Si tiene un poco de código, no verá las ventajas de inmediato, pero cuando su proyecto crezca cada vez más, se sentirá muy satisfecho al trabajar con las vistas para no tener que entrar en la lógica de los servicios. Repositorios para entender el modelo de vista. View Model es otro guardia en el vasto mundo de la capa anticorrupción y vale su peso en oro en un proyecto a largo plazo.

La única razón por la que no veo ninguna ventaja de usar el modelo de vista es que su proyecto sea lo suficientemente pequeño y simple como para tener vistas vinculadas directamente a cada propiedad de su modelo. Pero si en el futuro, el requisito de cambio y algunos controles en las vistas no se vincularán al modelo y usted no tiene un concepto de modelo de vista, comenzará a agregar parches en muchos lugares y comenzará a tener un código heredado que usted no apreciará Claro, puede hacer un poco de refactorización para transformar su modelo de vista en view-viewmodel y seguir el principio YAGNI sin agregar código si no lo necesita, pero para mí, es mucho más una práctica recomendada que debo seguir para agregar un capa de presentación que expone únicamente objetos del modelo de vista.

Este es un ejemplo real de por qué me parece una buena práctica separar las entidades de dominio de la vista.

Hace unos meses, creé una IU simple para mostrar los valores de Nitrógeno, Fósforo y Potasio en una muestra de suelo a través de una serie de 3 medidores. Cada medidor tenía una sección roja, verde y roja, es decir, podría tener muy poco o mucho de cada componente, pero había un nivel verde seguro en el centro.

Sin pensarlo mucho, modelé mi lógica empresarial para suministrar datos para estos 3 componentes químicos y una hoja de datos separada, que contiene datos sobre los niveles aceptados en cada uno de los 3 casos (incluida la unidad de medida que se estaba utilizando, es decir, lunares o porcentaje). Luego modelé mi UI para usar un modelo muy diferente, este modelo estaba preocupado por las etiquetas de los indicadores, los valores, los valores de los límites y los colores.

Esto significaba que cuando más tarde tuve que mostrar 12 componentes, simplemente asigné los datos adicionales a 12 nuevos modelos de vista de indicador y aparecieron en la pantalla. También significaba que podía reutilizar el control del medidor fácilmente y hacer que mostraran otros conjuntos de datos.

Si hubiera acoplado estos indicadores directamente en las entidades de mi dominio, no tendría ninguna de la flexibilidad anterior y cualquier modificación futura sería un dolor de cabeza. He encontrado problemas muy similares al modelar calendarios en la interfaz de usuario. Si hay un requisito para que una cita del calendario se vuelva roja cuando haya más de 10 asistentes, entonces la lógica de negocios para manejar esto debería permanecer en la capa de negocios y todo el calendario en la interfaz de usuario debe saber, es que se le ha indicado que se vuelve rojo, no debería necesitar saber por qué.

La única razón sensata para agregar mapeo adicional entre semánticas generalizadas y específicas de dominio es que tiene (acceso a) un cuerpo de código (y herramientas) existente que se basa en una semántica generalizada (pero asignable) distinta de la semántica de su dominio .

Los diseños controlados por dominios funcionan mejor cuando se usan en conjunto con un conjunto ortogonal de marcos funcionales de dominio (como ORM, GUI, flujo de trabajo, etc.). Siempre recuerde que es solo en las adyacencias de la capa externa que la semántica del dominio necesita ser expuesta. Normalmente, este es el extremo delantero (GUI) y el back-end persistente (RDBM, ORM). Cualquier capa intermedia diseñada de manera efectiva puede y debe ser invariante en el dominio.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top