The core logic is to separate the parts of the program that handle business and domain knowledge (domain or business logic) from the parts responsible for process control, coordination, and decision-making (control logic), thereby improving code maintainability, testability, and reusability.
In DDD, business logic corresponds to domain logic, and control logic corresponds to the “application layer” or “service layer.”
Business Logic
- Content: Business rules, data validation, calculation formulas
- Responsibility: Ensure system behavior complies with business requirements and specifications
- Examples:
- Calculating the total price of an order
- Determining user permissions
- Business state transitions
Control Logic
- Content: Process control, call sequence, conditional judgment
- Responsibility: Organize and manage the execution of business logic to ensure correct system flow
- Examples:
- Handling state transitions in multi-step business processes
- Controlling transaction start and commit
Examples
Using Python
Conventional Approach
class UserService:
def __init__(self):
self.users = []
def register_user(self, username, password):
# 1. validate username
if username in self.users:
return {"success": False, "message": "Username already exists"}
# 2. validate password length
if len(password) < 6:
return "Password too short"
# 3. store user
self.users.append(username)
return {"success": True, "message": "User registered successfully"}
Separated Approach
class UserRepository:
def __init__(self):
self.users = {}
def exists(self, username):
return username in self.users
def save(self, user):
self.users[user["username"]] = user
# Domain Logic
class UserDomainService:
def __init__(self, user_repository):
self.user_repository = user_repository
def is_username_available(self, username):
# Check if the username is already taken
return self.user_repository.exists(username)
def validate_password(self, password):
# Validate the password according to your criteria
return len(password) >= 6
def create_user(self, username, password):
user = {"username": username, "password": password}
self.user_repository.save(user)
return user
# Application Logic
class UserApplicationService:
def __init__(self, user_domain_service):
self.user_domain_service = user_domain_service
def register_user(self, username, password):
# 1. Check if the username is available
if self.user_domain_service.is_username_available(username):
return {"success": False, "message": "Username already taken."}
# 2. Validate the password
if not self.user_domain_service.validate_password(password):
return {"success": False, "message": "Password does not meet criteria."}
# 3. Create the user
user = self.user_domain_service.create_user(username, password)
return {"success": True, "user": user}
repo = UserRepository()
domain_service = UserDomainService(repo)
app_service = UserApplicationService(domain_service)
print(app_service.register_user("john_doe", "password123")) # Should succeed
print(
app_service.register_user("john_doe", "pass")
) # Should fail due to password criteria
print(
app_service.register_user("john_doe", "newpassword")
) # Should fail due to username already taken
- UserDomainService focuses only on business rules (whether the username exists, password validation, user creation).
- UserApplicationService is responsible for process control (call sequence, return results).
Using Java
Conventional Approach
import java.util.HashSet;
import java.util.Set;
public class UserService {
private Set<String> users = new HashSet<>();
public Result register(String username, String password) {
// 1. Check if the username is available
if (users.contains(username)) {
return new Result(false, "Username is already in use");
}
// 2. Validate the password
if (password.length() < 6) {
return new Result(false, "Password must be at least 6 characters");
}
// 3. Create the user
users.add(username);
return new Result(true, "success");
}
public static class Result {
private boolean success;
private String message;
public Result(boolean success, String message) {
this.success = success;
this.message = message;
}
public boolean isSuccess() {return success;}
public String getMessage() {return message;}
}
}
Separated Approach
import java.util.HashMap;
import java.util.Map;
// Domain Logic
class UserDomainService {
private UserRepository userRepository;
public UserDomainService(UserRepository userRepository) {
this.userRepository = userRepository;
}
public boolean isUsernameTaken(String username) {
return userRepository.exists(username);
}
public boolean validatePassword(String password){
return password != null && password.length() >= 6;
}
public void createUser(String username, String password) {
User user = new User(username, password);
userRepository.save(user);
}
}
// Persistence Layer
class UserRepository{
private Map<String, User> users = new HashMap<>();
public boolean exists(String username){
return users.containsKey(username);
}
public void save(User user){
users.put(user.getUsername(), user);
}
}
// User Entity
class User {
private String username;
private String password;
public User(String username, String password) {
this.username = username;
this.password = password;
}
public String getUsername() {
return username;
}
}
class Result {
private boolean success;
private String message;
public Result(boolean success, String message) {
this.success = success;
this.message = message;
}
public boolean isSuccess() {return success;}
public String getMessage() {return message;}
}
// Application Logic
class UserApplicationService {
private UserDomainService userDomainService;
public UserApplicationService(UserDomainService userDomainService) {
this.userDomainService = userDomainService;
}
public Result register(String username, String password) {
if(userDomainService.isUsernameTaken(username))
return new Result(false, "Username taken");
if(!userDomainService.validatePassword(password))
return new Result(false, "Invalid password");
userDomainService.createUser(username, password);
return new Result(true, "success");
}
}
public class scratch_46 {
public static void main(String[] args) {
UserRepository userRepository = new UserRepository();
UserDomainService userDomainService = new UserDomainService(userRepository);
UserApplicationService userApplicationService = new UserApplicationService(userDomainService);
Result r1 = userApplicationService.register("alice", "12345");
System.out.println(r1.getMessage());
Result r2 = userApplicationService.register("alice", "123456");
System.out.println(r2.getMessage());
Result r3 = userApplicationService.register("alice", "1234567");
System.out.println(r3.getMessage());
}
}
- UserDomainService is responsible for business rules (whether the username exists, password validation, user creation).
- UserApplicationService is responsible for controlling the process (call sequence, return results).
- UserRepository simulates data storage.
- User is the domain entity.
Tips and Suggestions
- Start by designing simple methods.
- Move simple methods to the control logic layer.
- Separate out the business logic.