개인취향 JPA 사용기 3편 – Scalable Service

안녕하세요? gemini 입니다.

제가 속한 가자고 팀은 매 2주간의 스프린트 마다 추가 기능을 배포하고 있습니다.
아직 오래전 급하게 만든 코드 등 숙제들이 많지만, 많은 부분이 변하여 순조롭게 기능 확장 중입니다.

이번에 제가 공유하려는 내용은 서비스의 기능을 지속적으로 확장시키는 경험 속에서 느꼈던 점을 공유해보겠습니다.
특히 이번 글은 더 개인 취향에 의한 주관적 생각이오니 많은 의견 주시면 좋을 것 같습니다.

먼저 간단한 상황을 예제로 들어보겠습니다.

기획팀에서 아래와 같은 기능 개발 요청이 왔습니다.
1. 유저는 장바구니에 새로운 상품을 추가할 수 있어야 한다.
2. 유저가 장바구니에 담았던 누적 수량, 금액을 저장하고 있어야 한다.

자, 요구 사항을 위해 Business Logic 을 담을 CartService 를 만들어 보겠습니다.

벌써 다 만들었습니다! Cart 추가할 때에 User 를 불러와서 수량 과 금액 을 갱신 시켜 줍니다.

물론 동작에는 이상이 없지만 CartService 에서 User 를 가져와서 제어하는 형태가 제 취향은 아닌 것 같습니다.
테스트 코드 작성하기도 조금 까다로워 보이네요.

일단 제 취향대로 변경하기 위해 User 의 대한 처리를 UserService 가 수행하도록 변경해보겠습니다.

오우, 좋은 것 같습니다. 테스트 코드도 훨씬 작성하기 쉽겠네요
CartService 는 장바구니 저장만 해주고, User 의 대한 내용은 UserService 에게 맡깁니다.

그런데.. 또 다른 요구 사항으로 인해 UserService 에서도 CartService 가 필요한 상황이 발생합니다.
요구 사항을 반영하기 위해 UserService 에서 CartService 를 사용하여 작업을 진행해봅니다.

엇! 구현을 모두 끝내고 서버를 띄워보니 에러가 발생합니다.
Screen Shot 2016-09-19 at 3.02.57 AM
다들 추측하셨겠지만 UserSerivceCartService 가 상호 참조를 하고 있습니다.
이 문제는 다양한 방법으로 해결할 수 있습니다. 일단은 CartService 쪽 의 의존성을 끊어서 해결하겠습니다.

결국은 CartServiceUserRepository 를 통하여 직접 User 를 가져오고 이를 처리하게 되었습니다.
정상 동작할 것이고, 문제 될 것은 당연히 없습니다.

그렇지만 역시 제 취향은 아니네요.
저의 취향대로 Business Object 를 만들어 핵심 로직을 처리하도록 수정해보겠습니다.

이제 CartServiceUserInfoUpdater 를 사용하도록 수정하겠습니다.

이제 CartServiceUserService 와 관계가 전혀 없어졌습니다. 그리고 CartService 에서는 User 에 관하여 어떤 기능만을 사용하는지 더욱 명확해진 것 같네요.

또한 아주 약한 결합을 가지고 있기에 테스트를 작성하기가 아주 편하고 테스트도 설명하는 바가 명확합니다.

제 취향을 강조하기 위해 빡빡한 예를 들어보았습니다. 적절한 예제였는지는 잘 모르겠습니다, 조금 억지가 있어도 양해 부탁드립니다.

꾸준한 기능 확장으로 인해 Service 들에는 수십 개의 Method 가 생길지 모릅니다.
그런 상황에서 Service 들끼리 엉켜 있다면 서로를 어떤 의도로 쓰는지, 또 다른 곳에서는 어떻게 쓰이는지 예측하기가 힘들어지기 때문에 수정하기 힘들어집니다.

심한 경우에는 AService 안에서 B, C, D, E, F, G, H, I, J 서비스들을 가지고 있을 수도 있겠지요.

결론적으로 제가 공유하고 싶었던 내용은 초기에 Service 를 만들고 기능을 계속 확장해가며 너무 커져버린 Service 로 인하여 생기는 문제, 그로 인하여 점점 더 확장해나가기 힘들어지는 상황에 대한 경험 그리고 그것을 개선하기 위한 고민과 개선해본 경험을 공유하고 싶었습니다.

한 Service 가 많은 의존성을 가지고 있고 많은 일을 하고 있다면, 그 Service 가 너무 많은 책임을 지고 있다는 것입니다.

의존성과 일이 많으면 테스트하기가 까다롭고, 테스트하기가 까다로우면 확장하는데 자유롭지 못 합니다.

끝없이 요구되는 추가 기능과 버그 수정을 감당하며 문제없이 배포하기 위해서는
모든 객체들의 역할이 명확하고 테스트하기 쉬운 구조를 만들어서 객체들이 유연한 형태라면
당연하게도 확장에 유리할 것입니다.

부족한글읽어주셔서 감사합니다. 많은 생각들을 공유해주시면 감사하겠습니다. geminikims@gmail.com