전체 보기
🍀

Service에서 다른 Service 의존 vs Repository 의존

작성일자
2024/04/26
태그
DIARY_DEVELOP
프로젝트
WoowaCourse
책 종류
1 more property

고민한 상황

Controller > Service > Repository 구조의 스프링 프로젝트에서 Service가 다른 Service에 의존할지, 다른 Repository에 의존할지 고민이 되는 순간이 생겼다. 코드로 보자면 아래와 같은 상황이었다.
@Service public class ReservationService { private final ReservationRepository reservationRepository; private final ReservationTimeRepository reservationTimeRepository; public ReservationResponse saveReservation(ReservationRequest request) { ReservationTime time = findReservationTimeById(request.timeId()); Reservation reservation = request.toReservation(time); Reservation savedReservation = reservationRepository.save(reservation); return ReservationResponse.from(savedReservation); } private ReservationTime findReservationTimeById(Long id) { return reservationTimeRepository.findById(id) .orElseThrow(() -> new IllegalArgumentException("존재하지 않는 시간입니다.")); } } public class Reservation { private Long id; private String name; private LocalDate date; private ReservationTime time; }
Java
복사
Reservation이 ReservationTime과 연관관계를 맺고 있어 Reservation을 저장하려면 ReservationTime에 대한 조회 쿼리를 함께 날려야 했다. 이때 ReservationService 에서 ReservationTimeRepository의 findById() 함수를 이용할지, ReservationTimeService의 findById() 함수를 이용할지 고민이 되었다. 둘중 뭘 사용해도 결과는 쿼리 실행 결과는 똑같은 상황이었다. 고려할 점은 객체 간 의존성이었다.

Service에서 다른 Service 의존

ReservationService가 ReservationTimeDao를 아는 건 Controller -> Serivce -> Dao 순에서 하위 계층을 참조하고 있기에 순환참조의 위험이 없다. 그러나 중복 코드가 생길 수 있다. 지금 상황에선 ReservationTimeService 에 아래의 함수가 존재했다면, 두 Service 객체 사이에 중복 코드가 존재한다.
@Service public class ReservationTimeService { private final ReservationTimeRepository reservationTimeRepository; private ReservationTime findReservationTimeById(Long id) { return reservationTimeRepository.findById(id) .orElseThrow(() -> new IllegalArgumentException("존재하지 않는 시간입니다.")); } }
Java
복사

Service에서 다른 Repository 의존

반면, ReservationService가 ReservationTimeService를 아는 건 순환참조의 위험이 존재한다. 그러나 순환참조가 생기지 않도록 조심한다면 너무 경계할 필요는 없다. 오히려 중복 코드를 제거한단 관점에서 효율적일 수 있다. 현재 상황에선 아래와 같이 고쳐볼 수 있다.
@Service public class ReservationService { private final ReservationRepository reservationRepository; private final ReservationTimeService reservationTimeService; public ReservationResponse saveReservation(ReservationRequest request) { ReservationTime time = reservationTimeService.findById(request.timeId()); Reservation reservation = request.toReservation(time); Reservation savedReservation = reservationRepository.save(reservation); return ReservationResponse.from(savedReservation); } }
Java
복사

선택의 근거

둘 중 뭐가 옳다 하는 정답은 없고, 상황마다 팀마다 다르게 선택할 거 같다. 만일 ResevationService가 사용해야 하는 ReservationTimeService의 메서드가 단순히 dao 접근만 담당하는 게 아니라 그 외의 복잡한 비즈니스 로직을 실행한다면 ReservationTimeService를 사용해 중복 코드를 줄일 거 같다. 현재 상황에선 단순히 dao 접근만 담당하는 전자에 가깝기에 ReservationService가 ReservationTimeService가 아닌 ReservationTimeRepository를 사용하는 방식을 택했다.