Diseño impulsado por el dominio: servicio de dominio, servicio de aplicación

¿Puede alguien explicar la diferencia entre el dominio y los servicios de la aplicación proporcionando algunos ejemplos? Y, si un servicio es un servicio de dominio, ¿pondría la implementación real de este servicio dentro del ensamblado de dominio y, de ser así, también inyectaría repositorys en ese servicio de dominio? Alguna información sería realmente útil.

Los servicios vienen en 3 sabores: servicios de dominio , servicios de aplicaciones y servicios de infraestructura

  • Servicios de dominio : encapsula la lógica empresarial que no encaja de forma natural en un objeto de dominio, y NO son operaciones CRUD típicas, sino que pertenecen a un repository .
  • Servicios de aplicación : utilizados por consumidores externos para hablar con su sistema (piense en servicios web ). Si los consumidores necesitan acceso a las operaciones de CRUD, estarían expuestos aquí.
  • Servicios de infraestructura : se utilizan para abstraer inquietudes técnicas (por ejemplo, MSMQ, proveedor de correo electrónico, etc.)

Mantener los servicios de dominio junto con sus objetos de dominio es sensato: todos están enfocados en la lógica de dominio. Y sí, puedes inyectar Repositorios en tus Servicios.

Los servicios de aplicaciones generalmente usarán los servicios de dominio y los repositorys para tratar las solicitudes externas.

¡Espero que ayude!

(Si no tiene ganas de leer, hay un resumen en la parte inferior 🙂

Yo también he luchado con la definición precisa de los servicios de aplicación. Aunque la respuesta de Vijay fue muy útil para mi proceso de pensamiento hace un mes, he llegado a estar en desacuerdo con parte de ella.

Otros recursos

Hay muy poca información sobre los servicios de aplicaciones. Temas como raíces agregadas, repositorys y servicios de dominio se discuten extensamente, pero los servicios de aplicaciones solo se mencionan brevemente o se omiten por completo.

El artículo de MSDN Magazine, Introducción al diseño impulsado por dominio, describe los servicios de aplicaciones como una forma de transformar y / o exponer su modelo de dominio a clientes externos, por ejemplo, como un servicio WCF. Así es como Vijay también describe los servicios de aplicaciones. Desde este punto de vista, los servicios de aplicaciones son una interfaz para su dominio .

Los artículos de Jeffrey Palermo sobre la architecture de la cebolla (primera parte, dos y tres ) son una buena lectura. Trata los servicios de aplicaciones como conceptos de nivel de aplicación , como la sesión de un usuario. Aunque esto está más cerca de mi comprensión de los servicios de aplicación, todavía no está en línea con mis pensamientos sobre el tema.

Mis pensamientos

He llegado a pensar en los servicios de aplicaciones como dependencias proporcionadas por la aplicación . En este caso, la aplicación podría ser una aplicación de escritorio o un servicio WCF.

Dominio

Tiempo para un ejemplo Comienzas con tu dominio. Todas las entidades y cualquier servicio de dominio que no dependa de recursos externos se implementan aquí. Todos los conceptos de dominio que dependen de recursos externos están definidos por una interfaz. Aquí hay un posible diseño de la solución (nombre del proyecto en negrita):

 Mi solución
 - My.Product.Core (My.Product.dll)
   - DomainServices
       IExchangeRateService
     Producto
     ProductFactory
     IProductRepository

Las clases Product y ProductFactory se han implementado en el ensamblaje central. El IProductRepository es algo que probablemente esté respaldado por una base de datos. La implementación de esto no es asunto del dominio y, por lo tanto, está definida por una interfaz.

Por ahora, nos centraremos en IExchangeRateService . La lógica comercial para este servicio es implementada por un servicio web externo. Sin embargo, su concepto sigue siendo parte del dominio y está representado por esta interfaz.

Infraestructura

La implementación de las dependencias externas forma parte de la infraestructura de la aplicación:

 Mi solución
 + My.Product.Core (My.Product.dll)
 - My.Product.Infrastructure (My.Product.Infrastructure.dll)
   - DomainServices
       XEExchangeRateService
     SqlServerProductRepository

XEExchangeRateService implementa el servicio de dominio IExchangeRateService comunicándose con xe.com . Las aplicaciones que utilizan su modelo de dominio pueden usar esta implementación al incluir el conjunto de infraestructura.

Solicitud

Tenga en cuenta que aún no he mencionado los servicios de aplicaciones. Veremos ésos ahora. Digamos que queremos proporcionar una implementación IExchangeRateService que use un caché para búsquedas rápidas. El esquema de esta clase de decorador podría verse así.

 public class CachingExchangeRateService : IExchangeRateService { private IExchangeRateService service; private ICache cache; public CachingExchangeRateService(IExchangeRateService service, ICache cache) { this.service = service; this.cache = cache; } // Implementation that utilizes the provided service and cache. } 

Observe el parámetro ICache ? Este concepto no es parte de nuestro dominio, por lo que no es un servicio de dominio. Es un servicio de aplicación . Es una dependencia de nuestra infraestructura que puede ser proporcionada por la aplicación. Vamos a presentar una aplicación que demuestre esto:

 Mi solución
 - My.Product.Core (My.Product.dll)
   - DomainServices
       IExchangeRateService
     Producto
     ProductFactory
     IProductRepository
 - My.Product.Infrastructure (My.Product.Infrastructure.dll)
   - ApplicationServices
       ICache
   - DomainServices
       CachingExchangeRateService
       XEExchangeRateService
     SqlServerProductRepository
 - My.Product.WcfService (My.Product.WcfService.dll)
   - ApplicationServices
       MemcachedCache
     IMyWcfService.cs
   + MyWcfService.svc
   + Web.config

Todo esto se combina en la aplicación de esta manera:

 // Set up all the dependencies and register them in the IoC container. var service = new XEExchangeRateService(); var cache = new MemcachedCache(); var cachingService = new CachingExchangeRateService(service, cache); ServiceLocator.For().Use(cachingService); 

Resumen

Una aplicación completa consta de tres capas principales:

  • dominio
  • infraestructura
  • solicitud

La capa de dominio contiene las entidades de dominio y los servicios de dominio independientes. Todos los conceptos de dominio (esto incluye servicios de dominio, pero también repositorys) que dependen de recursos externos, están definidos por interfaces.

La capa de infraestructura contiene la implementación de las interfaces desde la capa de dominio. Estas implementaciones pueden introducir nuevas dependencias no de dominio que deben proporcionarse a la aplicación. Estos son los servicios de aplicaciones y están representados por interfaces.

La capa de aplicación contiene la implementación de los servicios de la aplicación. La capa de aplicación también puede contener implementaciones adicionales de interfaces de dominio, si las implementaciones proporcionadas por la capa de infraestructura no son suficientes.

Aunque esta perspectiva puede no coincidir con la definición general de DDD de servicios, sí separa el dominio de la aplicación y le permite compartir el conjunto de dominio (y la infraestructura) entre varias aplicaciones.

El mejor recurso que me ayudó a entender la diferencia entre un Servicio de aplicación y un Servicio de dominio fue la implementación de Java del ejemplo de carga de Eric Evans, que se encuentra aquí . Si no la descarga, puede consultar las partes internas de RoutingService (un servicio de dominio) y BookingService, CargoInspectionService (que son servicios de aplicación).

Mi momento ‘aha’ fue provocado por dos cosas:

  • Leyendo la descripción de los Servicios en el enlace de arriba, más precisamente esta frase:

Los servicios de dominio se expresan en términos del lenguaje ubicuo y los tipos de dominio, es decir, los argumentos de método y los valores de retorno son clases de dominio adecuadas.

  • Leyendo esta publicación de blog , especialmente esta parte:

Lo que encuentro de gran ayuda para separar las manzanas de las naranjas es pensar en términos del flujo de trabajo de la aplicación. Toda la lógica concerniente al flujo de trabajo de la aplicación generalmente termina siendo Servicios de Aplicación factorizados en la Capa de Aplicación, mientras que los conceptos del dominio que no parecen ajustarse como objetos modelo terminan formando uno o más Servicios de Dominio.

El servicio de dominio es la extensión del dominio. Debe verse solo en el contexto del dominio. Esta no es una acción del usuario como, por ejemplo, cerrar una cuenta o algo así. El servicio de dominio se adapta donde no hay estado. De lo contrario, sería un objeto de dominio. El servicio de dominio hace algo que solo tiene sentido cuando se realiza con otros colaboradores (objetos de dominio u otros servicios). Y ese sentido tiene la responsabilidad de otra capa.

El servicio de aplicaciones es la capa que inicializa y supervisa la interacción entre los objetos de dominio y los servicios. El flujo es generalmente así: obtener el objeto de dominio (u objetos) del repository, ejecutar una acción y ponerlo (ellos) allí (o no). Puede hacer más, por ejemplo, puede verificar si un objeto de dominio existe o no y lanzar excepciones en consecuencia. Por lo tanto, permite que el usuario interactúe con la aplicación (y es probable que provenga de ahí su nombre) manipulando objetos y servicios de dominio. Los servicios de aplicaciones generalmente deberían representar todos los casos de uso posibles. Probablemente, lo mejor que puede hacer antes de pensar en el dominio es crear interfaces de servicios de aplicaciones, lo que le dará una idea mucho mejor de lo que realmente está tratando de hacer. Tener tal conocimiento le permite enfocarse en el dominio.

En general, los repositorys pueden inyectarse en servicios de dominio, pero este es un escenario bastante raro. Sin embargo, es la capa de aplicación quien lo hace la mayor parte del tiempo.

Desde el Libro Rojo (Implementing Domain Driven Design, por Vaughn Vernon), así es como entiendo los conceptos:

Los objetos de dominio ( entidades y objetos de valor ) encapsulan el comportamiento requerido por el (sub) dominio, haciéndolo natural, expresivo y comprensible.

Los servicios de dominio encapsulan esos comportamientos que no encajan en un solo objeto de dominio. Por ejemplo, una biblioteca de libros que presta un Book a un Client (con los cambios de Inventory correspondientes) puede hacerlo desde un servicio de dominio.

Los servicios de aplicaciones manejan el flujo de casos de uso, incluyendo cualquier inquietud adicional necesaria sobre el dominio. A menudo expone dichos métodos a través de su API, para el consumo de clientes externos. Para construir sobre nuestro ejemplo anterior, nuestro servicio de aplicación podría exponer un método LendBookToClient(Guid bookGuid, Guid clientGuid) que:

  • Recupera el Client .
  • Confirma sus permisos. ( Tenga en cuenta cómo hemos mantenido nuestro modelo de dominio libre de preocupaciones de seguridad / administración de usuarios. Dicha contaminación podría generar muchos problemas. En su lugar, cumplimos con este requisito técnico aquí, en nuestro servicio de aplicaciones ) .
  • Recupera el Book
  • Llama al servicio de dominio (pasando el Client y el Book ) para manejar la lógica de dominio real de prestar el libro al cliente. Por ejemplo, imagino que confirmar la disponibilidad del libro es definitivamente parte de la lógica del dominio.

Un servicio de aplicación generalmente debería tener un flujo muy simple. Los flujos complejos de servicios de aplicaciones a menudo indican que la lógica de dominio se ha filtrado fuera del dominio.

Como puede ver, el modelo de dominio se mantiene muy limpio de esta manera, y es fácil de entender y discutir con los expertos en el dominio, ya que solo contiene sus propias preocupaciones comerciales. El flujo de aplicaciones , por otro lado, también es mucho más fácil de administrar, ya que se alivia de las preocupaciones del dominio y se vuelve conciso y directo.

Servicios de dominio: los métodos que realmente no se ajustan a una sola entidad ni requieren acceso al repository están contenidos dentro de los servicios de dominio. La capa de servicio de dominio también puede contener lógica de dominio propia y forma parte del modelo de dominio tanto como entidades como objetos de valor.

Servicios de aplicación: el servicio de aplicación es una capa delgada que se ubica sobre el modelo de dominio y coordina la actividad de la aplicación. No contiene lógica comercial y no posee el estado de ninguna entidad; sin embargo, puede almacenar el estado de una transacción de flujo de trabajo empresarial. Utiliza un servicio de Aplicación para proporcionar una API en el modelo de dominio utilizando el patrón de mensajes Solicitud-Respuesta.

Millett, C (2010). Patrones de diseño de ASP.NET profesionales. Wiley Publishing. 92.