본문 바로가기

DDD/도메인 주도 설계 철저 입문

유스케이스의 응집도와 구현 - 「도메인 주도 설계 철저 입문」 6장 (3)

 

 

 

본 포스트 시리즈는 「도메인 주도 설계 철저 입문」책을 요약한 내용입니다.

 

 

이전 발행 글 보기

 

 

더보기

2024.09.02 - [DDD/도메인 주도 설계 철저 입문] - 도메인 주도 설계란? - 「도메인 주도 설계 철저 입문」 1장

2024.09.04 - [DDD/도메인 주도 설계 철저 입문] - 도메인 주도 설계란? - 「도메인 주도 설계 철저 입문」 2장 (1)

2024.09.05 - [DDD/도메인 주도 설계 철저 입문] - 도메인 주도 설계란? - 「도메인 주도 설계 철저 입문」 2장 (2)

2024.09.09 - [DDD/도메인 주도 설계 철저 입문] - 도메인 주도 설계란? - 「도메인 주도 설계 철저 입문」 3장 (1)

2024.09.09 - [DDD/도메인 주도 설계 철저 입문] - 도메인 주도 설계란? - 「도메인 주도 설계 철저 입문」 3장 (1)

2024.09.11 - [DDD/도메인 주도 설계 철저 입문] - 도메인 주도 설계란? - 「도메인 주도 설계 철저 입문」 3장 (2)

2024.09.30 - [DDD/도메인 주도 설계 철저 입문] - 도메인 주도 설계란? - 「도메인 주도 설계 철저 입문」 4장

2024.09.30 - [DDD/도메인 주도 설계 철저 입문] - 도메인 주도 설계란? - 「도메인 주도 설계 철저 입문」 5장 (1)

2024.09.30 - [DDD/도메인 주도 설계 철저 입문] - 도메인 주도 설계란? - 「도메인 주도 설계 철저 입문」 5장 (2)

2024.09.30 - [DDD/도메인 주도 설계 철저 입문] - 도메인 주도 설계란? - 「도메인 주도 설계 철저 입문」 5장 (3)

2024.10.05 - [DDD/도메인 주도 설계 철저 입문] - 도메인 주도 설계란? - 「도메인 주도 설계 철저 입문」 6장 (1)

2024.10.05 - [DDD/도메인 주도 설계 철저 입문] - 도메인 주도 설계란? - 「도메인 주도 설계 철저 입문」 6장 (2)

 

 

 


 

06장 유스케이스를 구현하기 위한 '애플리케이션 서비스'

 

(3) 애플리케이션 서비스의 응집도와 유연성

 

 

응집도란

응집도란 모듈의 책임 범위가 얼마나 집중되어있는지를 말한다. 응집도가 높다는 것은 모듈이 하나의 관심사에만 집중하고 있다는 뜻이고, 이는 모듈의 신뢰성, 재사용성, 가독성 측면에서 뛰어나다는 것이다. 

 

 

응집도의 측정

응집도를 측정하는 방법에는 LCOM(Lack of Cohesion in Method)이 있다. 모든 인스턴스가 모든 메소드에 사용되고 있는지를 확인하는 방법이다. 

 

응집도가 낮은 애플리케이션 서비스

다음은 응집도가 낮은 애플리케이션 서비스다. 

public class UserApplicationService {
    private final IUserRepository userRepository;
    private final UserService userService;

	(...생략...)

    public void register(String name, String mailAddress) {
        User user = new User(new UserName(name), new MailAddress(mailAddress));
        
        // 도메인 서비스를 통해 중복 확인
        if (userService.exists(user)) {
            throw new CanNotRegisterUserException(user, "이미 등록된 사용자입니다.");
        }

        userRepository.save(user);
    }

    public void delete(UserDeleteCommand command) {
        UserId targetId = new UserId(command.getId());
        User user = userRepository.find(targetId);

        if (user == null) {
            // 탈퇴 대상 사용자가 발견되지 않았다면 탈퇴 처리 성공으로 간주한다
            return;
        }

        userRepository.delete(user);
    }
}

 

위 서비스가 응집도가 낮은 이유는 `UserService`가 `register` 함수에서는 사용되었지만 `delete`에서는 사용되지 않고 있기 때문이다. 

 

 

응집도가 높은 서비스

다음과 같이 서비스를 분리하면 응집도를 높일 수 있다. 

public class UserRegisterService {
    private final IUserRepository userRepository;
    private final UserService userService;

    public UserRegisterService(IUserRepository userRepository, UserService userService) {
        this.userRepository = userRepository;
        this.userService = userService;
    }

    public void handle(UserRegisterCommand command) {
        UserName userName = new UserName(command.getName());

        User user = new User(userName);

        // 중복된 사용자인지 확인
        if (userService.exists(user)) {
            throw new CanNotRegisterUserException(user, "이미 등록된 사용자입니다.");
        }

        userRepository.save(user);
    }
}

 

`UserRegisterService`의 필드 변수인 `IUserRepository`와 `UserService`는 `UserRegisterService`의 모든 메소드에서 다 사용되고 있다. 

public class UserDeleteService {
    private final IUserRepository userRepository;

    public UserDeleteService(IUserRepository userRepository) {
        this.userRepository = userRepository;
    }

    public void handle(UserDeleteCommand command) {
        UserId userId = new UserId(command.getId());
        User user = userRepository.find(userId);

        if (user == null) {
            throw new UserNotFoundException(userId);
        }

        userRepository.delete(user);
    }
}

 

그리고 `UserDeleteService`의 필드 변수인 `IUserRepository`도 `UserDeleteService` 내에서 항상 사용되고 있다. 따라서 각각은 응집도가 높은 모듈이라고 볼 수 있다. 

 

 

애플리케이션 서비스를 인터페이스로 구현하는 예시

다음은 앱 서비스를 인터페이스로 구현한 경우 클라이언트가 이를 사용하는 코드이다.

public class Client {
    private IUserRegisterService userRegisterService;

    public Client(IUserRegisterService userRegisterService) {
        this.userRegisterService = userRegisterService;
    }

    public void register(String name) {
        UserRegisterCommand command = new UserRegisterCommand(name);
        userRegisterService.handle(command);
    }
}

 

 

애플리케이션 서비스를 인터페이스로 구현하는 이유

도메인 주도 설계 철저 입문 144p

앱 서비스를 인터페이스로 구현하면 첫째, 앱 서비스의 구현이 끝나기 전에 클라이언트 측이 `MockUserRegisterService`를 만들어 개발을 진행할 수 있어 효율적이다. 둘째, 예외가 발생했을 때 예외 처리에 대한 개발을 진행하기 위해 `ExceptionUserRegisterService`를 개발하여 사용할 수 있다.

 


 

 

요약

 

1. 응집도란 모듈이 얼마나 한 가지 목적에 집중하고 있는지를 말한다. 

2. 응집도를 측정하는 방법은 모든 변수가 모든 메소드에서 사용되고 있는지를 확인하는 것이다. 

3. 응집도에 따라 애플리케이션 서비스를 나누어 구현하는 것도 고려해보는 것이 좋다.

4. 앱 서비스를 인터페이스로 구현하면 개발 생산성이 높아진다.