⌨️ What About U?
앞으로 꾸준히 쓰게 될 포스팅 중 하나이다. 따로 어디 카테고리에 넣기가 애매해서 Dev에 넣고 꾸준히 쓰려고 한다.
Spring에 대한 고민일 수도 있고, Java 혹은 DB에 대한 고민이 있을 수도 있다.
물론 당장은 신입이기에 신입의 시각에서 보는 관점이라 많이 틀릴 수도 있고 패러다임에 맞지 않을 수도 있지만, 사고하고 공유한다는 것에 의의를 두고 싶다.
1. Service Layer
Layerd Pattern 하면 현재로선 Controller-Service-Repository가 꽤 눈에 익지 않을까 한다.
당연히 Controller가 하는 일 Service가 하는 일 이런 걸 쓰고자 했으면 안 썼을 포스팅이다.
내가 고민하고 예전과 생각이 달라진 점은 바로 Coupling과 Cohesion 부분이다.
우선 간단히 코드 하나를 보고 가자
@Service
public class ArticleService {
private final ArticleRepository articleRepository;
private final UsersRepository usersRepository;
... 생략
}
흔히 Spring에서 볼 수 있는 방법인데 무슨 문제라도..?
나 또한 그렇게 생각했다.
분명 우리는 자바 공부를 할 때 그리고 스프링 공부를 할 때 늘 재사용성과 확장성 블라블라.. 를 입에 달고 산다.
시니어들이 서류보고 괜찮아서 면접 보려고 Github를 봤는데 코드를 보고 많이 실망했다.라고 말한다면 이런 부분에서 발생한 게 아닌가 싶다.
2. Service에서 다른 도메인(Entity)의 Repository를 주입
우선 나의 예전의 관점은 이러하였다. 그리고 당시 같이 공부했던 사람들과 토론해서 내린 결론이기도 하다.
위의 코드를 도식화하였다. 자 이 상황에서 Users 도메인을 분리해보자.
어떤가? 생각처럼 분리하기가 쉽지 않을 것이다. 나는 이것에 대한 이유를 Repository를 직접 의존하고 있기 때문에라고 생각한다.
필연적으로 Repository를 의존하면 Entity를 보유하고 있는 게 여러모로 구현이 편해진다.
(* 혹 아닐 수도 있으니 틀렸다면 지적 바랍니다 :) )
나는 예전엔 횡단 간 의존성 주입이 강결합이라고 생각했다. 무슨 말이냐면 Service가 다른 Service를 의존성 주입받는다면 둘의 결합도가 높아진다고 생각한 것이다.
근데 위 그림에서 보면 알다시피 위와 같은 구조는 Users 도메인의 응집도가 낮아진다. 이유가 무엇일까?
Users라는 관심사 안에 있는 UsersRepository가 Article에서도 사용되기 때문이다. 비단 이뿐만 아니라 Users라는 건 거의 모든 도메인이 참조할 가능성이 높다. 그렇다면 Users를 분리할 수 있는가?
이러한 생각을 계속해온 결과 지금에서는 Service의 횡단 간 의존성 주입이 더욱 결합도를 낮추고 확장에 용이하다는 판단을 했다
당연하게도 Trade-off기 때문에 그에 따른 단점도 발생한다. 예를 들어 Repository에서 바로 접근할 수 있는 Users 객체를 서비스에서 호출해서 가져와야 한다든지, 더 추상화되기 때문에 흐름을 한눈에 파악하기는 힘들 수도 있다.
3. Service에서 Service를 주입.
자 그럼 이런 흐름에서는 Users를 어떻게 분리할 수 있을까? Article Server가 따로 생겨 서로 다른 Server에서 동작한다든지 다른 모듈일 경우에 말이다.
가장 흔히 볼 수 있는 예로는 역시 MSA 환경에서 처럼 MQ 활용일 것이다. 그냥 Users를 가져와서 MQ로 Article 서버로 넘겨주면 된다.
아니 첫 번째도 그럼 그렇게 하면 되는데요??
라고 하겠지만, 첫 번째는 Service 자체가 Repository를 주입받고 있기 때문에 의존성을 끊어버리면 기능자체가 불가하다는 게 나의 생각이다.
이를 바탕으로 리팩터링 한 나의 변화된 코드를 보여드리면
이런 느낌이다
Repository를 주입받는 것은 하나의 도메인으로 엮인다. 나머지는 분리한다고 하더라도 문제 되지 않는다.
그렇다면 나중에 서비스가 분리되어 Users가 이 서버에서 사라진다면? Controller에서 MQ로 Users를 받아서 넘겨주면 그만이다.
간단한 예로
@Transactional
@Override
public Article createArticle(Users user, RequestArticleDto requestArticleDto, List<String> storeNameList) throws
IOException {
Category category = categoryService.readCategory(requestArticleDto.getCategoryCode());
Article article = articleRepository.save(requestArticleDto.toEntity(category, user));
이런 느낌이 되지 않을까 한다. 물론 user는 json 객체로 올 수도 있고 혹은 그냥 column에 필요한 user의 어떤 String 값이 올 수도 있다.
정리하자면 내 생각엔 서비스에서 서비스를 주입하는 게
- 조금 더 결합도를 낮추고 응집도를 높여, 확장에 용이하다.
- 로직의 분리 혹은 관심사의 분리 측면에서도 더욱 유연하게 설계할 수 있다.
- 그럼에도 왜 많은 교육과정과 강의에서 Repository 주입을 할까? -> 더 고민해 봐야겠다
는 결론이다.
여러분들의 생각은 어떠한가?
* 우선 내 생각은 항상 프바프고 팀이 하자는 대로 가는 게 맞지만, 생각의 폭은 넓혀두는 것이 좋은 것 같다.