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:
- Query the database for the Reservation object.
- invoke Reservation->cancel.
- 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.
No, you are not using tokens correctly.
The idea is that you have an Auth service which issues tokens and Resource services which can validate the token and read the claims it contains. So the rather than forwarding the bearer token to the auth service each time the flow should be as follows
- Client -> Auth : please give me a token, here is my username and pass
- Auth -> Client : here is a token I have signed it with my private key and it contains the claim "i am an Accounting Agent"
then
- Client -> Resource : hi, please give me a list of accounts, here is my token
- Resource -> Client : I have checked the signature on your token using the Auth services public key. so I know I can trust your claim that you are an Accounts Agent. Here is the list of accounts
then
- Client -> Resource : Please delete this account, here is my token
- Resource -> Client : sorry Account Agents are not allowed to delete accounts
This flow prevents the Auth service becoming a performance bottleneck and leave the various microservices to decide if Claim X can do Operation Y
Roles
To address your second question about roles and permissions. At the end of the day a service has to have a set of Roles or Permissions that it knows about. eg you have to actually code something like:
If(users.Role != "RoleX")
{
return "Access Denied!";
}
Rather than have a whole list of different permissions, 'canEditAccounts' ,' canEditCustomers', 'canDeleteAccounts'... etc etc the modern approach is to instead have a shorter list of Roles 'AccountingAgent' which essentially act as a set of permissions.
If a third party consumes your services though they will have to use the roles that the service knows about. This means that they are stuck with the level of granularity that you provide in your Roles.
ie If your Accounting Agent does too little and your Accounting Manager does too much for your third parties needs you are stuck.
One way around this is to have a dynamic mapping between Roles and Permissions. Have your service know about permissions and query what permissions a role has.
You can then allow your third party consumers to create their own roles, selecting the permissions they want each to have
Best Answer
I would use a central, unified authentication system and have separate permissions/stats for each microservice (sort of like how I can't yet upvote on this stack exchange site but I can in stack overflow while using the central stack exchange authentication system). One of my current projects will involve this approach in the near future, which will be nice; the previous development work involved creating a HIPPA compliant system, necessitating a second level of authorization/authentication, and it is a time consuming annoyance to daisy chain authorizations from legally separate but functionally inseparable components of the system. The debugging process involves a lot less joy than a simple oauth login or an api with appid and x-auth headers.
Which to use depends upon the specific requirements of a development roadmap, but I would choose the simpler approach where possible to avoid excessive overhead and development time/effort.