도메인 모델 순수성 vs 도메인 모델 완전성 (DDD Trilemma)

DongHyun Kim·2024년 8월 2일
0
post-custom-banner

도메인 모델 완전성

  • 예를 들어 사용자 이메일 변경
public class User {
	
	private String email;
	
	public Result changeEmail(String newEmail){
		if(Company.isEmailCorporate(newEmail) == false)
			return Result.Failure("Incorrect email domain");
		
		email = newEmail;
		return Result.Success();
	}
}

public class Company {

	public boolean isEmailCorporate(String email){
		...
	}
}

public class UserController {
	
	public String changeEmail(int userId, String newEmail){
		User user = userRepository.getById(userId);
		Result result = user.changeEmail(newEmail);
		if(result.isFailure) return "fail";
		return "ok";
	}
}

위와 같이 도메인에 애플리케이션의 비즈니스 로직이 모두 포함되는 것을 풍부한 도메인(Rich Domain) , 완전한 도메인이라 부른다.

위와 같은 도메인의 특징은, 도메인 로직 단편화(Domain Logic Fragmentation) 가 일어나지 않는다.

도메인 로직 단편화란? - 도메인 계층이 아닌 다른 계층에 도메인 로직이 있는 경우

위 예에서 UserController에 로직을 포함하지 않고 조합하는 역할만 한다.

도메인 모델 순수성

  • 또 다른 비즈니스 규칙을 구현한다 가정, 사용자 이메일을 변경하기 전에 새 이메일이 이미 사용 중인지 확인
  • 이메일 고유성 확인 로직 필요
public class UserController {
	
	public String changeEmail(int userId, String newEmail){
		
		User existingUser = userRepository.getByEmail(newEmail);
		if(existingUser != null && existingUser.id != userId){
			return "email is already taken";
		}
		User user = userRepository.getById(userId);
		Result result = user.changeEmail(newEmail);
		if(result.isFailure) return "fail";
		return "ok";
	}
}
  • 위의 도메인 로직 단편화가 일어났다. 컨트롤러에 도메인 관련 비즈니스 로직 하나가 추가됐기 때문
  • 도메인 모델 완전성을 복원하려면 로직을 User 클래스에 이동 필요
public class User {
	
	private String email;
	
	public Result changeEmail(String newEmail, UserRepository repository){
		if(Company.isEmailCorporate(newEmail) == false)
			return Result.Failure("Incorrect email domain");
		
		User existingUser = repository.getByEmail(newEmail);
		if(existingUser != null && existingUser.id != userId){
			return "email is already taken";
		}
		
		email = newEmail;
		return Result.Success();
	}
}
  • 이 버전의 경우 도메인 모델 단편화는 제거하지만, 도메인 모델 순수성을 희생한다.
    • User가 데이터베이스에 접근하게 하므로 실패
  • 도메인 모델 순수성이란? 도메인 클래스는 기본 유형이나 다른 도메인 클래스에만 의존해야 한다. (도메인 계층끼리)
  • 여기서 도메인 모델 완전성과 도메인 모델 순수성 사이의 선택이 나온다

트릴레마

  • 애플리케이션 성능을 포기하며 도메인 모델 순수성과 완전성을 챙길 수 있다
public class User {
	
	private String email;
	
	public Result changeEmail(String newEmail, List<User> allUsers){
		if(Company.isEmailCorporate(newEmail) == false)
			return Result.Failure("Incorrect email domain");
		
		boolean existingUser = allUsers.any(x -> x.email == newEmail);
		if(existingUser != null && existingUser.id != userId){
			return "email is already taken";
		}
		
		email = newEmail;
		return Result.Success();
	}
}
  • 모든 검증이 도메인 계층에 있고, 순수하며 완벽하다

  • 여기서 트릴레마가 작용한다. 다음 세 가지 속성을 모두 가질 수는 없다

    • 도메인 모델 완전성 - 도메인 로직은 도메인에만 존재한다
    • 도메인 모델 순수성 - 도메인 계층에 외부 종속성이 없다
    • 성능 - 불필요한 프로세스 호출이 없다
  • 3가지 옵션 , 각각 2가지 속성만 충족

    • 모든 외부 읽기, 쓰기를 포함 → 성능 포기
    • 도메인 계층에 외부 종속성 주입 → 순수성 포기
    • 도메인 계층과 컨트롤러 간 프로세스를 분리 → 완전성 포기
  • 도메인 완전성보단 순수성을 선택 권장 → 도메인 로직 단편화가 덜하다.

  • 컨트롤러와 도메인에 비즈니스 로직을 분할해야하는 이유

    • DDD 관점: 도메인이 “핵심”이기 때문에 애플리케이션의 복잡성을 핵심에서 해결하는 것이 좋다
    • 함수형 프로그래밍 : 함수를 투명하게 만들어서 애플리케이션의 기능적 핵심에서 숨겨진 입력, 출력을 피하는 것 (데이터베이스 쿼리)
    • 단위 테스트 : 순수 도메인 모델이 테스트 가능한 도메인 모델을 의미. 외부 종속성이 있다면 Mock, Stub을 설정해야 하므로 테스트 유지 관리가 힘듬

출처 : https://enterprisecraftsmanship.com/posts/domain-model-purity-completeness/

https://parkmuhyeun.github.io/etc/java/2023-12-16-Domain/

profile
do programming yourself
post-custom-banner

0개의 댓글