Alexander Steshenko | On Software Engineering

Service Layer

For the demo DDD PHP application I will use the “Service Layer” pattern(http://martinfowler.com/eaaCatalog/serviceLayer.html).

There is another pattern, called Facade (http://en.wikipedia.org/wiki/Facade_pattern) and the Service Layer is a case of it. It is very important to understand that if purely implemented, Service Layer hides everything that lies inside. For instance, in my service layer I could have method like this:

public function add_product_to_cart(...)  

When using the service, I do not know anything about the way this method is done inside. It can be a raw sql query in a huge solid method… or it could be some profound structured practice applied (like DDD). All I know is that I can send some “data” to the service and perhaps get some “data” as the result of its work. Try to think of the service layer as of something your end users have to deal with “directly” (without all those other layers you might have e.g. MVC, external REST API etc).

Data format

How you define the “data” and the interface of interaction with services - is up to you. There are several popular approaches though.

The truly object oriented way and the only “pure” way is to use Data Transfer Objects (DTO). Data wrapped into objects and strengthened with interfaces. This one is considered by many developers as bringing along too much overwork.

Another way to go is to simplify things and use data containers without defining strict interfaces (e.g. simpler objects or even PHP arrays). It’s not an object oriented way at all but who says we have to use it everywhere.

Somewhat straightforward and obvious at the first glance is to use the function parameters to pass data to it. It’s not so comfortable in PHP as it doesn’t have named parameters and may lead to difficulties if the data you need to enter has not trivial structure or if there’s a lot of params. Still it may be very convenient and good enough in a wide range of tasks.

Keep in mind that you can use anything you want. You can use DTOs and be safe in any situation. However for my demonstrative purposes in the sample DDD app coming I’m going to use the following set of compromises for interacting with services:

Logic in Service Layer

If we use Service Layer with DDD then it’s useful to think of it not just of a common facade to all your business and application logic but also as of a place to put logic that doesn’t necessary require a special object by domain design. Consider you have the following requirements for the operation “registering a user”:

Very typical. So, here instead of entering another domain object called “UserRegistrator” which would embed those domain model details you may have just put the whole operation in a method of a Service. So one Service Layer public method = single atomic business process. Here is how such requirements could be implemented (let’s say it’s a part of UsersService class):

public function registerUser($inviteCode, $email, $password, $repeatPassword)
{
    // NOTE: How we're going to control our dependencies is smth for another 
    // discussion, for now let’s just assume we have the objects we need already.

    $invite = $invitesRepository->findByCode($inviteCode);
    if (!$invite || $invite->countUsersRegistered() >= 2) {
        throw new DomainException('Wrong invite code');
    }

    if ($usersRepository->findByEmail($email)) {
        throw new DomainException('Email is already registered');
    }

    if ($password != $repeatPassword) {
        throw new DomainExceptions('Passwords are not equal');
    }

    $user = new User($email, $password);
    // There's more to say about the atomicity of a single business operation
    // (the confirmation email should not be sent if we failed saving
    // the new user to our database) I'll leave it out for now.

    $usersStorage->save($user);
    $mailer->sendConfirmationEmail($user);
}

Now you should also see the benefit and the very matter of DDD: there is no additional work for a programmer on converting the requirements to the model design except writing those as they are using a programming language.


Comments and feedback are much appreciated. See contact details here