2. THREE MAIN ROLES IN DOMAIN
ENTITY VALUE OBJECT
DOMAIN SERVICE
Unique Identity
Stateful
Immutable
Conceptual whole
Replaceability
Side-effect free
Stateless
Domain object interaction
Complex process
3. SOMETIMES, IT JUST ISN’T A THING - ERIC EVANS
DOMAIN SERVICE
▸ A STATELESS operation that fulfills a domain-specific task
▸ An operation is not easy to be defined on an
Aggregate(Entity) or a Value Object
▸ Make sure the operation name is a part of the
UBIQUITOUS LANGUAGE
▸ The only role can invoke repositories in the domain
5. PRODUCT
1..*
BACKLOG ITEM
public class Product {
private Set<BacklogItem> backlogItems
public BusinessPriorityTotals businessPriorityTotals() {
// Iterating backlogItems and calculating priority totals
}
}
SO FAR SO GOOD
11. WHAT IS NOT A DOMAIN SERVICE
▸ Different from application services
▸ Not required to be a remote-capable(SOA, RPC, MoM)
Application Service
Domain Service
12. REASONS OF USING DOMAIN SERVICES
▸ Perform a significant business process
▸ Calculate a Value requiring input from more than one
domain object
▸ Transform a domain object from one composition to
another
14. IDENTITY AND ACCESS CONTEXT
▸ Users of a system must be authenticated but can be
authenticated only if the tenant is active
▸ Passwords must be stored encrypted, not as clear text
15. boolean authentic = false;
Tenant tenant = DomainRegistry.tenantRepository().tenantOfId(aTenantId);
if (tenant == null || !tenant.isActive()) {
return authentic;
}
User user = DomainRegistry
.tenantRepository()
.userWithUsername(aTenantId, aUsername);
if (user == null) {
return authentic;
}
authentic = tenant.authenticate(user, aPassword);
return authentic;
16. boolean authentic = false;
Tenant tenant = DomainRegistry.tenantRepository().tenantOfId(aTenantId);
if (tenant == null || !tenant.isActive()) {
return authentic;
}
User user = DomainRegistry
.tenantRepository()
.userWithUsername(aTenantId, aUsername);
if (user == null) {
return authentic;
}
authentic = tenant.authenticate(user, aPassword);
return authentic;
Tenant knowing how to
encrypt the password
Domain logic was leaked
to the client
17. if {
…
} else { … }
Application Layer
for …
x + y
ENCAPSULATE COMPLEX LOGICS IN DOMAIN SERVICE
18. USING A DOMAIN SERVICE
UserDescriptor userDescriptor = DomainRegistry
.authenticationService()
.authenticate(aTenantId, aUsername, aPassword);
YOU CAN RETURN WHAT YOU NEED INSTEAD OF A WHOLE USER
FIT OUR UBIQUITOUS LANGUAGE
22. package saasovation.identityaccess.infrastructure.services;
import saasovation.identityaccess.domain.model.identity.AuthenticationService;
import …
public class DefaultEncryptionAuthenticationService implement AuthenticationService {
public UserDescriptor authenticate(TenantId tenantId, String username, String password) {
// Checking null value for all of the properties
UserDescriptor userDescriptor = null;
if (tenant == null || !tenant.isActive()) {
return userDescriptor;
}
String encryptedPassword = DomainRegistry.encryptionService().encryptedValue(password);
User user = DomainRegistry.userRepository().userFromAuthenticCredentials(
tenantId, username, encryptedPassword
);
if (user == null || !user.isEnabled()) {
return userDescriptor;
}
return userDescriptor;
}
}
23. IS SEPARATED INTERFACE A NECESSITY ?
▸ Considering the name of your interface
(ex: DefaultService, AuthenticationServiceImp)
▸ The service in the domain will have multiple
implementation
▸ You can still prevent the client from being aware of the
implementation by using DI or a Factory
30. MAKE SURE YOU NEED A SERVICE
▸ Do not treat Domain Services as a silver bullet
▸ Using Services overzealously will usually result in the
negative consequences of creating an Anemic Domain
Model