4. 서비스레이어 간 상호참조, 강결합을 해결하자

선종우·2023년 8월 17일
0

1. 문제점

  • 프로젝트의 패키지 구조를 크게 match, member, message로 구분하였다. 그리고 각각의 패키지에는 주요 관심사와 관련된 entity와 각 entity에 대한 repository, sevice를 구현하였다.
  • 그런데 개발을 하다보니 강하게 결합되는 서비스들이 있었다. 예를 들어 현재 구조상 match가 성사되면 message방이 자동으로 생성되어야 한다. 한편 메시지가 작성되면 해당 메시지가 속한 message방의 마지막 메시지가 업데이트 되어야 한다.
  • 이렇다 보니 MessageRoom을 관리하기 위한 서비스 클래스가 Message관련 기능도 담당해 단일 책임 원칙을 위배하거나 두 개의 클래스가 순환참조하는 관계가 되어버렸다.
  • 문제를 해결하기 위해서는 1. 컨트롤러가 각각의 서비스를 호출한 후 결과를 조립 2. 퍼사드 패턴 사용 방법 중 하나를 선택할 수 있었다.
  • 컨트롤러에서는 사용자 입력값에 대한 검증 및 응답값 처리에 대해서만 집중하기로 정했기 때문에 2번 방법을 택하기로 하였다.

2. 퍼사드의 도입

  • 검색해보니 서비스 간 상호의존 문제, 강하게 연결되는 서비스를 묶기 위해 퍼사드 패턴을 적용할 수 있다고 한다.

  • 기존에는 서비스 레이어에서는 무조건 DTO를 반환하게끔 하였는데, 퍼사드를 적용하고 나서는 Entity와 직접 연결되는 서비스는 Entity를 반환하게끔 하였다. DTO를 반환하게 할 경우 Entity -> DTO -> Entity로 변환을 해야 하거나, 불필요한 쿼리가 발생하게 되었다. Entity를 직접 이용하며 한 개의 Transaction으로 묶을 경우 영속성 컨텍스트를 이용할 수 있으므로 불필요한 쿼리 발생을 줄일 수 있었다.

  • 아래는 예시이다.

    @RequiredArgsConstructor
    @Service
    public class GetTodayMatchPartnerList {
       private final MatchService matchService;
       private final MemberService memberService;
       private final CountService countService;
       @Transactional
       public List<MemberDto> execute(Long memberId){
           Member member = memberService.getMemberById(memberId);
           if(countService.getSwipeCount(member).isExhausted()){
               return Collections.emptyList();
           }
    
           List<MemberDto> todayMatchPartnerList = matchService.getTodayMatchPartnerList(member);
           if (todayMatchPartnerList.size() > 5) {
               todayMatchPartnerList = todayMatchPartnerList.subList(0, 5);
           }
           return todayMatchPartnerList;
       }
    }
    • 기존 코드에서는 사용자 엔티티를 활용하기 위해서 MatchService에서 MemberRepository에 접근해야 했다. 또한 SwipeCount에 따른 분기처리를 해야하므로 Controller에 관련 로직이 많이 들어가야만 했다.
    • 사용자 리스트를 뽑아오는 행위는 사용자 검색 - 사용자의 Swipe Count 확인 - match list 추출로 묶이는 하나의 행위이다. 따라서 이를 퍼사드로 구현하게 되면, 작업의 원자성도 얻을 수 있고 코드의 재사용도 가능해진다.
    • 또한 Entity를 각 서비스 레이어에 직접 전달하므로써 각 서비스는 단일 책임 원칙을 지킬 수 있게 되었다.(기존에는 각 서비스레이어에서 member를 찾고 없다면 예외를 반환하는 로직이 있었다.)

0개의 댓글