[ODOP] 101일차 - ApplicationService
![[ODOP] 101일차 - ApplicationService](/content/images/size/w1200/2023/09/odop-5.png)
ApplicationService
애플리케이션 서비스는 도메인 서비스를 합쳐서 특정한 기능을 만드는데에 사용한다
DomainService 는 가끔 애플리케이션 서비스가 되기도 하는데, 간단한 CRUD 같은 로직의 경우에는 DomainService 로도 충분하기 때문이다
같이 여러 DomainService 를 사용해야 하는 경우는 ApplicationService 를 따로 만들어서 처리하는 방식이 좋다고 생각한다.
이전 글에서 썼던 예시를 리팩토링 해보자
@Service
@RequiredArgsConstructor
public class DomainService {
private final DomainRepository domainRepository;
private final UserRepository userRepository;
private final ScheduleService scheduleService;
public Domain get(Long id) throws NotFoundException {
return domainRepository.findOne(id)
.orElseThrow(NotFoundException::new);
}
public Domain create(String domainName, Long userId) {
Domain persistTarget = new Domain(domainName);
if (userRepository.findById(userId).isPresent()) {
// 유저가 존재하는 경우 특정 비즈니스
Schedule schedules = scheduleService.getSchedules(2L, YearMonth.now());
// 스케쥴에 등록하는 비즈니스
}
if (domainRepository.isExist(persistTarget)) {
// 이름이 중복되어 가입 불가
throw new DuplicateKeyException("Duplicated name");
}
return domainRepository.save(persistTarget);
}
}
먼저 ApplicationService.java 를 만들고, 위의 클래스를 하나 하나 뜯어보자
@Component
@RequiredArgsConstructor
public class ApplicationService {
// 아직 아무런 기능이 없음.
}
먼저 이 항목을 보자
public Domain create(String domainName, Long userId) {
Domain persistTarget = new Domain(domainName);
if (userRepository.findById(userId).isPresent()) {
// 유저가 존재하는 경우 특정 비즈니스
Schedule schedules = scheduleService.getSchedules(2L, YearMonth.now());
// 스케쥴에 등록하는 비즈니스
}
if (domainRepository.isExist(persistTarget)) {
// 이름이 중복되어 가입 불가
throw new DuplicateKeyException("Duplicated name");
}
return domainRepository.save(persistTarget);
}
이 기능을 ApplicationService 로 옮겨보자
![](https://blog.pollra.com/content/images/2023/09/-----2023-09-06----10.01.04.png)
코드는 깔끔해졌지만 기능은 동작하지 않는다.
하나 하나 변경해보자
if (userRepository.findById(userId).isPresent()) {
// 유저가 존재하는 경우 특정 비즈니스
Schedule schedules = scheduleService.getSchedules(2L, YearMonth.now());
// 스케쥴에 등록하는 비즈니스
}
UserRepository 를 사용하고 있다.
User 의 도메인으로 보이니 UserService 를 만들어 끼워넣자
데이터를 확인만 하고 있으니 isExist 정도면 적당한 네이밍이 아닐까?
![](https://blog.pollra.com/content/images/2023/09/-----2023-09-06----10.05.03.png)
이제 UserService 가 어떻게 확인하든 신경쓰지 않게 되었고 UserService 도 재사용이 가능해졌다.
다음으로 ScheduleService 를 보자
과연 저 리턴되는 데이터가 필요할까? 스케쥴을 생성만 하면 되지 않을까?
좀 더 복잡한 처리를 따라하기 위해 가정을 추가해보자
domain 의 id 를 스케쥴에 같이 저장하는 경우라면 어떨까?
여기서 변경 될 부분은 이렇다
- domain 은 먼저 저장 될 필요가 있기 때문에 validation 을 먼저 수행하도록 변경한다
- 위 validation 수행 된 후 domain 을 저장 하는 로직을 수행한다.
- domain 의 id 를 schedule 에서 같이 저장한다.
![](https://blog.pollra.com/content/images/2023/09/-----2023-09-06----10.28.26.png)
아주 간단해진 것을 확인 할 수 있다.
validation 이 수행되는 것은 외부로 노출시킬 필요가 없기 때문에 create 함수 내부로 숨겼다
이로서 모든 서비스는 재사용이 가능하며 로직도 정상적으로 돌아간다
애플리케이션 서비스는 이처럼 도메인 서비스의 결합을 이용해서 특정 기능을 구현하는데 초점이 맞춰져있다
도메인 서비스는 오로지 하나의 도메인을 신경쓰며 외부에서 얼마든지 호출해서 사용 할 수 있도록 나누어지게 되었다.
각 도메인 서비스는 결국 하나의 Repository 만을 사용 하게 될 것이다
같은 도메인의 로직들은 오로지 하나의 Service 만을 통하게 된다
코드의 가독성은 올라갔다.
단점은 레이어가 하나 추가된 느낌이 든다는 것인데 이게 과연 단점일까?
이 예시에서는 레이어 아키텍쳐를 활용하여 예시를 들었지만, 애플리케이션 서비스와 도메인 서비스 개념은 레이어 아키텍쳐만 사용하는 개념은 아니라는 것을 끝으로 이번 글을 마친다.