알림 서비스는 현재 구글 토크와 트위터에 스터디와 모임 소식을 전달해주고 있습니다. 그런데 이전에 만든 메일 서비스가 이 것과 굉장히 비슷한 구조였습니다.


녹색은 스프링에서 제공하는 라이브러리이고, 파란색 계열이 봄싹 코드입니다. 보시면 알림 서비스와 거의 같은 구조지만, 사용하는 클래스가 조금 다르고, SendMailService가 구현하는 인터페이스가 없다는 것만 다를 뿐입니다.

이 두 개의 서비스를 사용하는 NotificationAspect를 보면 통합의 필요성을 더 확실하게 느낄 수 있습니다.

@Aspect
public class NotificationAspect {
  
    @Autowired SendMailService sendMailService;
    @Autowired JabberService messangerService;
    @Autowired TwitterService twitterService;
    @Autowired MemberService memberService;
...
    @AfterReturning(pointcut = "addStudyPointcut() && args(study)", argNames="study")
    public void sendMailAfterAddStudy(Study study){
        sendMailService.sendMail(new StudyMail(study, StudyStatus.OPEN, memberService.getMemberList()));
        StudyMessage msg = new StudyMessage(study, StudyStatus.OPEN, memberService.getMemberList());
        messangerService.sendMessage(msg);
        twitterService.sendMessage(msg);
    }
...

    @AfterReturning(pointcut = "addMeetingPointcut() && args(study, meeting)", argNames="study, meeting")
    public void sendMailAfterAddMeeting(Study study, Meeting meeting){
        sendMailService.sendMail(new MeetingMail(study, meeting, MeetingStatus.OPEN));
        MeetingMessage msg = new MeetingMessage(study, meeting, MeetingStatus.OPEN);
        messangerService.sendMessage(msg);
        twitterService.sendMessage(msg);
    }
}

sendMailService도 다른 알림 서비스와 같은 인터페이스를 구현하고, SpringSproutMessage 타입의 객체를 받아서 사용할 수 있다면. 어떤 일이 벌어질지 보이시나요?

저에게는 콜렉션이 보이고, 애스팩트의 여러 어브다이스에서 연달아 메서드를 호출해주는 구조의 중복을 제거할 수 있어 보입니다.

그래서 통합했습니다.


메시지쪽이 좀 까다로웠지만, 상속을 이용해서 나름 열심히 작업했습니다.

결과는 어떨까요?
1. 메시지 작성이 간편해졌습니다.
2. NotificationAspect가 다이어트를 했습니다.

원했던 성과를 거뒀습니다.

    <util:list id="notificationServices">
        <value>sendMailService</value>
        <value>jabberService</value>
        <value>twitterService</value>
    </util:list>

이렇게 빈 설정을 해 놓고..

@Aspect
public class NotificationAspect {
  
    @Autowired List<NotificationService> notificationServices;
    @Autowired MemberService memberService;

...

    @AfterReturning(pointcut = "addStudyPointcut() && args(study)", argNames="study")
    public void sendMailAfterAddStudy(Study study){
        sendMsg(new StudyMailMessage(study, StudyStatus.OPEN, memberService.getMemberList()));
    }

    @AfterReturning(pointcut = "addMeetingPointcut() && args(study, meeting)", argNames="study, meeting")
    public void sendMailAfterAddMeeting(Study study, Meeting meeting){
        sendMsg(new MeetingMailMessage(study, meeting, MeetingStatus.OPEN));
    }

    private void sendMsg(SpringSproutMessage msg) {
        for(NotificationService service : notificationServices)
            service.sendMessage(msg);
    }

...
}

NotificationAspect 코드를 이렇게 리팩토링 했습니다.

캬~~~ 엄청난 대규모 리팩토링이었는데 생각했던대로 되서 다행입니다. 이 작업을 진행하는 내내 테스트가 충분하지 않아서 굉장히 불안했었는데, 그래도 최소한의 테스트가 마지막 검증을 하는데 도움이 됐습니다. 역시.. 테스트는 있어야 합니다. 매우 필요한 존재에요;

다음 과제는 모임 등록시 SWF 적용하기!!