인프런 커뮤니티 질문&답변

steadyJay님의 프로필 이미지
steadyJay

작성한 질문수

실전! 코틀린과 스프링 부트로 도서관리 애플리케이션 개발하기 (Java 프로젝트 리팩토링)

39강. Querydsl 사용하기 - 두 번째 방법

멀티 모듈에 대한 질문이 있습니다!!

해결된 질문

작성

·

2.9K

2

안녕하세요 !!

자바 개발자가 되기 위해 학습하다가 코틀린을 새로 배우는 과정에서 이 강의를 듣게 된 학생입니다!!

먼저 좋은 강의 제공해주셔서 정말 감사합니다!!

멀티 모듈에서 Repository를 각각 api 모듈에 맞게 구현하고, Spring Data JPA Repository를 코어 모듈에 둔다고 하셨는데. 이런 경우에는 api 모듈에서 core와 관련된 그래들 설정(Querydsl or db 등)이 들어가겠구나 라는 생각이 들었습니다.

멀티 모듈의 장점 중 하나가 모듈의 역할에 맞게 의존성을 관리하는 것도 있다고 생각하는데, 이런 경우 이 장점을 잃지는 않을까 우려됩니다.

그래서 저는 멀티모듈을 사용할 때, core 모듈에 Repository와 관련한 코드를 놓고, 사용하는 모듈에서 인터페이스, 혹은 Repository를 참조하는 구현체를 만들어 해당 클래스만 사용하게끔 유지하는 게 좋지 않을까 생각하는 편인데요. 혹시 강사님의 의견은 어떠신지 궁금합니다!!

(적고 보니 강의 내용과는 조금 다른 질문인 것 같아 조금 죄송스럽네요 ㅠㅠ)

답변 1

2

최태현님의 프로필 이미지
최태현
지식공유자

안녕하세요~!!! steadyJay님!! ㅎㅎㅎㅎ 아이고~~ 매우 좋은 질문이십니다!!! 😊

이게 또 쉽지 않은 주제인데요~~~ 제 생각을 조심스럽게 말씀드려 보겠습니다!!

  1. core 모듈에서는 인터페이스 만을 제공하고, 그 구현이 어떻게 되어 있는지는 상위 모듈 들에서 모르는 채로 사용하는 방식도 좋다고 생각합니다! (core가 그 책임을 가져가는거죠!)

  2. 단, 이렇게 되었을 때 core가 인프라에 강하게 의존하게 되어 이를 우려하는 시각도 존재하게 됩니다. 물론 @Entity class를 작성하는 것부터 core 모듈은 JPA에 강하게 의존하는 것이긴 하지만, 거기에 querydsl까지 얹고 싶지는 않다. 라는 의견을 많이 들었었습니다!

    1. 저도 여기에 대해서 일부 동의하는 편입니다!

    2. core는 가능하면 언제든지 다른 모든 모듈과 분리할 수 있게끔 가져가는 것이 좋다는 이야기도 많이 있고요! 인프라에 지나치게 의존하는 것을 꺼려 하는 느낌도 있습니다 ㅎㅎㅎ 물론 querydsl을 의존하면 지나친 것인가는 또 애매~하긴하죠!

  3. 이런 경우도 있습니다. Application Module에서만 사용하는 A Entity class가 있고 Admin Module에서만 사용하는 B Entity class가 있습니다. A에 대한 쿼리와 B에 대한 쿼리가 모두 core에 모이게 된다면, 과연 이것이 모듈별로 역할이 잘 나누어진 것일까, 라는 의문이죠.

  4. 또한 같은 Entity를 사용하더라도 사실상 다른 쿼리를 사용하는 경우라면, 결국 모든 쿼리는 core에 모이게 되고 비대해집니다.

  5. 추가적으로 쿼리를 작성함에 있어 특히 조회 쿼리는 View에 의존적인 경우가 많습니다. repository에서 바로 DTO를 반환해야 한다면 (강의에서 사용한 Projections.constructor 처럼요!), core에 쿼리가 작성된다 하더라도 그 자체로 독립적인 모듈이 아니라 특정 상위 모듈에 의존하는 코드가 되는 것이죠. 이 부분에 대해서도 애매합니다 😢

  6. 그래서 https://techblog.woowahan.com/2637/ 와 같이 API와 하나의 인프라에만 의존하는 중간 계층 모듈을 설계하기도 한다고 알고 있습니다.

결론적으로, 제 의견은 core에만 qureydsl을 갖고 모든 쿼리를 모으기 vs core는 JpaRepository만 갖고 상위 모듈에서 qureydsl을 필요한만큼 사용하기 를 했을 때 1) 진정한 역할 분리의 애매함 2) core의 비대해짐 3) View에 의존적이게 되는 core 모듈 이라는 단점때문에 후자를 약간 더 선호하는 편입니다.

하지만 당연히~ 프로그래밍에 또 정답은 없고 다양한 상황 (프로젝트의 수명, 인력 상황, 요구되는 비즈니스 속도, 확장성과 안정성의 Trade-Off 등등...) 이 복합적으로 고려되어야 하다보니 명확히 이런 방법이 무조건 좋습니다! 는 아닙니다 ㅎㅎㅎㅎㅎ

아이고~~~ 제 생각이 조금이라도 도움이 되었으면 좋겠네요!!

좋은 질문 남겨주셔서 정말 감사드리고요~ 혹시나 또 궁금한 내용 있으시면 편하게 남겨주세요!!! 😊

좋은 밤 되세요~!! 감사합니다!

steadyJay님의 프로필 이미지
steadyJay
질문자

안녕하세요 강사님!!

늦은 시간임에도 상세한 답변 감사합니다 :) 덕분에 강사님의 생각을 잘 이해할 수 있었어요!!

상황에 맞게 선택을 해서 사용하면 되겠다!! 라는 생각이 들었습니다! 특정 모듈에만 사용돼야 하는 로직이 있다면 그것은 해당 모듈에서 책임을 가져가도록 유지하는 것이 좋은 방법이 될 것 같아요 ! 그렇지않을 경우에는 모듈 분리 자체를 고려해보거나, 모듈을 분리하더라도 코어에 유지해도 괜찮겠네요..!

인프라스트럭쳐 설정으로 인해 중복되는 yml 설정이나 db 접근 구현체에 대해서는 팀원들과 잘 소통이 되어야 겠군요(yml이 중복되는 건 막을 수 없겠죠..?)

실무 경험이 전혀 없어 멀티 모듈을 사용하는 것이 공감도 덜 되고 어려움이 있었는데 강사님의 답변이 정말 큰 힘이 됐습니다!!

내일도 즐거운 하루 되세요 :)

최태현님의 프로필 이미지
최태현
지식공유자

안녕하세요~~ 아이고~ 다행입니다 ㅎㅎㅎㅎ 인프라 설정 같은 경우 yml파일을 중복하지 않게 가져갈 수 있어요!!! 특정 관심사에 대한 설정을 모아두고 (설정별 + profile 별로도 설정할 수 있습니다) 각 모듈에서 해당 yml 파일을 import 하는 방식으로요! - 스프링 2.3.x 까지는 '스프링 yml include'라는 키워드로 스프링 2.4.x부터는 '스프링 yml import'라는 키워드로 검색해보시면 아마 잘 나올겁니다!! 😊

추가적으로 멀티 모듈을 구성하게 되면, 각 기능별 R&R 관점으로도 도움이 되지만, 실제 인프라 환경에서도 '더 큰 도움'이 됩니다!! 어떤 말씀이냐면요, 예를 들어 @Scheduled와 같은 스케쥴러와 @RestController가 한 모듈에 존재하게 되면 (즉 단일 모듈이라면) scale out이 사실상 불가능합니다. 스케쥴러는 보통 동시에 1개만 실행되는 것을 기대하기 때문이죠. 이런 경우에는 트래픽이 많아지면, 스케쥴러만 존재하는 모듈과 API만 존재하는 모듈로 나눠야만 해요! (즉 멀티모듈이죠)

비슷하게 같은 API라고 하더라도 사용처가 다르다면, 사용처가 많은 API들만 scaling을 하는것이 훨씬 효과적이기에 멀티 모듈을 필수적으로 사용하게 됩니다 ㅎㅎㅎㅎ

steadyJay님께서 좋은 포인트들 남겨주셔서 이런 저런 이야기를 더 할 수 있었군요~!!! 오늘도 좋은 하루 되세요 ㅎㅎㅎㅎ 감사합니다! 🙇

steadyJay님의 프로필 이미지
steadyJay
질문자

와!! 꿀팁까지 감사합니다!!! 얼른 사이드 프로젝트에 도입해봐야겠네요 ㅎㅎ

정말 죄송하지만 딱 하나만 더 여쭤보겠습니다 ㅠㅠ (질문이 길어져서 죄송해요)

스케쥴러만 존재하는 모듈과 API만 존재하는 모듈로 나눠야만 해요! (즉 멀티모듈이죠)

만약 위와 같은 상황이 된다면 스케쥴러와 API 모듈은 포트가 달라지고 실행하는 jar 파일이 따로 존재하게 되는 걸까요? 만약 그렇다면 멀티 모듈이 꼭 하나의 JVM에서 돌아갈 필요가 없던거군요. MSA와 멀티 모듈의 큰 차이점이 하나의 JVM 에서 작동하는가 / 아닌가 라고 생각했거든요. 멀티모듈이 단일 JVM에서만 작동된다면 트래픽이 많아질 경우 개선을 기대하기는 어렵겠다 라는 생각도 드네용..

보통 동시에 1개만 실행되는 것을 기대

스케쥴러 같은 경우에도 비동기를 지원(TaskScheduler)해서 동시에 다른 스레드에서 작동시킬 수 있는데, 일반적인 경우에 여러 개의 스케줄러를 한 번에 작동시키는 방식으로는 활용하지 않나요?

다시 보니까 질문이 조금 중구난방이네요 .. 바쁘실텐데 정말 마지막 질문 남기겠습니다 ㅠㅠ 계속해서 친절한 답변 주셔서 정말 감사드려요!!

최태현님의 프로필 이미지
최태현
지식공유자

아이고~~ 아닙니다 ㅎㅎㅎㅎㅎ 저도 설명드리면서 새로운 시각을 또 배워가는걸요~~~!

만약 위와 같은 상황이 된다면 스케쥴러와 API 모듈은 포트가 달라지고 실행하는 jar 파일이 따로 존재하게 되는 걸까요? 만약 그렇다면 멀티 모듈이 꼭 하나의 JVM에서 돌아갈 필요가 없던거군요. MSA와 멀티 모듈의 큰 차이점이 하나의 JVM 에서 작동하는가 / 아닌가 라고 생각했거든요.

네네 맞습니다! 정확히는 port의 경우는 각 최상위 모듈 (이 경우는 스케쥴러 모듈, API 모듈입니다!) 별로 각자 설정할 수 있고요! jar 파일 역시 완전히 독립되어 나오게 됩니다 ㅎㅎㅎㅎ 그렇습니다! 멀티 모듈과 MSA는 약간 다른 개념이에요!! MSA는 Business 관심사 (=도메인) 를 나눠둔 N개의 시스템으로 구성된 구조를 이야기하고, 그 N개의 시스템 중 한 시스템이 멀티 모듈로써 구성이 되는 느낌입니다! (설명을 위해 약간 단순화시켜 말씀드리기는 했지만요 ㅎㅎㅎㅎㅎ...) 😅

스케쥴러 같은 경우에도 비동기를 지원(TaskScheduler)해서 동시에 다른 스레드에서 작동시킬 수 있는데, 일반적인 경우에 여러 개의 스케줄러를 한 번에 작동시키는 방식으로는 활용하지 않나요?

아마 말씀해주신 TaskScheduler라는 것은 비동기가 아닌 Multi-Thread를 말씀해주신 것 같아요!!! ㅎㅎㅎㅎ 제가 말씀드렸던 1개만 실행되는 것을 기대한다라는 의미는, @Scheduled를 붙인 10개의 함수가 있다고 하면, 한 함수가 동시에 2개 이상 실행되면 안된다 라는 의미입니다!!! 보통 이러한 배치성 기능은 동시성을 생각하지 않고 작성하게 되거든요! 즉 TaskScheduler에서 최대 3개의 함수를 동시에 실행시킬 수 있다 하더라도, A / B / C 이렇게 실행시켜야 하지 A / A / A 이렇게 실행시키면 안된다는 의미입니다!!!

물론, 스케쥴링 함수를 동시성을 고려하여 작성할 수도 있지만, 일반적인 경우를 말씀드려 보았어요 ㅎㅎㅎ 추가적으로 스프링 스케쥴러를 사용할 때 ThreadPool에 대한 별다른 설정을 하지 않으신다면, 기본적으로 1개의 thread만 존재하는 pool에 @Scheduled 함수들을 대기시키는 것으로 알고 있습니다! 😊

회사일에 더불어 강의도 들으시고~ 사이드 프로젝트도 하시고~ 정말 멋지십니다!!! ㅎㅎㅎㅎ 덕분에 저도 자극 받게 되네요!! 😊😊 내일도 화이팅 넘치는 하루 되세요!!! 👍

steadyJay님의 프로필 이미지
steadyJay
질문자

정말 친절한 답변 감사합니다!! 강사님 :) 내일도 좋은 하루 되세요~~!!! ㅎㅎ

steadyJay님의 프로필 이미지
steadyJay

작성한 질문수

질문하기