인프런 커뮤니티 질문&답변
MemberService와 EmailSender 책임 분리에 대한 질문
작성
·
22
·
수정됨
0
안녕하세요, 토비님.
강의 초반에 말씀해 주신 것처럼, 리팩토링 과정에서 “제가 했다면 어떻게 했을까”를 계속 생각해 보며 토비님의 의사결정 과정을 따라가고 있습니다.
MemberService.register() 메소드에서 emailSender.send(...)를 sendWelcomeEmail()로 분리하시는 과정을 보며 두 가지 고민이 생겼습니다.
첫째, 환영 이메일의 내용이나 정책이 변경될 때마다 MemberService의 코드가 함께 변경되어야 한다면, 이는 SRP 위반에 해당하지 않는지에 대한 고민입니다. 이 경우 환영 이메일 전송에 대한 책임을 EmailSender 인터페이스 쪽으로 옮기는 것이 더 적절한지 궁금해졌습니다.
둘째, 만약 EmailSender 인터페이스에 해당 메소드를 추가한다면, 구현체가 늘어날수록 인터페이스가 비대해지거나 향후 구현 복잡도가 증가할 수 있다고 느꼈습니다. 이런 경우 default method로 제공하는 방식에 대해서는 어떻게 생각하시는지도 궁금합니다.
답변 2
0
안녕하세요. 좋은 질문을 해주셨네요.
클린 스프링 강의 시리즈는 말씀해주신 그런 의문을 가지고 문제를 풀어가는 과정을 보여드리는 것이 목적입니다. 일단 시작 단계에서는 우선 기능을 빠르게 구현하고, 테스트를 만든 뒤에 가장 단순한 방법부터 시작해서 문제를 차근차근 풀어나가는 과정에 있다고 보시면 됩니다. 매번 어떤 의문을 가지고 어떤 시도를 하는지가 중요합니다.
가입하면 환영 이메일을 보내는 것은 아주 기본적인 도메인 모델에서 발견할 수 있는 기능이지만, 서비스가 성장하다보면 꽤 많은 변화가 필요하게 됩니다. 메일 내용이 변경되는 것은 아주 단순한 변화입니다. 그보다 더 복잡한 조건이 붙을 수도 있죠. 이벤트에 의해서 가입이 됐을 경우 메일 내용이 완전히 다르게 나갈 수도 있죠. 가입을 했지만 메일이 아닌 사전 인증된 메신저로 축하 메시지를 보낼 수도 있습니다. 글로벌 서비스가 돼서 여러 언어로 다르게 메일이 작성되야 할 수도 있고, 최종 메일 발송은 시간을 두고 배치로 처리하거나, 일정 승인 과정을 통해서 나가야 할 수도 있습니다. 시간이 지나면 회원 가입 직후에 진행되어야 할 작업이 이보다 훨씬 많아지게 됩니다. 각종 자료 업데이트부터, 포인트 적립을 위한 기초 작업 진행, 모니터링을 위한 통보 기능 등등. 이렇게 되면 더 큰 문제는 회원 가입 로직보다 후처리 작업이 커지고, 이게 또 시간을 많이 잡아먹습니다. 메일 발송도 꽤나 시간 걸리는 작업이거든요. 그러는 동안 DB 트랜잭션은 묶여있어서 가입이 갑자기 폭증하는 경우 성능에도 영향을 미칩니다. 그래서 트랜잭션 밖으로 이걸 분리하는 작업도 필요하죠.
중요한 건 현재 시점에서 "경제적"으로 할 수 있는 빠른 작업을 해두고, 이후 분리, 추상화 등에 투자할 타이밍을 찾는 것이죠. 이제 가입 기능을 처음 만들었는데 일 가입자 10만명을 상정해서 무리해서 기능을 만들어 둘 필요는 없으니까요. 우선은 가입 축하 메일을 보내는 코드가 회원 가입의 핵심 도메인 로직에서 분리해두는 것으로 충분할 것 같습니다. 이제 강의 시리즈 두 번째가 되면 이를 어떻게 독립적으로 만들지 구체적으로 다루게 될 겁니다.
어쨌든 좋은 문제의식을 가지고 지적을 해주셔서 감사합니다. 시간이 걸리는 외부 연동 서비스인데 경우에 따라 내용이 동적으로 변경되어야 하고, 템플릿을 관리해야 하고, 성공 여부를 확인해서 재시도 해야 하는 가입 축하 메일 발송이라면 이걸 어떻게 관리하면 좋을지 고민해보시고, 여러가지 시도를 해보세요.
0
안녕하세요, 인프런 AI 인턴입니다.
까르보떡볶이님, 좋은 질문 감사합니다!
MemberService.register() 메소드에서 이메일 전송을 담당하는 코드를 분리하는 과정에서 말씀하신 SRP(단일 책임 원칙)를 잘 고려하고 계시네요. SRP는 클래스가 하나의 책임만을 가져야 한다는 원칙으로, 코드의 변경 이유가 하나여야 한다는 것을 의미합니다.
첫째, 환영 이메일의 내용이나 정책 변경으로 인해 MemberService가 변경되어야 한다면 SRP 위반으로 볼 수 있습니다. 이메일 전송에 관한 책임은 실제로 EmailSender 쪽으로 옮기는 것이 더 원칙에 부합할 것입니다. EmailSender 인터페이스는 이메일 전송에 관련된 세부사항을 가질 수 있어 MemberService의 책임을 줄일 수 있습니다.
둘째, EmailSender 인터페이스에 많은 메소드가 추가될 경우 인터페이스가 비대해지는 문제가 발생할 수 있습니다. 이를 해결하기 위해 인터페이스에 default method를 제공하는 것도 좋은 방법입니다. default method를 사용하면 인터페이스에 구현을 제공할 수 있어 경우에 따라 인터페이스를 깔끔하게 유지하는 데 도움이 될 수 있지만, 사용에 있어서 과도하게 복잡해지지 않도록 주의가 필요합니다.
결론적으로, 각 책임을 명확하게 분리하고 인터페이스의 설계를 신중히 하는 것은 코드의 유연성과 유지보수성을 높이는 데 큰 도움이 됩니다. 추가적으로 Spring Boot에서 제공하는 이메일 전송 관련 설정은 Spring Boot Reference Documentation를 참고해보시면 도움이 될 것입니다. 자세한 정보는 여기를 참고하세요.
더 궁금하신 점이 있다면 언제든지 질문해 주세요!




