이번 포스팅에서는, App Server에서 도메인 기능과 완전히 분리하여, Push 알림 요청 기능을 확장한 과정을 기술하려고 합니다.
도메인과 Push 알림을 분리하자
Push 알림은 도메인과 완전히 상관이 없는 개념입니다. 따라서, Push 알림이 도메인 로직에 의존해서도, 도메인 로직이 Push 알림에 의존해서도 안됩니다.
1. 기존의 아키텍쳐
기존의 아키텍쳐는 DDD
의 Layered Architecture를 이용해 설계가 되어있었습니다.
각 계층은 아래로의 의존만을 가지며, infra(저수준 모듈의 구현) 계층의 필요한 구현은 DIP를 이용해 Application, Domain
이 infra(저수준 모듈)에 의존하는 것이 아니라, infra가 고수준 모듈에 의존하도록 했습니다.
2. 문제의 Push 알림을 위한 아키텍쳐 ?
Push 알림의 문제는 아래와 같습니다.
- Push 알림은 Application, Domain 계층에서 로직을 처리하기 위해 필요로 하는 별도의 모듈이 아닙니다. 즉 우리의 도메인과는 전혀 관련이 없습니다.
- 하지만, 도메인에서 특정 기능을 수행하는 경우, Push 알림을 주기 위해, Application의 여러 부분에서 사용될 수 있습니다.
- Application의 기능 테스트시, FCM 메시지의 의존성 관리를 해주어야 합니다.
- FCM에서의 구현이 변경된다면, Application 계층이 영향을 받습니다(변경이 일어남).
3. 최종 아키텍쳐 AOP
위의 문제들을 해결하기 위해, 저는 Push 알림을 횡단 관심사로 분리하였습니다.
위와 같이 변경하여, Application 코드를 수정 또는 변경할 필요없이, 별도의 파일에서 설정을 통해, Push 알림을 요청할 수 있도록 변경하였습니다.
3.1 구현
xxxxxxxxxx
public class FirebaseCloudMessageService {
public void sendMessageTo(Long userId, String title, String body) {
... // FCM 을 이용해 Push 알림 처리
}
}
public class FcmAopConfig {
private final FirebaseCloudMessageService messageService;
private final RefundRepository refundRepository;
"execution(* com.galid.card_refund.domains.admin.application.AdminEstimateUserPassportService.estimateUserPassport(..))") (
public void sendFcmMessageWhenEstimatePassport(JoinPoint joinPoint) {
Object[] args = joinPoint.getArgs();
messageService.sendMessageTo((Long)args[0], "Tour Cash", "여권정보 평가 완료");
}
"execution(* com.galid.card_refund.domains.admin.application.AdminEstimateRefundService.estimateRefundRequest(..))") (
public void sendFcmMessageWhenEstimateRefund(JoinPoint joinPoint) {
Object[] args = joinPoint.getArgs();
RefundEntity refundEntity = refundRepository.findById((Long) args[0]).get();
messageService.sendMessageTo(refundEntity.getRequestorId(), "Tour Cash", "환급 요청 평가 완료");
}
}
위와 같이 별도의 FCM AopConfig 파일에서, Push 알림이 필요한곳에 기능을 weaving하여 Application 로직과 완전히 분리 했습니다.
3.2 테스트
문제 발생
하지만 위와 같이 Push알림이 필요한 기능을 테스트하는 도중, 문제가 발생함을 볼 수 있습니다. 이는, AOP를 통해 처리하더라도, 결국 해당 기능이 호출된 뒤, Push 알림이 보내지기 때문에 발생하는 현상입니다.
해결방법 1 - 비동기로 동작
해당 기능이 비동기로 동작한다면, Push 알림 요청과 Application 서비스 요청이 분리 될 수 있습니다.
해결방법 2 - Mocking
"test") (
public class PushNotificationSetUp {
private FirebaseCloudMessageService service;
public void init() {
doNothing().when(service).sendMessageTo(any(), any(), any());
}
}
두번째 방법은 Test시 PushNotification을 Mocking 하는 것입니다. 이렇게 하면, Push 알림 기능이 실행되더라도 아무런 일이 발생하지 않기 때문에 테스트가 통과됩니다.
이 방법은 테스트시 Push 알림을 위한 처리가 필요하다는 것을 기억해야하므로 별로 좋지 않은 방법 같습니다.
해결방법 3 - Bean Profile
마지막 방법은 Bean의 Profile을 이용하는것 입니다. Profile은 Profile에 따라서 IOC 컨테이너에 등록될 빈들의 그룹을 설정할 수 있도록 하는 기능인데요, 이점을 이용해서 Push 알림을 weaving하는 FcmAopConfig를 deploy 환경에서만 동작하도록 하여 해결하는 것입니다.
이렇게하면, test 시에는 FcmAopConfig 빈이 IOC 컨테이너에 없기 때문에, Push 알림 기능이 호출되지 않습니다.
이 방법은 테스트 코드를 위해서, 별도의 처리를 요구하지 않기 때문에 가장 좋은 방법 같습니다.
'FrameWork > Spring' 카테고리의 다른 글
Spring - classpath란? Intellij에서 classpath 추가하기 (0) | 2019.05.04 |
---|---|
Spring - IoC 컨테이너의 기능 - 7 (Resource 추상화 - ResourceLoader) (0) | 2019.05.03 |
Spring - Lombok 이란?, Intellij Lombok 설정방법 (2) | 2019.05.01 |
Spring - IoC 컨테이너의 기능 - 6 (DataBinding 추상화, Converter, Formatter 란?) (0) | 2019.04.16 |
Spring - IoC 컨테이너의 기능 - 5 (객체의 값 검증 Validation, Errors) (2) | 2019.04.14 |