Domain-Driven Design Part 2 – Application Services and Domain Services

May 31, 2016 Tomasz Pluskiewicz

Tags:DDD

Previously, I introduced you to a set of libraries which can be used to create an application with Domain-Driven Design and CQRS/Event Sourcing. In the first post, I showed the PGS.DDD.Domain and PGS.DDD.Data assemblies which we used to implement the first Aggregate Root in our internal link sharing platform. In this part I would like to show you briefly how we approach services in our implementation.

What are services?

The term service is often used and somewhat overloaded. Thus, I find it slightly deprecated and its precise meaning hard to grasp. Some developers tend to put a broad spectrum of responsibilities on the “services layer”. Anemic Domain Model aside (which I find to be an anti-pattern by the way), services in general are a vital part of an application – DDD or otherwise.

Eric Evans introduces services as the realization of significant processes which do not belong to any specific Entity or Aggregate Root. These classes, called Domain Services, must follow the Ubiquitous Language and are part of the Domain layer.

There are also Application Services, which live outside of the Domain and can be used as a facade for complex business processes, and can access infrastructure and external dependencies. Application Services also usually serve as the topmost layer, directly below the API interface layer such a RESTful web service or library.

Distinguishing service types

For the newcomers to DDD, it can be challenging to decide whether a given functionality should become a Domain or Application Service. The answer may not always be straightforward and one should seek guidance from the domain experts.

Domain Services

Domain Service should be directly related to the core business functionality. A common example is assigning invoice numbers. It could be a responsibility of the Invoice itself to generate these numbers in series or according to set rules, taking the client’s identifier, date, etc. into account. It may, however, strike some people as odd. And such a decision could lead to trouble in any more complex cases; for example, if invoice numbers are generated differently between clients or require access to some external state. If this is true then the responsibility may belong to a domain service. Such domain services can be consumed by an aggregate root or invoked by an Application Service which only passes the result to the domain.

More technical kinds of Domain Services are factories and repositories. They are part of the domain (the interfaces at least). Less obvious, in the case of repositories, it is clear that factories very much belong there. Factories, used to create Aggregate Roots and/or Entities, require knowledge obtained from the Domain Expert and operate based on business decisions. Consider a hypothetical VehicleFactory which would create instances of Car or Truck entities depending on the characteristics of that vehicle (size, mass, etc.).

Lastly, a Domain Service is often used whenever a given operation must access more than one Aggregate Root. Many would say that each operation should update only a single Aggregate Root but it may not always be possible. Especially in the face of requirement changes to an existing application. If ever required, a Domain Service would be used rather than having Aggregate Roots access each other.

Application Services

A typical example of an Application Service on the other hand is the entry point to the application’s functionality. This is the most common example of service accessed from the API (for example, MVC controllers). An Application Service performs tasks not directly related to business logic – orchestrates the creation of other services, takes care of transaction and persistence, etc. Personally, I think that an Application Service (or at least an Application Service method) should directly correspond to a single business Use Case.

Finally, there are application services which are not the core of the domain but take part of some larger process. A common case could be an (asynchronous) email notification service. Whether sending a notification succeeds or not may not be crucial to the actual business action completing. Thus, it would not become a Domain Service. It also wouldn’t become part of an Application Service itself as not to break the Single Responsibility Principle. In practice, it could even work asynchronously and totally independent of the Application Service. This can be implemented by using Domain Events and a method of distributing them (service bus or pub/sub are two possibilities).

Example of services in the Link Sharing Platform

The first Application Service we have created processes a submitted link, creates a new Aggregate Root instance, persists it and pushes the changes to interested parties over a service bus. Here is the method in question:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class SubmittingLinkService : ISubmittingLinkService
{
    public CommandResult SubmitLink(SubmitLinkOnBehalfCommand command)
    {
        var linkValidator = new LinkValidator();
 
        if (linkValidator.IsValid(command.Uri) == false)
        {
            return CommandResult.Failure();
        }
 
        var link = new Link(command.Uri, new SubmitterId(command.SubmitterId), new Description(command.Description), _clock.Now);
 
        _repository.Save(link);
        var changes = ((IAggregateRoot)link).Changes.ToArray();
 
        _serviceBus.Publish(changes);
 
        return CommandResult.Success(changes);
    }
}

Arguably, a lot happens here, and parts of this method could be moved to a common base, but it’s not yet the time for that. All in all, there are three parts to this method. Prepare and validate the input, execute a business action (in this case creating an Aggregate Root) and finish up by doing some actions on the infrastructure. Simple as that.

By the way – see the LinkValidator class? This is another example of Domain Services – domain validation. We decided here, that verifying whether we want to accept any given submitted URL is not a responsibility of the Linkclass. First, it could become quite complicated and second, we decided that the Domain Expert (being myself for the purpose of our project) would not care for actual validity. At this stage, the URL is assumed to be properly formed and the validator only checks whether it uses the HTTP scheme, etc. More general validation, like checking mandatory fields and field types belongs to the API layer.

Alternatively, we could be passing a validator instance to Link through the constructor but decided against to avoid using exceptions for control flow. Also, this way it is easier to test the types in isolation.

What about PGS.DDD.Application?

The SubmittingLinkService class currently doesn’t inherit from any common base type. We have yet to determine what our needs are. Currently, the PGS.DDD.Application package contains only a solitary CommandResult class, which we return from application service methods and use to decide on the general outcome in the API layer. In our case, that would be a HTTP response.

As I wrote above, we are likely to introduce some base ApplicationService class(es), which would encapsulate common cases of handling the service bus, repository, etc. We just didn’t want to get ahead of ourselves.

Next

In the next post, and last for the time being, I will show you our read models.

Further reading

Lev Gorodinski – Services in DDD

Last posts