event를 이용한 의존성 제거 2

Hyuk·2023년 9월 25일
0

HappyScrolls 개발기

목록 보기
16/24
post-thumbnail

event를 이용한 의존성 제거 1 에서 buyCreate에서 다른 서비스의 함수를 호출하는 부분을 전부 이벤트로 처리하였다.

그러나 기존 코드를 찾기 힘들다는 문제점이 발견했고, 또다른 문제점은 없는지 살펴보게 되었다.

과연 모든 로직을 이벤트로 처리하는게 맞을까??🤔

buyCreate가 실행되면 다른 서비스에서 실행되어야할 로직들이 실행된다.
1. CartService에서 cart를 불러온다.
2. ProductSevice에서 Product를 불러온다.
3. CartService에서 cart를 삭제
4. MemberService에서 포인트를 감소
5. NotificationService에서 알림을 전송

이렇게 5개의 로직이 진행된다. 그런데 1~4번은 물건을 구매했다면 당연히 일어나야 하는 로직이고, 5번은 부수적으로 일어나는 효과라고 생각되었다.

이벤트를 이용하게 되면서 의존성은 완화되었지만 buyCreate에서 무슨 일이 일어나는지 알기 힘들었다. 이는 buyCreate가 맡아야 할 일들을 이벤트로 넘겨버린 탓에 생긴 문제라고 생각되었다. buyCreate가 호출되며 벌어지는 일들은 buyCreate가 관리해야한다고 생각했다.

잠깐 정리

로직 1
물건을 장바구니로부터 구매한다면,
장바구니로부터 물건을 불러오고, 구매한 만큼 포인트를 감소하고, 구매한 장바구니 목록은 삭제하는 (이 부분은 정책마다 다를수도 있지만 대체로 장바구니 목록은 구매후 삭제된다.) 흐름은 당연하고 buyCreate가 호출될 시 실행이 보장되어야 하는 로직이다.

로직 2
반면에 물건을 구매했다는 알림은 필수적이지 않고 정책에 의존적이다. 정책이 바뀌면 메세지가 바뀔수도 있고, 아예 알림을 주지 않을수도 있는것이다.
따라서 1~4 와 5는 성격이 다른 집합이라고 생각되었다.

책임을 고려한 설계

여기서 만약 1~5를 전부 이벤트로 처리한다면 1~5는 더이상 buyCreate의 책임이 아니라고 생각되었다. buyCreate는 이벤트를 발행했을 뿐 1~5의 로직에 관여한 것이 없기 때문이다.

또한 이벤트의 책임도 아니라고 생각되었다. 이벤트는 말 그대로 발행되었고, 각각의 서비스 객체에서 이벤트리스너를 통해 이벤트를 받아들이고, 그에 맞는 행위를 한것이므로 1~5 로직이 각각의 도메인에서 책임을 진다고 생각되었다.

하지만 앞에서 서술하였듯 1~4는 buyCreate가 보장하여야 하는 로직들이다.
따라서 다시 코드를 수정하였다.

최초 코드

    public List<Buy> buyCreate(Member member, BuyDTO.RequestCart request) {

        List<Buy> response = new ArrayList<>();

		중략...
		
		cartService.deleteCarts(cartList);
		memberService.decreasePoint(member,requirePoints); 
        notificationService.notiBuy(response);


        return response;
    }

1차 수정 코드

   public List<Buy> buyCreate(Member member, BuyDTO.RequestCart request) {

        List<Buy> response = new ArrayList<>();

		중략...
		
		바뀐 부분(기존 코드 삭제됨)
        applicationEventPublisher.publishEvent(new BuyEvent(member,requirePoints,cartList));


        return response;
    }

최종 수정 코드

   public List<Buy> buyCreate(Member member, BuyDTO.RequestCart request) {

        List<Buy> response = new ArrayList<>();

		중략...
		cartService.deleteCarts(cartList);
		memberService.decreasePoint(member,requirePoints);
        
        이전과는 달리 일부만 이벤트로 발행
        applicationEventPublisher.publishEvent(new BuyEvent(member,requirePoints,cartList));


        return response;
    }

위 코드와 같이 1~4 로직은 다시 buyCreate가 호출하도록 하고, 알림에 관한 부분만 이벤트로 따로 뺐다.
이렇게 된다면 기존에 기대했던 복잡한 의존성을 관리하는 목적을 달성할 수 있다.
만약 쿠폰 발행이나 레벨업 같은 정책에 의한 추가 로직이 생긴다면 이벤트리스너를 통해 구현하면 된다. 그러면 더이상 buyCreate를 건들지 않아도 기능추가가 가능하다.

만약 구매 로직의 흐름이 바뀐다면 (가령 포인트가 아니라 실제 현금으로 결제해야하는 상황 ) 그땐 BuyService가 의존해야하는 것들이 늘어나고 buyCreate의 코드에 변경이 생기겠지만, 이는 주요 로직이 바뀐것이기에 불가피한 변경이라 어쩔 수 없는 부분이라고 생각되었다.

결론

  • 의존하는 것들이 로직의 주요 흐름에 포함되는 내용이라면 의존성이 복잡해지더라도 메소드 내에서 호출하는게 좋다고 생각된다.
  • 만약 주요 흐름은 아니고 부가적으로 실행되는 로직이라면, 정책 변경에 따라 추가, 수정, 삭제되기 쉬운 로직이라면 이벤트로 관리하는게 좋아보인다.
profile
🙂 🙃 🙂 🙃

0개의 댓글