Domain Driven Design: Domain Service, Application Service
Services come in 3 flavours: Domain Services, Application Services, and Infrastructure Services.
- Domain Services : Encapsulates business logic that doesn't naturally fit within a domain object, and are NOT typical CRUD operations – those would belong to a Repository.
- Application Services : Used by external consumers to talk to your system (think Web Services). If consumers need access to CRUD operations, they would be exposed here.
- Infrastructure Services : Used to abstract technical concerns (e.g. MSMQ, email provider, etc).
Keeping Domain Services along with your Domain Objects is sensible – they are all focused on domain logic. And yes, you can inject Repositories into your Services.
Application Services will typically use both Domain Services and Repositories to deal with external requests.
Hope that helps!
(If you don't feel like reading, there's a summary at the bottom :-)
I too have struggled with the precise definition of application services. Although Vijay's answer was very helpful to my thinking process a month ago, I have come to disagree with part of it.
Other resources
There's very little information about application services. Subjects like aggregate roots, repositories and domain services are discussed extensively, but application services are only mentioned briefly or left out altogether.
The MSDN Magazine article An Introduction To Domain-Driven Design describes application services as a way to transform and/or expose your domain model to external clients, e.g. as a WCF service. This is how Vijay describes application services too. From this point of view, application services are an interface to your domain.
Jeffrey Palermo's articles on the Onion Architecture (part one, two and three) are a good read. He treats application services as application-level concepts, such as a user's session. Although this is closer to my understanding of application services, it's still not in line with my thoughts on the subject.
My thoughts
I have come to think of application services as dependencies provided by the application. In this case the application could be a desktop application or a WCF service.
Domain
Time for an example. You start out with your domain. All entities and any domain services that don't depend on external resources are implemented here. Any domain concepts that depend on external resources are defined by an interface. Here is a possible solution layout (project name in bold):
My Solution - My.Product.Core (My.Product.dll) - DomainServices IExchangeRateService Product ProductFactory IProductRepository
The Product
and ProductFactory
classes have been implemented in the core assembly. The IProductRepository
is something that is probably backed by a database. The implementation of this is not the domain's concern and is therefore defined by an interface.
For now, we'll focus on the IExchangeRateService
. The business logic for this service is implemented by an external web service. However, its concept is still part of the domain and is represented by this interface.
Infrastructure
The implementation of the external dependencies are part of the application's infrastructure:
My Solution + My.Product.Core (My.Product.dll) - My.Product.Infrastructure (My.Product.Infrastructure.dll) - DomainServices XEExchangeRateService SqlServerProductRepository
XEExchangeRateService
implements the IExchangeRateService
domain service by communicating with xe.com. This implementation can be used by your applications that utilize your domain model, by including the infrastructure assembly.
Application
Note that I haven't mentioned application services yet. We'll look at those now. Let's say we want to provide an IExchangeRateService
implementation that uses a cache for speedy lookups. The outline of this decorator class could look like this.
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.
}
Notice the ICache
parameter? This concept is not part of our domain, so it's not a domain service. It's an application service. It's a dependency of our infrastructure that may be provided by the application. Let's introduce an application that demonstrates this:
My Solution - My.Product.Core (My.Product.dll) - DomainServices IExchangeRateService Product 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
This all comes together in the application like this:
// 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);
Summary
A complete application consists of three major layers:
- domain
- infrastructure
- application
The domain layer contains the domain entities and stand-alone domain services. Any domain concepts (this includes domain services, but also repositories) that depend on external resources, are defined by interfaces.
The infrastructure layer contains the implementation of the interfaces from the domain layer. These implementations may introduce new non-domain dependencies that have to be provided the application. These are the application services and are represented by interfaces.
The application layer contains the implementation of the application services. The application layer may also contain additional implementations of domain interfaces, if the implementations provided by the infrastructure layer are not sufficient.
Although this perspective may not match with the general DDD definition of services, it does separate the domain from the application and allows you to share the domain (and infrastructure) assembly between several applications.