Php – DDD: Creating reusable modules and service type distinctions (Domain, Infrastructure, Application)

Architecturedesign-patternsdomain-driven-designenterprise-architecturePHP

So after reading "Implementing Domain-Driven Design by Vaughn Vernon" I've decided to refactor my code for better re usability by isolating what I believe to be core domain concepts into separate modules.

Each module contains their own set of distinct architectural layers which include the Domain, Infrastructure and the Application/Presentation layer (per Vaughn's recommendation I've decided to further separate the responsibilities of the Application layer from routes, MVC controllers + templates which exist in the Presentation Layer).

I've decided to place each of these layers within their own package; and each package is referencing the layer beneath it as a dependency. ie: Presentation Layer depends on the Application Layer, Application depends on Infrastructure, etc. Since the Repository is a part of the Domain, each Repository Interface exists within the Domain layer/package with implementation being a responsibility of the Infrastructure layer/package (Doctrine, etc).

I'm hoping that by restructuring my code in this way I'll be able to swap out the Application layer and reuse my Domain across multiple Web Applications.

The code finally looks like it's starting to shape again however what still confuses me is this distinction between Application, Infrastructure and Domain Services.

One common example of a Domain Service is something which you would use to hash passwords. This makes sense to me from a SRP perspective since the User entity shouldn't concern itself with the many different hashing algorithms which might be used to store a user's credentials.

So with that in mind I treated this new Domain service the same way as my Repositories; by defining an interface in the Domain and leaving the implementation up to Infrastructure layer. However, now I'm wondering about what should be done with the Application Services.

As it stands now, each Entity has its own Application Service, i.e. the User Entity has a UserService within the Application Layer. The UserService in this case is responsible for parsing primitive data types and handling a common use-case "UserService::CreateUser(string name, string email, etc) : User.

What concerns me is the fact that I'll need to re-implement this logic across multiple applications should I decide to swap out the Application layer. So I guess this leads me to my next few questions:

  1. Are Domain Services merely an Interface which exist to provide a layer of abstraction between the Infrastructure Layer and your Model? ie: Repositories + HashingServices, etc.

  2. I mentioned having an Application Service which looks like this:

    • Access/Application/Services/UserService::CreateUser(string name, string email, etc): User

    • The method signature accepts primitive data type arguments and returns a new User Entity (not a DTO!).

    Does this belong in the Infrastructure layer as an implementation of some interface defined within the Domain layer or is the Application Layer in fact more appropriate due to primitive data type arguments, etc?

    example:

    Access/Domain/Services/UserServiceInterface 
    

    and

    Access/Infrastructure/Services/UserService implements UserServiceInterface
    
  3. How should separate modules handle unidirectional relationships. Should module A reference module B's application layer (as it's doing now) or the infrastructure implementation (via separated interface)?

  4. Do Application Layer Services require a Separate Interface? If the answer is yes then where should they be located?

Best Answer

Are Domain Services merely an Interface which exist to provide a layer of abstraction between the Infrastructure Layer and your Model? ie: Repositories + HashingServices, etc.

Domain services responsibilities include several things. The most obvious is housing logic that doesn't fit into a single entity. For example, you may need to authorize a refund for a certain purchase, but to complete the operation you need data from the Purchase entity, Customer entity, CustomerMembership entity.

Domain services also my provide operations needed by the domain to complete its functionality such as PasswordEncryptionService, but the implementation of this service will reside in the infrastructure layer since it will mostly be a technical solution.

Infrastructure services are services which so an infrastructure operation such as opening a network connection, copy file from file system, talk to an external web service or talk to database.

Application services are the implementation of a use case in the application you are building. If you are cancelling a flight reservation you would:

  1. Query the database for the Reservation object.
  2. invoke Reservation->cancel.
  3. Save object to DB.

The application layer is the client of the domain. The domain has no idea what your use case is. It just exposes the functionality through its aggregates and domain services. The application layer however mirrors what you are trying to achieve by orchestrating the domain and infrastructure layers.

I mentioned having an Application Service which looks like this: Access/Application/Services/UserService::CreateUser(string name, string email, etc): User The method signature accepts primitive data type arguments and returns a new User Entity (not a DTO!).

PHP might not be the best place to start learning about DDD since many of the PHP frameworks out there (Laravel, Symfony, Zend,..etc) tend to promote RAD. They are focused more on CRUD and translating forms to entities. CRUD != DDD

Your presentation layer should be responsible for reading the form inputs from the request object and invoking the correct application service. The application service will create the user and invoke the User repository to save the new user. You may optionally return a DTO of the user back to the presentation layer.

How should separate modules handle unidirectional relationships. Should module A reference module B's application layer (as it's doing now) or the infrastructure implementation (via separated interface)?

The word module in DDD lingo has a different meaning than what you are describing. A module should house related concepts. For example, an order module in the domain layer could house the Order aggregate, OrderItem entity, OrderRepositoryInterface and MaxOrderValidationService.

An Order module in the application layer could house the OrderApplicationServie, CreateOrderCommand and OrderDto.

If you are talking about layers then each layer should preferably depend on interfaces of other layers whenever possible. The presentation layer should depend on interfaces of the application layer. Application layer should reference interfaces of the repositories or domain services.

I personally don't create interfaces for entities and value objects coz I believe interfaces should be related to a behavior, but YMMV :)

Do Application Layer Services require a Separate Interface? If the answer is yes then where should they be located?

It depends :) for complex applications I build interfaces coz we apply rigorous unit, integration and acceptance testing. Loose coupling is key here and the interfaces are in the same layer (application layer).

For simple app I build against the app services directly.