Una parte del diseño impulsado por dominios sobre la 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 no parece que esté avanzando mucho ...
Usan entidades de dominio donde quieran 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 comercial en hacer algo así, porque ahora tiene un objeto de interfaz de usuario para mantener así como el objeto de dominio original.
Así que estoy buscando algunas razones concretas que pueda utilizar para respaldar esto. Específicamente:
- ¿Por qué no deberíamos utilizar objetos de dominio en nuestra capa de presentación?
(si la respuesta es obvia, 'desacoplamiento', explique por qué esto es importante en este contexto) - ¿Deberíamos usar objetos o construcciones adicionales para aislar nuestros objetos de dominio de la interfaz?
Respuestas:
Simplemente, la razón es 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, se agregan cosas 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 su capa empresarial (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 al realizar cambios aparentemente benignos en sus objetos comerciales.
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 forma con la que se puede comunicar; no se exponen detalles de implementación (es decir, objetos de dominio) sobre la interfaz. Sí, esto significa que debe implementar sus objetos de dominio en dos ubicaciones; su capa de interfaz y en su capa BO. Pero esa reimplementación, aunque inicialmente puede parecer un trabajo adicional, ayuda a reforzar el desacoplamiento que ahorrará TONELADAS de trabajo en algún momento en el futuro.
fuente
Yo mismo he luchado con esto. Hay casos en los que tiene sentido utilizar un DTO en la presentación. Digamos que quiero mostrar un menú desplegable de Empresas en mi sistema y necesito su identificación para vincular el valor.
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 en mi humilde opinión.
Ahora tome otro ejemplo. Tengo un objeto que representa una estimación, esta estimación puede estar compuesta por mano de obra, equipo, etc., puede tener muchos cálculos definidos por el usuario que toman todos estos elementos y los resumen (cada estimación podría ser diferente con diferentes tipos de cálculos). ¿Por qué debería modelar este objeto dos veces? ¿Por qué no puedo simplemente hacer que mi interfaz de usuario enumere los cálculos y los muestre?
Por lo general, 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 comercial? Bueno, digo que esto es bueno. Su interfaz de usuario no debería tener la responsabilidad exclusiva de validar sus objetos comerciales. Su capa empresarial DEBE realizar su propia validación.
¿Por qué pondrías el código de generación de UI en un objeto busienss? En mi caso, tengo objetos separados que generan el código de la interfaz de usuario por separado de la interfaz de usuario. Tengo varios objetos que convierten mis objetos comerciales en Xml, la idea de que tenga que separar sus capas para evitar este tipo de contaminación es tan ajena para mí porque ¿por qué poner código de generación HTML en un objeto comercial ...
Editar Como pienso un poco más, hay casos en los que la información de la interfaz de usuario puede pertenecer a la capa de dominio. Y esto podría nublar lo que usted llama una capa de dominio, pero trabajé en una aplicación de múltiples inquilinos, que tenía un comportamiento muy diferente tanto en la apariencia de la interfaz de usuario como en el flujo de trabajo funcional. Depende de varios 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 la interfaz de usuario (etiquetas para campos genéricos, por ejemplo).
Si tuviera que diseñar mis objetos para hacerlos persistentes, ¿debería también tener que 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 usa DDD, ¿son todas las entidades persistentes objetos de dominio? Sé en mi ejemplo que lo fueron.
fuente
Lo hace por la misma razón por la que mantiene SQL fuera de sus páginas ASP / JSP.
Si mantiene solo un objeto de dominio, para usarlo en la presentación Y la capa de dominio, ese objeto pronto se vuelve monolítico. Comienza a incluir código de validación de la interfaz de usuario, código de navegación de la interfaz de usuario y código de generación de la interfaz de usuario. Luego, pronto agregará todos los métodos de la capa empresarial además de eso. Ahora su capa empresarial y la interfaz de usuario están todas mezcladas, y todas están jugando con 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 realizar la validación comercial. Oh, también debe incluir estas otras 85 clases no relacionadas porque se hace referencia a ellas en la capa empresarial, que resulta estar en el mismo archivo.
fuente
Estoy en desacuerdo.
Creo que la mejor manera de hacerlo es comenzar con los objetos de dominio en su capa de presentación HASTA QUE TIENE SENTIDO HACER LO CONTRARIO.
Contrariamente a la creencia popular, "Objetos de dominio" y "Objetos de valor" pueden coexistir felizmente en la capa de presentación. Y esta es la mejor manera de hacerlo: obtiene el beneficio de ambos mundos, duplicación reducida (y código repetitivo) con los objetos de dominio; y la adaptación y simplificación conceptual del uso de objetos de valor en las solicitudes.
fuente
La respuesta depende de la escala de su aplicación.
Aplicación simple CRUD (crear, leer, actualizar, eliminar)
Para las aplicaciones básicas de crud, no tiene ninguna funcionalidad. Agregar DTO encima de las entidades sería una pérdida de tiempo. Aumentaría la complejidad sin aumentar la escalabilidad.
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 empresarial asociada a ellas.
Agregar DTO en este caso es una buena idea por algunas razones:
Aplicación empresarial complicada
Una sola entidad puede necesitar múltiples formas de presentación. Cada uno de ellos necesitará un conjunto de campos diferente. En este caso, encontrará los mismos problemas que en el ejemplo anterior, además de tener que controlar la cantidad de campos visibles para cada cliente. Tener un DTO separado para cada cliente le ayudará a elegir lo que debería ser visible.
fuente
Estamos usando 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 debe cortarse en trozos más pequeños para poder serializarlo sin que se haga 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 se pueden serializar y no se pueden enviar al cliente. Por ejemplo, 'Tipo' o cualquier clase genérica. Deben ser no genéricos y Type debe transferirse como 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 el enlace de datos y muchas entidades tienen muchas propiedades redundantes solo para fines de interfaz de usuario. Además, hay muchos 'BrowsableAttribute' y otros en el modelo de entidad. Esto es realmente malo.
Al final, creo que es solo una cuestión de qué camino es más fácil. Puede que haya proyectos en los que funcione bien y no sea necesario escribir otro modelo DTO.
fuente
Se trata en su mayor parte de dependencias. La estructura funcional central de la organización tiene sus propios requisitos funcionales, y la interfaz de usuario debería permitir a las personas modificar y ver el núcleo; pero el núcleo en sí no debería ser necesario para adaptarse a la interfaz de usuario. (Si es necesario que suceda, suele ser una indicación de que el núcleo no tiene un diseño de propiedad).
Mi sistema contable tiene una estructura y contenido (y datos) que se supone deben modelar el funcionamiento de mi empresa. Esa estructura es real y existe independientemente del software de contabilidad que utilice. (Inevitablemente, un paquete de software determinado contiene estructura y contenido por sí mismo, 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 y de forma completa e independiente como sea posible. Luego, es de esperar que la interfaz de usuario facilite hacer el trabajo de la manera más transparente posible y de la manera más productiva posible.
Las interfaces se refieren a las entradas y vistas proporcionadas para el núcleo funcional invariante y modelado correctamente.
fuente
Maldita sea, te juro que esto dijo persistencia.
De todos modos, es una instancia más de lo mismo: la ley de Parnas dice que un módulo debe mantener 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 quiere presentar los precios en dólares con texto en mandarín. El dominio es el mismo; la presentación puede cambiar. Entonces, para minimizar la fragilidad del sistema, es decir, la cantidad de cosas que se deben cambiar para implementar un cambio en los requisitos, separe las preocupaciones.
fuente
Su presentación puede hacer referencia a su capa de dominio, pero no debe haber ningún vínculo directo desde su interfaz de usuario a sus objetos de dominio. Los objetos de dominio no están diseñados para el uso de la interfaz de usuario, ya que a menudo, si se diseñan correctamente, 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 interfaz de usuario al dominio, probablemente se creará muchos dolores de cabeza. Tienen dos propósitos diferentes.
fuente
Quizás no esté conceptualizando la capa de interfaz de usuario en términos suficientemente amplios. Piense en términos de múltiples formas de respuesta (páginas web, respuesta 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 que 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 usan la misma versión de Firefox". Pero, ¿y en 5 o 10 años?
fuente
Consulte también la sección "Propagación de datos entre capas" a continuación, que creo que presenta argumentos convincentes:
http://galaxy.andromda.org/docs/andromda-documentation/andromda-getting-started-java/java/index.html
fuente
Con la ayuda de herramientas como ' Value Injecter ' y el concepto de 'Mappers' en la capa de presentación mientras se trabaja con vistas, es mucho más fácil entender cada fragmento de código. Si tienes un poco de código, no verás las ventajas de inmediato pero cuando tu proyecto crezca cada vez más, estarás muy contento mientras trabajas con las vistas para no tener que entrar en la lógica de los servicios, repositorios para comprender 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 en usar el modelo de vista es si su proyecto es 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 cambia y algunos controles en las vistas no se vincularán al modelo y no tiene un concepto de modelo de vista, comenzará a agregar parches en muchos lugares y comenzará a tener un código heredado que no lo apreciarás. Claro, puede hacer un poco de refactorización para transformar su modelo de vista en modelo de vista y seguir el principio YAGNI sin agregar código si no lo necesita, pero para mí, es mucho más una mejor práctica que debo seguir para agregar un capa de presentación que expone solo objetos de modelo de vista.
fuente
Aquí hay 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 interfaz de usuario 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 indicador tenía una sección roja, verde y roja, es decir, podría tener muy poco o demasiado de cada componente, pero había un nivel verde seguro en el medio.
Sin pensarlo mucho, modelé mi lógica empresarial para proporcionar 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, moles o porcentaje). Luego modelé mi interfaz de usuario 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 significó que cuando más tarde tuve que mostrar 12 componentes, simplemente mapeé los datos adicionales en 12 nuevos modelos de vista de indicador y aparecieron en la pantalla. También significaba que podía reutilizar fácilmente el control del medidor y hacer que mostraran otros conjuntos de datos.
Si hubiera acoplado estos medidores 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. Me he encontrado con problemas muy similares al modelar calendarios en la interfaz de usuario. Si existe el requisito de que una cita del calendario se vuelva roja cuando hay más de 10 asistentes, entonces la lógica empresarial para manejar esto debería permanecer en la capa empresarial y todo lo que el calendario en la interfaz de usuario necesita saber es que se le ha indicado que se pone rojo, no debería ser necesario saber por qué.
fuente
La única razón sensata para agregar un mapeo adicional entre la semántica generalizada y específica del dominio es que tiene (acceso a) un cuerpo de código existente (y herramientas) que se basan 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 utilizan junto con un conjunto ortogonal de marcos de dominio funcionales (como ORM, GUI, flujo de trabajo, etc.). Recuerde siempre que solo en las adyacencias de la capa externa es necesario exponer la semántica del dominio. Normalmente, este es el front-end (GUI) y el back-end persistente (RDBM, ORM). Cualquier capa intermedia diseñada eficazmente puede y debe ser invariante en el dominio.
fuente