¿Los servicios siempre deben devolver DTO o también pueden devolver modelos de dominio?

Estoy (re) diseñando aplicaciones a gran escala, utilizamos una architecture multicapa basada en DDD.

Tenemos MVC con capa de datos (implementación de repositorys), capa de dominio (definición de modelo de dominio e interfaces – repositorys, servicios, unidad de trabajo), capa de servicio (implementación de servicios). Hasta ahora, usamos modelos de dominio (principalmente entidades) en todas las capas, y utilizamos DTO solo como modelos de vista (en controlador, servicio devuelve modelo (s) de dominio y el controlador crea el modelo de vista, que se pasa a la vista).

Leí innumerables artículos sobre cómo usar, no usar, mapear y pasar DTO. Entiendo que no hay una respuesta definitiva, pero no estoy seguro de si está bien o no devolver los modelos de dominio de los servicios a los controladores. Si devuelvo el modelo de dominio, todavía no se pasa a la vista, ya que el controlador siempre crea un modelo de vista específico para la vista, en este caso, parece legítimo. Por otro lado, no se siente bien cuando el modelo de dominio deja la capa empresarial (capa de servicio). A veces el servicio necesita devolver un objeto de datos que no estaba definido en el dominio y luego tenemos que agregar un nuevo objeto al dominio que no está mapeado, o crear un objeto POCO (esto es feo, ya que algunos servicios devuelven modelos de dominio, algunos efectivamente devuelve DTO).

La pregunta es: si usamos estrictamente los modelos de vista, ¿está bien devolver los modelos de dominio a los controladores, o deberíamos usar siempre los DTO para la comunicación con la capa de servicio? Si es así, ¿está bien ajustar los modelos de dominio según lo que necesitan los servicios? (Francamente, no lo creo, ya que los servicios deberían consumir lo que tiene el dominio). Si nos ceñimos estrictamente a los DTO, ¿deberían definirse en la capa de servicio? (Creo que sí.) A veces está claro que debemos usar DTO (por ejemplo, cuando el servicio realiza mucha lógica comercial y crea objetos nuevos), a veces está claro que debemos usar modelos de dominio (por ejemplo, cuando el servicio de membresía devuelve un usuario anémico) s) – parece que no tendría mucho sentido crear DTO que sea lo mismo que el modelo de dominio) – pero prefiero la coherencia y las buenas prácticas.

Artículo Dominio vs DTO vs ViewModel – ¿Cómo y cuándo usarlos? (y también algunos otros artículos) es muy similar a mi problema, pero no responde a esta (s) pregunta (s). Artículo ¿Debo implementar DTO en el patrón de repository con EF? también es similar, pero no trata con DDD.

Descargo de responsabilidad: no tengo la intención de utilizar ningún patrón de diseño solo porque exista y sea elegante, por otro lado, me gustaría usar buenos patrones de diseño y prácticas también porque ayuda a diseñar la aplicación como un todo, ayuda a la separación de inquietudes, incluso cuando se usa un patrón particular no es “necesario”, al menos en este momento.

Como siempre, gracias.

no se siente bien cuando el modelo de dominio deja la capa empresarial (capa de servicio)

Te hace sentir como si estuvieras sacando las tripas ¿verdad? De acuerdo con Martin Fowler: la capa de servicio define el boundery de la aplicación, encapsula el dominio. En otras palabras, protege el dominio.

A veces el servicio necesita devolver un objeto de datos que no estaba definido en el dominio

¿Puedes dar un ejemplo de este objeto de datos?

Si deberíamos adherirnos estrictamente a los DTO, ¿deberían definirse en la capa de servicio?

Sí, porque la respuesta es parte de su capa de servicio. Si se define “en otro lugar”, entonces la capa de servicio debe hacer referencia a “en otro lugar”, agregando una nueva capa a su lasaña.

¿Está bien devolver los modelos de dominio a los controladores, o deberíamos usar siempre los DTO para la comunicación con la capa de servicio?

Un DTO es un objeto de respuesta / solicitud, tiene sentido si lo usa para la comunicación. Si utiliza modelos de dominio en su capa de presentación (MVC-Controllers / View, WebForms, ConsoleApp), entonces la capa de presentación está estrechamente vinculada a su dominio, cualquier cambio en el dominio requiere que cambie sus controladores.

parece que no tendría mucho sentido crear DTO que sea lo mismo que el modelo de dominio)

Esta es una de las desventajas de DTO para ojos nuevos. En este momento, usted está pensando en la duplicación de código , pero a medida que su proyecto se expanda, tendrá mucho más sentido, especialmente en un entorno de equipo donde se asignan diferentes equipos a diferentes capas.

DTO puede agregar complejidad adicional a su aplicación, pero también lo son sus capas. DTO es una característica costosa de su sistema, no es gratis.

Por qué usar un DTO

Este artículo proporciona ventajas y desventajas de usar un DTO, http://guntherpopp.blogspot.com/2010/09/to-dto-or-not-to-dto.html

Resumen de la siguiente manera:

Cuándo usar

  • Para proyectos grandes.
  • La duración del proyecto es de 10 años o más.
  • Aplicación estratégica y de misión crítica.
  • Grandes equipos (más de 5)
  • Los desarrolladores se distribuyen geográficamente.
  • El dominio y la presentación son diferentes.
  • Reducir los intercambios de datos generales (el propósito original de DTO)

Cuándo no usar

  • Proyecto de tamaño pequeño a mediano (5 miembros máximo)
  • La duración del proyecto es de aproximadamente 2 años.
  • No hay equipo separado para GUI, back-end, etc.

Argumentos contra DTO

  • Duplicación de código.
  • Costo del tiempo de desarrollo, depuración. (use las herramientas de generación de DTO http://entitiestodtos.codeplex.com/ )
  • Debe sincronizar ambos modelos todo el tiempo.
  • Costo del desarrollo: se necesita un mapeo adicional. (use auto mapeadores como https://github.com/AutoMapper/AutoMapper )
  • ¿Por qué los objetos de transferencia de datos son un antipatrón?

Argumentos con DTO

  • Sin DTO, la presentación y el dominio están estrechamente relacionados. (Esto está bien para proyectos pequeños)
  • Interfaz / estabilidad de API
  • Puede proporcionar optimización para la capa de presentación devolviendo un DTO que contiene solo aquellos atributos que son absolutamente necesarios. Usando linq-projection , no es necesario extraer una entidad completa.
  • Para reducir el costo de desarrollo, utilice herramientas generadoras de código

Según mi experiencia, debes hacer lo que sea práctico. “El mejor diseño es el diseño más simple que funciona” – Einstein. Con eso está la mente …

si usamos estrictamente los modelos de vista, ¿está bien devolver los modelos de dominio a los controladores, o deberíamos usar siempre los DTO para la comunicación con la capa de servicio?

¡Absolutamente está bien! Si tiene Entidades de Dominio, DTO y Modelos de Vista que incluyen tablas de base de datos, tiene todos los campos de la aplicación repetidos en 4 lugares. Trabajé en proyectos grandes en los que las entidades de dominio y los modelos de vista funcionaron muy bien. La única excepción a esto es si la aplicación se distribuye y la capa de servicio reside en otro servidor, en cuyo caso se requiere que los DTO se envíen a través del cable por razones de serialización.

Si es así, ¿está bien ajustar los modelos de dominio según lo que necesitan los servicios? (Francamente, no lo creo, ya que los servicios deberían consumir lo que tiene el dominio).

En general, estoy de acuerdo y digo que no porque el modelo de Dominio es típicamente un reflection de la lógica comercial y generalmente no se ve moldeado por el consumidor de esa lógica.

Si deberíamos adherirnos estrictamente a los DTO, ¿deberían definirse en la capa de servicio? (Creo que si.)

Si decides usarlos, estaría de acuerdo y diría que sí, que la capa de Servicio es el lugar perfecto, ya que devuelve los DTO al final del día.

¡Buena suerte!

parece que su aplicación es lo suficientemente grande y compleja ya que ha decidido aplicar el enfoque DDD. No devuelva sus entidades poco o las denominadas entidades de dominio y objetos de valor en su capa de servicio. si desea hacerlo, elimine su capa de servicio porque ya no la necesita. Los objetos View Model o Data Transfer deben vivir en la capa Service porque deben correlacionarse con los miembros del modelo de dominio y viceversa. Entonces, ¿por qué necesitas tener DTO? en una aplicación compleja con muchos escenarios, debe separar las preocupaciones del dominio y las vistas de presentación, un modelo de dominio podría dividirse en varias DTO y también varios modelos de Dominio podrían colapsarse en una DTO. así que es mejor crear su DTO en architecture en capas, incluso si fuera igual a su modelo.

¿Deberíamos siempre usar DTO para la comunicación con la capa de servicio? sí, tiene que devolver DTO por su capa de servicio ya que ha hablado con su repository en la capa de servicio con miembros del modelo de dominio y los asigna a DTO y regresa al controlador MVC y viceversa.

¿Está bien ajustar los modelos de dominio según lo que necesitan los servicios? un servicio solo habla con los métodos de dominio y repository y servicios de dominio, debe resolver el negocio en su dominio según sus necesidades y no es tarea del servicio decirle al dominio lo que se necesita.

Si deberíamos adherirnos estrictamente a los DTO, ¿deberían definirse en la capa de servicio? sí, intenta tener DTO o ViewModel solo en servicio más tarde porque deberían estar asignados a miembros del dominio en la capa de servicio y no es una buena idea colocar DTO en los controladores de tu aplicación (intenta utilizar el patrón Solicitud de respuesta en tu capa de servicio), ¡salud! !

Hasta ahora, usamos modelos de dominio (principalmente entidades) en todas las capas, y utilizamos DTO solo como modelos de vista (en el controlador, el servicio devuelve modelo (s) de dominio y el controlador crea el modelo de vista, que se pasa a la vista).

Dado que el Modelo de dominio proporciona terminología ( Lenguaje ubicuo ) para toda su aplicación, es mejor usar ampliamente el Modelo de dominio.

La única razón para usar ViewModels / DTOs es una implementación del patrón MVC en su aplicación para separar View (cualquier tipo de capa de presentación) y Model (Domain Model). En este caso, su presentación y modelo de dominio están ligeramente acoplados.

A veces el servicio necesita devolver un objeto de datos que no estaba definido en el dominio y luego tenemos que agregar un nuevo objeto al dominio que no está mapeado, o crear un objeto POCO (esto es feo, ya que algunos servicios devuelven modelos de dominio, algunos efectivamente devuelve DTO).

Supongo que hablas de los servicios de Application / Business / Domain Logic.

Le sugiero que devuelva las entidades de dominio cuando pueda. Si es necesario para devolver información adicional, es aceptable devolver DTO que contenga varias entidades de dominio.

En ocasiones, las personas que usan marcos de terceros, que generan proxies sobre entidades de dominio, enfrentan dificultades para exponer las entidades de dominio de sus servicios, pero solo es una cuestión de uso incorrecto.

La pregunta es: si usamos estrictamente los modelos de vista, ¿está bien devolver los modelos de dominio a los controladores, o deberíamos usar siempre los DTO para la comunicación con la capa de servicio?

Diría que es suficiente para devolver entidades de dominio en 99,9% de los casos.

Para simplificar la creación de DTO y mapear sus entidades de dominio en ellos, puede usar AutoMapper .

Sugeriría analizar estas dos preguntas:

  1. ¿Sus capas superiores (es decir, ver y ver modelos / controladores) consumen los datos de una manera diferente a lo que expone la capa de dominio? Si se realiza una gran cantidad de mapeo o incluso lógica, le sugiero volver a visitar su diseño: probablemente debería estar más cerca de cómo se usan realmente los datos.

  2. ¿Qué tan probable es que cambies profundamente tus capas superiores? (por ejemplo, intercambiando ASP.NET por WPF). Si esto es muy diferente y su architecture no es muy compleja, es mejor que exponga tantas entidades de dominio como sea posible.

Me temo que es un tema bastante amplio y realmente se reduce a la complejidad de su sistema y sus requisitos.

Llego tarde a esta fiesta, pero esta es una pregunta tan común e importante que me sentí obligada a responder.

Por “servicios” ¿te refieres a la “capa de aplicación” descrita por Evan en el libro azul ? Asumiré que sí, en cuyo caso la respuesta es que no deberían devolver DTO. Sugiero leer el capítulo 4 en el libro azul, titulado “Aislar el dominio”.

En ese capítulo, Evans dice lo siguiente sobre las capas:

Partición de un progtwig complejo en capas. Desarrolle un diseño dentro de cada capa que sea cohesivo y que dependa solo de las siguientes capas.

Hay una buena razón para esto. Si utiliza el concepto de orden parcial como una medida de la complejidad del software , tener una capa que dependa de una capa superior aumenta la complejidad, lo que disminuye la capacidad de mantenimiento.

Aplicando esto a su pregunta, los DTO son realmente un adaptador que es una preocupación de la capa Interfaz de usuario / Presentación. Recuerde que la comunicación remota / entre procesos es exactamente el propósito de un DTO (vale la pena señalar que en esa publicación Fowler también argumenta en contra de que los DTO sean parte de una capa de servicio, aunque no necesariamente habla el lenguaje DDD).

Si su capa de aplicación depende de esos DTO, depende de una capa superior y su complejidad aumenta. Puedo garantizar que esto boostá la dificultad de mantener su software.

Por ejemplo, ¿qué sucede si su sistema se conecta con otros sistemas o tipos de clientes, cada uno de los cuales requiere su propio DTO? ¿Cómo sabe qué DTO debe devolver un método de su servicio de aplicación? ¿Cómo resolverías ese problema si tu lenguaje de elección no permite sobrecargar un método (método de servicio, en este caso) basado en el tipo de devolución? E incluso si encuentra una manera, ¿por qué violar su capa de aplicación para soportar una preocupación de la capa de presentación?

En términos prácticos, este es un paso por un camino que terminará en una architecture de spaghetti. He visto este tipo de delegación y sus resultados en mi propia experiencia.

Donde trabajo actualmente, los servicios en nuestros objetos de dominio de retorno de la capa de aplicación. No consideramos que esto sea un problema ya que la capa Interfaz (es decir, UI / Presentación) depende de la capa de Dominio, que está debajo de ella. Además, esta dependencia se minimiza a un tipo de dependencia de “solo referencia” porque:

a) la capa de interfaz solo puede acceder a estos objetos de dominio como valores de retorno de solo lectura obtenidos mediante llamadas a la capa de aplicación

b) los métodos sobre servicios en la capa de aplicación aceptan como entrada solo la entrada “en bruto” (valores de datos) o parámetros de objeto (para reducir el conteo de parámetros cuando sea necesario) definidos en esa capa. Específicamente, los servicios de aplicación nunca aceptan objetos de Dominio como entrada.

La Capa de Interfaz usa técnicas de mapeo definidas dentro de la Capa de Interfaz para mapear desde objetos de Dominio a DTOs. De nuevo, esto mantiene a los DTO enfocados en ser adaptadores controlados por la capa de interfaz.