문제
어떠한 문제를 해결하기 위해선, 해결하기에 앞서 문제를 정확하게 식별하고 정의하는 것이 무엇보다 중요합니다. 먼저 Ludo
알림 서비스의 구조에 대해 간단히 설명하고, 무엇이 문제인지 살펴보고자 합니다.
Ludo
의 알림 서비스는 다양한 트리거에 의해 사용자에게 알림을 전송합니다. 핵심 비즈니스를 담당하는 서비스에서 알림 서비스를 의존하고 있고, 상황에 맞게 알림 서비스의 메서드를 호출하는 구조입니다. 이를 그림으로 표현하면 아래와 같습니다.
한 가지 예를 들어보겠습니다. RecruitmentService
는 모집공고와 관련한 비즈니스 흐름을 담당하는 클래스입니다. NotificationService
는 알림 관련 기능으로 응집되어 있는 클래스입니다. 사용자가 모집공고를 작성하면, 해당 모집공고에 적합한 알림 대상자에게 알림을 전송합니다.
1 |
|
1 |
|
1. 알림 기능 실패시 핵심 비즈니스도 함께 실패
여기서 두가지 문제가 있습니다. 첫번째는 핵심 비즈니스의 트랜잭션
이 알림 기능의 트랜잭션
으로 전파되는 것입니다. 현재 구조에서는 알림 기능이 모종의 이유로 실패하면, 핵심 비즈니스 기능은 성공을 했음에도 알림 기능과 함께 롤백이 되어버립니다. 핵심 비즈니스 기능이 성공했다면, 알림 기능의 성공 / 실패 여부와 상관없이 커밋되어야 할 것입니다.
2. 단위 테스트하기 어려운 구조
두 번째 문제는 BusinessService
와 NotificationService
가 강결합함으로써, 두 클래스 모두 단위 테스트하기 어려운 구조가 됩니다. 알림 기능은 총 4가지 단계를 거쳐서 이루어집니다.
- 핵심 비즈니스 로직 과정에서의 알림 메서드 호출
- 알림 대상자 조회
- 알림을 RDB에 저장
- 실시간 알림 전송
BusinessService
관점에서 보면, 기존에 작성한 단위 테스트에 NotificationService
를 Mocking하는 코드를 추가해야 합니다. 알림 요구사항이 변경되어 NotificationService
내부 구현을 수정한다면, 기존에 성공했던 BusinessService
단위 테스트에도 영향을 받아 실패하게 됩니다. 이를 해결하려면 Mocking한 코드를 재차 수정해야할 것입니다.
NotificationService
관점에서 살펴보면, 알림 전송 트리거가 잘 동작하는지 테스트하기 위해선 BusinessService
의 모든 내부 구현을 알아야하며 그에 맞게 Mocking해야 합니다. 이것도 마찬가지로 BusinessService
의 내부 구현이 수정되면, NotificationService
의 단위 테스트에도 영향을 받고, Mocking한 코드를 재차 수정해야 합니다.
두 문제 모두 핵심은 BusinessService
와 NotificationService
간의 강결합으로 인해 파생되는 문제라고 볼 수도 있겠습니다. 정리하면 이번 고도화의 목표는 아래와 같습니다.
- 문제1: 트랜잭션 전파로 인해 알림 기능의 성공 / 실패 여부가 핵심 비즈니스 로직에도 영향을 미친다.
- 목표: 알림 기능이 실패해도 핵심 비즈니스는 영향을 받지 않는다.
- 문제2: 강결합으로 인해 테스트하기 어려운 코드 구조이다.
- 목표: 핵심 비즈니스 기능 또는 알림 기능이 변경되어도, 두 클래스에 대한 단위 테스트는 영향을 받지 않는다.