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

268

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

Chris
fuente

Respuestas:

358

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

  • Servicios de dominio : encapsula la lógica de negocios que no encaja naturalmente dentro de un objeto de dominio, y NO son operaciones CRUD típicas; esas pertenecerían a un repositorio .
  • Servicios de aplicación : Usado por consumidores externos para hablar con su sistema (piense en los servicios web ). Si los consumidores necesitan acceso a las operaciones CRUD, estarían expuestos aquí.
  • Servicios de infraestructura : se utilizan para resolver problemas técnicos (por ejemplo, MSMQ, proveedor de correo electrónico, etc.).

Mantener los Servicios de dominio junto con los Objetos de dominio es sensato: todos se centran en la lógica de dominio. Y sí, puede inyectar repositorios en sus servicios.

Los Servicios de aplicación generalmente utilizarán tanto los Servicios de dominio como los Repositorios para atender solicitudes externas.

¡Espero que ayude!

Vijay Patel
fuente
2
¿Dónde pondrías los comandos y consultas de CQRS? ¿Qué servicio los genera y qué servicio los maneja?
inf3rno
55
Creo que los Servicios de aplicaciones deben ser independientes de detalles técnicos como "servicios web", que son utilizados por dichos servicios. Ver servicios en diseño dirigido por dominio
deamon
1
@prograhammer: un ejemplo para un servicio de dominio podría ser FundsTransferService, donde el modelo de dominio es BankAccount, la transferencia podría tener cierta lógica comercial que no cabe directamente en un objeto de cuenta (tomado del libro Evans DDD).
BornToCode
Entonces, por ejemplo, Loginuser () sería un ejemplo de un servicio de dominio. donde como getUsers () sería un servicio de aplicación?
filthy_wizard
Ambos son más bien servicios de aplicaciones porque la autenticación y, a menudo, también las decisiones de autorización no pertenecen al dominio central.
MauganRa
114

(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 aplicaciones. 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, repositorios y servicios de dominio se discuten ampliamente, 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 describe los servicios de aplicaciones también. Desde este punto de vista, los servicios de aplicaciones son una interfaz para su dominio .

Los artículos de Jeffrey Palermo sobre la arquitectura de la cebolla (parte uno , 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 aplicaciones, 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. Empiezas con tu dominio. Aquí se implementan todas las entidades y los servicios de dominio que no dependen de recursos externos. Cualquier concepto de dominio que dependa de recursos externos está definido por una interfaz. Aquí hay un posible diseño de solución (nombre del proyecto en negrita):

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

Las clases Producty ProductFactoryse han implementado en el ensamblaje central. El IProductRepositoryes 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 el IExchangeRateService. La lógica de negocios 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 son 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

XEExchangeRateServiceimplementa el IExchangeRateServiceservicio de dominio comunicándose con xe.com . Esta implementación puede ser utilizada por sus aplicaciones que utilizan su modelo de dominio, incluyendo el ensamblaje de infraestructura.

Solicitud

Tenga en cuenta que aún no he mencionado los servicios de aplicaciones. Los veremos ahora. Digamos que queremos proporcionar una IExchangeRateServiceimplementación 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 ICacheparámetro? 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 proporcionar la aplicación. Vamos a presentar una aplicación que demuestra esto:

Mi solución
- My.Product.Core (My.Product.dll)
  - DomainServices
      IExchangeRateService
    Producto
    ProductFactory
    IProductRepository
- My.Product.Infrastructure (My.Product.Infrastructure.dll)
  - Servicios de aplicación
      Dolor
  - DomainServices
      CachingExchangeRateService
      XEExchangeRateService
    SqlServerProductRepository
- My.Product.WcfService (My.Product.WcfService.dll)
  - Servicios de aplicación
      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<IExchangeRateService>().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. Los conceptos de dominio (esto incluye servicios de dominio, pero también repositorios) que dependen de recursos externos, están definidos por interfaces.

La capa de infraestructura contiene la implementación de las interfaces de la capa de dominio. Estas implementaciones pueden introducir nuevas dependencias que no sean de dominio a las que se debe proporcionar la aplicación. Estos son los servicios de aplicación 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 servicios DDD, separa el dominio de la aplicación y le permite compartir el ensamblaje de dominio (e infraestructura) entre varias aplicaciones.

Niels van der Rest
fuente
2
@ dario-g: tendría que reconstruir / repoblar su modelo de dominio a partir del modelo de solicitud y pasar el modelo de dominio al servicio de dominio. Esta pregunta puede proporcionarle algunas ideas. Si no, avíseme y veré si tengo tiempo para agregar una respuesta a la otra pregunta.
Niels van der Rest
1
@Tiendq: ¿Te refieres a la IExchangeRateServiceinterfaz? Este es un concepto de dominio, es decir, algo que se incluye en el lenguaje omnipresente de su cliente. Otras partes de su dominio pueden depender de este servicio, por lo que su interfaz está definida en la capa de dominio. Pero debido a que su implementación involucra un servicio web externo, la clase de implementación reside en la capa de infraestructura. De esta forma, la capa de dominio solo se ocupa de la lógica empresarial.
Niels van der Rest
44
@Tiendq: en una arquitectura tradicional en capas, la infraestructura suele ser independiente del dominio. Pero en Onion Architecture (ver enlaces en mi respuesta) la infraestructura implementa las dependencias externas del dominio. Pero no diría que la infraestructura depende del dominio, solo lo hace referencia . Tomé el término 'infraestructura' de Onion Architecture, pero 'externos' puede ser un mejor nombre.
Niels van der Rest
1
@Derek: Una de esas 'cosas' podría ser una ExchangeRateinstancia, que contiene una moneda base, una moneda de cambio y el valor del tipo de cambio entre estas dos monedas. Estos valores estrechamente relacionados representan el concepto de "tasa de cambio" del dominio, por lo que estos viven en la capa de dominio. Aunque puede parecer un simple DTO, en DDD se llama un objeto de valor y podría contener lógica de negocios adicional para comparar o transformar instancias.
Niels van der Rest
66
No estoy de acuerdo con la parte en la que no estás de acuerdo con Vijay y aquí está el por qué. CachingExchangeRateService es un problema de infraestructura. Aunque está aceptando genéricamente un ICache, la implementación de ese ICache depende de la tecnología involucrada (es decir, Web, Windows). El hecho de que sea genérico no lo convierte en un servicio de aplicación. Un servicio de aplicación es la API de su dominio. ¿Qué pasaría si quisieras revelar tu dominio a otra persona que está escribiendo una aplicación, qué usarán? Servicios de aplicación, y puede que no tienen por qué el almacenamiento en caché para que su impl almacenamiento en caché es inútil para ellos (que ie.why de infraestructura)
Aaron Hawkins
38

El mejor recurso que me ayudó a comprender la diferencia entre un Servicio de aplicación y un Servicio de dominio fue la implementación en Java del ejemplo de carga de Eric Evans, que se encuentra aquí . Si no lo descarga, puede consultar las partes internas de RoutingService (un servicio de dominio) y el 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 oración:

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

  • Leyendo esto 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 de flujo de trabajo de la aplicación. Toda la lógica relativa 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 encajar como objetos modelo terminan formando uno o más Servicios de dominio.

Ghola
fuente
3
Estoy de acuerdo, así es exactamente como defino los Servicios de aplicación, y se ajusta a todas las situaciones que he conocido hasta ahora. Los Servicios de dominio se ocupan de todo lo relacionado con los objetos de dominio, pero que van más allá del alcance de una sola entidad. Por ejemplo: BookReferencesService.GetNextAvailableUniqueTrackingNumber (), el enfoque es claramente las reglas comerciales *. Con respecto al Servicio de aplicaciones, es exactamente lo que usted describe, la mayoría de las veces empiezo poniendo este flujo de trabajo empresarial en las acciones de mi controlador, y cuando lo noto, refactorizo ​​esta lógica en la capa de servicio de la aplicación. Podríamos decir que esta capa es para casos de uso
tobiak777
1
* Y tales interfaces de servicio de dominio son consumidas por las entidades de dominio.
tobiak777
32

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 cuenta o algo así. El servicio de dominio se ajusta donde no hay estado. De lo contrario, sería un objeto de dominio. El servicio de dominio hace algo que tiene sentido solo cuando se realiza con otros colaboradores (objetos de dominio u otros servicios). Y tener sentido es responsabilidad de otra capa.

Servicio de solicitud es esa capa que inicializa y supervisa la interacción entre los objetos de dominio y los servicios. El flujo generalmente es así: obtener un objeto de dominio (u objetos) del repositorio, ejecutar una acción y volver a colocarlos (o no) allí. Puede hacer más: por ejemplo, puede verificar si un objeto de dominio existe o no y generar excepciones en consecuencia. Por lo tanto, permite que el usuario interactúe con la aplicación (y probablemente aquí es donde se origina su nombre), manipulando objetos y servicios de dominio. Los servicios de aplicación generalmente deben representar todos los casos de uso posibles. Probablemente lo mejor que puede hacer antes de pensar en el dominio es crear interfaces de servicio de aplicaciones que le brinden una visión mucho mejor de lo que realmente está tratando de hacer. Tener ese conocimiento le permite concentrarse en el dominio.

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

kboom
fuente
10
"El servicio de dominio se ajusta donde no hay estado. De lo contrario, sería un objeto de dominio". hizo clic para mí. Gracias.
Nick
32

Del Libro Rojo (Implementing Domain Driven Design, de 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 tales comportamientos que no caben en un solo objeto de dominio. Por ejemplo, una biblioteca de libros que presta a Booka Client(con los Inventorycambios correspondientes ) podría hacerlo desde un servicio de dominio.

Los servicios de aplicaciones manejan el flujo de casos de uso, incluidas las inquietudes adicionales necesarias sobre el dominio. A menudo expone tales métodos a través de su API, para 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. ( Observe cómo hemos mantenido nuestro modelo de dominio libre de problemas de seguridad / gestión de usuarios. Dicha contaminación podría generar muchos problemas. En cambio, cumplimos con este requisito técnico aquí, en nuestro servicio de aplicaciones ) .
  • Recupera el Book.
  • Llama al servicio de dominio (pasando el Clienty 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 debe tener un flujo muy simple. Los flujos de servicios de aplicaciones complejos a menudo indican que la lógica del dominio se ha filtrado 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 de dominio, ya que solo contiene sus propias preocupaciones comerciales reales. El flujo de la aplicación , por otro lado, también es mucho más fácil de administrar, ya que se libera de las preocupaciones del dominio y se vuelve conciso y directo.

Timo
fuente
3
Yo diría que el servicio de aplicaciones también es el punto donde se resuelven las dependencias. Su método es un caso de uso, un flujo único, por lo que puede tomar decisiones informadas sobre implementaciones concretas para su uso. Las transacciones de bases de datos también encajan aquí.
Timo
10

Servicios de dominio: los métodos que realmente no caben en una sola entidad o que requieren acceso al repositorio 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 es tan parte del modelo de dominio como entidades y objetos de valor.

Servicios de aplicación: El servicio de aplicación es una capa delgada que se encuentra por encima del modelo de dominio y coordina la actividad de la aplicación. No contiene lógica de negocios y no contiene 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 profesional ASP.NET. Wiley Publishing. 92)

GorkemHalulu
fuente
7

Servicios de dominio : un servicio que expresa una lógica empresarial que no forma parte de ninguna raíz agregada.

  • Tienes 2 agregados:

    • Product que contiene nombre y precio.
    • Purchase que contiene la fecha de compra, la lista de productos solicitados con la cantidad y el precio del producto en ese momento y el método de pago.
  • Checkout no forma parte de ninguno de estos dos modelos y es un concepto en su negocio.

  • Checkoutse puede crear como un Servicio de dominio que obtiene todos los productos y calcula el precio total, paga el total llamando a otro Servicio de dominio PaymentServicecon una parte de implementación de Infraestructura y lo convierte en Purchase.

Servicios de aplicación : un servicio que "organiza" o ejerce métodos de dominio. Esto puede ser tan simple como solo su controlador.

Este es el lugar donde generalmente haces:

public String createProduct(...some attributes) {
  if (productRepo.getByName(name) != null) {
    throw new Exception();
  }

  productId = productRepository.nextIdentity();

  product = new Product(productId, ...some attributes);

  productRepository.save(product);

  return productId.value();
  // or Product itself
  // or just void if you dont care about result
}

public void renameProduct(productId, newName) {
  product = productRepo.getById(productId);

  product.rename(newName);

  productRepo.save(product);
}

Puede hacer validaciones aquí, como verificar si a Productes único. A menos que unProduct ser único sea invariante, eso debería ser parte del Servicio de dominio que podría llamarse UniqueProductCheckerporque no puede ser parte de la Productclase e interactúa con múltiples Agregados.

Aquí hay un ejemplo completo del proyecto DDD: https://github.com/VaughnVernon/IDDD_Samples

Puede encontrar muchos ejemplos de Servicio de aplicaciones y un par de Servicios de dominio

No importa
fuente
¿Es obligatorio validar y guardar entidades solo en Application Services? Si tengo entidades A, B y C y todas ellas relacionadas entre sí (A -> B -> C) y la operación en A debería causar cambios en B y C al llamar a un Servicio de dominio desde otro, ¿cómo hacerlo?
MrNVK
> ¿Es obligatorio validar y guardar entidades solo en Application Services? Si es necesario, entonces sí. La mayoría de las veces tiene que verificar si existe una ID porque de lo contrario trabajará en una variable nula.
importa
1
> Si tengo entidades A, B y C y todas ellas relacionadas entre sí (A -> B -> C) y la operación en A debería causar cambios en B y C al llamar a un Servicio de dominio desde otro, cómo hacerlo ? No estoy seguro de lo que quiere decir con "llamar a un Servicio de dominio de otro", pero para las reacciones a los cambios de una Entidad, puede usar Eventos o simplemente orquestarlo con el Servicio de aplicación como: agregateA.doOperation (), agregateB.doAnother ( ) Search for: Orchestration vs Choreography
doesnotmatter
Gracias por responder! "llamar a un servicio de dominio desde otro" - quiero decir, si tengo una operación compleja en la entidad A, entonces tengo que usar ADomainService. Pero esta operación, además de la entidad A, afecta a la entidad B. La operación que debe realizarse en la entidad B en el ADomainService también es compleja. Entonces tengo que usar BDomainService de ADomainService. Ahora dudo de este enfoque :) Pero si pongo esta lógica en el ApplicationService, ¿no rompería la encapsulación de los procesos comerciales que solo deberían estar en la capa de dominio, no en la capa de aplicación?
MrNVK
Puede emitir un evento desde su Servicio de dominio si cree que debería estar en un Servicio de dominio en lugar de un Servicio de aplicación.
importa
1

Piense en un Servicio de dominio como un objeto que implementa lógica comercial o lógica relacionada con reglas comerciales en objetos de dominio y esta lógica es difícil de encajar en los mismos objetos de dominio y tampoco causa un cambio de estado del servicio de dominio (el servicio de dominio es un objeto sin un "estado" o mejor sin un estado que tenga un significado comercial) pero que eventualmente cambie el estado solo de los objetos de dominio en los que opera.

Mientras que un servicio de aplicación implementa una lógica de nivel aplicativo como interacción del usuario, validación de entrada, lógica no relacionada con el negocio sino con otras preocupaciones: autenticación, seguridad, correo electrónico, etc., limitándose a usar simplemente servicios expuestos por objetos de dominio.

Un ejemplo de esto podría ser el siguiente escenario pensado solo para explicar el propósito: tenemos que implementar una aplicación de utilidad domótica muy pequeña que ejecuta una operación simple, es decir, "enciende las luces, cuando alguien abre la puerta de la habitación de una casa para entrar adentro y apaga la luz cuando cierra la puerta que sale de la habitación ".

Simplificando mucho, consideramos solo 2 entidades de dominio: Doory Lampcada una de ellas tiene 2 estados, respetuosamente open/closedy on/offmétodos específicos para operar los cambios de estado en ellos.

En este caso, necesitamos un servicio de dominio que ejecute la operación específica de encender la luz cuando alguien abre la puerta desde el exterior para entrar en una habitación, porque los objetos de la puerta y la lámpara no pueden implementar esta lógica de una manera que consideramos adecuada. a su naturaleza .

Podemos llamar a nuestro servicio de dominio como DomoticDomainServicee implementar 2 métodos: OpenTheDoorAndTurnOnTheLighty CloseTheDoorAndTurnOffTheLight, estos 2 métodos cambian respetuosamente el estado de ambos objetos Doory Lamphacia open/ony closed/off.

El estado de entrar o salir de una sala no está presente en el objeto de servicio de dominio y tampoco en los objetos de dominio, pero se implementará como una simple interacción del usuario por parte de un servicio de aplicación, que podemos llamar HouseService, que implementa algunos controladores de eventos como onOpenRoom1DoorToEntery onCloseRoom1DoorToExit, y así sucesivamente para cada sala (esto es solo un ejemplo para explicar el propósito ...) , eso se referirá respectivamente a los métodos de servicio de dominio de llamada para ejecutar el comportamiento atendido (no hemos considerado la entidad Roomporque es solo un ejemplo) .

Este ejemplo, lejos de ser una aplicación bien diseñada del mundo real, tiene el único propósito (como se ha dicho más veces) de explicar qué es un Servicio de dominio y su diferencia con un Servicio de aplicación, espero que sea claro y útil.

Ciro Corvino
fuente
Ciro: Tu ejemplo no es práctico y es muy confuso.
Morteza Azizi
Hola Morteza, ¿podrías ser más específico? El tuyo corre el riesgo de ser solo un "juicio" sin ningún argumento real. Gracias
Ciro Corvino