Spring 프로젝트를 개발할 때는 보통 다음과 같은 계층 구조를 따른다.

Controller -> Service -> Repository

여기에 모모 프로젝트는 하나의 클래스에서 제공하는 기능(메서드)의 수를 줄이고(역할을 최소화하고), 프로젝트 폴더를 볼 때 세분화하여 하나의 폴더 내에 수많은 클래스 파일이 있지 않도록 구성하였다. 일반적인 계층 구조로 나누되 하나의 도메인(모임) 안에서 분리될 수 있는 도메인들을 최상위 패키지로 한단계 더 분리하였다.

Domin -> Controller -> Service -> Repository

Untitled

작은 도메인 단위로 패키지를 분리하여 계층 내(폴더 내) 클래스의 수가 줄어들어 가독성이 높아졌다. 하지만 개발을 진행하다보면 완벽하게 분리되지 않는 도메인을 패키지로 분리하였기 때문에 오히려 ‘코드’의 가독성이 떨어지는 경우가 발생하였다.

예를 들어, 모모 서비스는 모임을 주축으로 모임에 참여할 수 있고, 찜을 할 수 있고, 이미지를 변경할 수도 있다. 서비스 특성 상 하나의 큰 서비스에 여러 서비스가 하위로 연결되어 있는 구조이다. 따라서 모임 패키지 내 서비스 계층에서는 어쩔 수 없이 수많은 의존성들이 생길 수 밖에 없었다.

의존이 발생하는 기능들을 보면 사용자가 어떤 요청을 보냈을 때 유기적으로 연결되어 있는 다른 도메인의 정보를 변경하는 경우가 많았다. (모임 삭제 시 찜 정보 삭제, 회원 삭제 시 찜 정보 삭제 등) 이런 경우 사용자가 요청을 보낸 계층에서 연결되어 있는 다른 도메인의 계층을 가져와서 메서드를 호출해야 했다. 이러한 의존 관계를 개선시키기 위해 Spring 의 Event 기능을 도입하였다.

Spring 의 Event 기능 구현

Spring 의 ApplicationContext 는 기본적으로 Event 기능을 제공한다. 이미 내장되어 있는 기능을 활용하여 의존 관계의 코드를 개선시킬 수 있다. Event 기능을 사용하기 위해서는 간단한 구조를 먼저 파악해야 한다. 이름에서 알 수 있듯이 어느 한 쪽에서 다른 한 쪽으로 이벤트 요청을 보내는 방식으로 이루어진다.

Publisher --(Event)--> Listener

요청을 보내는 객체를 Publisher, 요청을 받아 필요한 로직을 수행하는 객체를 Listener 라고 한다. 여기에서 각 객체 간 통신하기 위한 전달체는 Event 이다.

먼저, Event 로 구현해볼 기능은 모임을 생성할 때 모임의 기본 이미지 정보를 저장하는 기능이다. 이벤트를 사용하지 않았다면 아래와 같은 형식일 것이다.

GroupModifyService.java

@Transactional
public GroupIdResponse create(Long memberId, GroupRequest request) {
    // 모임 정보 저장 (생략)

		groupImageRepository.save(groupImage);

    return GroupResponseAssembler.groupIdResponse(savedGroup);
}

이렇게 모임 이미지 레포지토리를 이용하여 저장하는 방식을 사용하려면 서비스 계층에서 모임 이미지 레포지토리를 미리 받아와서 의존해야 한다. 이 메서드에서는 의존하는 관계가 적은 편이지만 기능이 복잡해질 수록 의존하는 관계가 무한정 늘어날 것이다.

GroupModifyService.java

@Transactional
public GroupIdResponse create(Long memberId, GroupRequest request) {
    // 모임 정보 저장 (생략)

		groupImageRepository1.save(groupImage);
		groupImageRepository2.save(groupImage);
		groupImageRepository3.save(groupImage);

    return GroupResponseAssembler.groupIdResponse(savedGroup);
}

간단하게 1, 2, 3 으로 표현하였지만 각자 다른 역할을 수행하는 레포지토리라고 가정하자. 그럼 모임 생성 기능을 구현하기 위해서 세 개의 레포지토리를 의존해야 한다. 이러한 경우에 Event 형식으로 바꾸면 더 간략하게 코드를 구성할 수 있다.

GroupModifyService.java