본문 바로가기

카테고리 없음

[2022 인프콘] 실전! 멀티 모듈 프로젝트 구조와 설계, 김대성 정리

1️⃣(WHY) 왜 멀티 모듈 프로젝트 구조가 중요할까?

아키텍처는 프로젝트 초기에 이루어져야 하는 일련의 설계 결정이다
아키텍처는 요소의 구조와 그 관계에 관한 것

"아키텍처"를 "멀티 모듈 프로젝트"로 바꿔서 얘기를 하자면

-> 시스템, 배포 프로세스 모두 관련이 되므로 나중에 변경하기 어렵다

-> 리스크를 줄이기 위한 시작

 

1. 코드의 복잡성이 커지는 원인

  • 구현 코드 많아지거나/ 다른도메인 서비스가 늘어나면서 공통적인 기능들이 많아지면 개발자들은 "중복을 제거해야한다" 라는 강박 관념으로 core, common(공통적인 기능들을 묶어서)으로 중복을 만든 것이 문제

2. 실제로 발생하게 되는 문제점

  1. Too many connections
    : 서비스가 커져가면서 다른 도메인이 추가되고, 트래픽이 늘어나면서 서버 수를 늘리게 되면 커넥션 풀을 할당받기 때문에 발생하는 에러 
  2. java.lang.NoClassDefFoundError
    : 특정한 모듈이 하위 버전 라이브러리를 참조하는 경우 업그레이드 난해
  3. Copy & paste
    : 참조하는 곳이 너무 많아 일단 if ~ else로 분기 처리
    -> 이러한 코드가 많아지면 깨진 창문 효과로 비슷한 코드가 증가하게 된다.
  4. All build & deploy
    : 특정 클래스에서 배포를 하려면 전체 빌드 -> 개발 생산성에 영향

 

2️⃣(WHAT) 무엇을 기준으로 멀티 모듈 프로젝트 구조를 나눌까?

  • 올바른 멀티 모듈 프로젝트 구조를 위해 확인해 봐야 할 것
    • 역할, 책임, 협력관계가 올바른가?
    • 서비스 도메인 기반의 구조를 지향, 기술 베이스 지향적인 모듈 구조 지양

 

  • CORE, COMMON 모듈은 삭제하고, 그래도 CORE, COMMON이 정말 필요한지 고민하기
    • 일부 코드에 대해서는 중복을 허용
    • 중복 코드가 있더라도 CORE, COMMON이 가지고 있는 잠재적 위험성 제거가 더 중요
  • 바운디드 컨텍스트를 사용하여 멀티 모듈 구조 나누기
    : 모델을 완전한 의미를 갖도록 하는 구분되는 경계. 한 개의 바운디드 컨텍스트는 논리적으로 한 개의 모델을 가짐
    DDD는 큰 모델을 서로 다른 Bounded Context로 나누고 상호 관계를 명시하여 처리
    • ⭐️ 멀티 모듈 그룹 기준 정의 ⭐️
      1. Boot (Server) 그룹 
        •  Server application
        • 코드의 변화가 가장 잦음
        • ex) Batch, Admin, Api와 같은
      2. Data (Domain) 그룹
        • 서버 모듈과 밀접한 관계
        • 도메인 영역으로 Data Store을 직접 핸들링
        • ex) meta, user, chart
      3. Infra 그룹
        • 업체 연동을 위한 모듈
        • 구현 후에는 변화가 적음
        • 버전 업에는 코드의 큰 변화
        • ex) and, vod, photo, biling
      4. Cloud(System) 그룹
        • 서버 관리를 위한 모듈
        • 컨테이너 환경과 시스템 관리를 위한 그룹
        • 변화 적음
        • ex) config, gateway, discovery, aws, gcp, azure

 

  • 위 네 가지 그룹은 각자 고유한 특성과 사이클을 가지고 있음
  • 이 기준으로 경계를 나누고  프로젝트를 구성

 

3️⃣ (HOW) 실전 멀티 모듈 프로젝트 구현하는 법

 

이를 세분화해서 표현하면 위와 같은 형태가 되는데, 여기서 장점과 단점을 찾아볼 수 있다.

 

  • 장 점 : 
    • 가독성 좋아짐. Build.gradle에서 그룹 폴더 명을 기준으로 일괄적으로 선언할 수 있음
    • 프로젝트 경계가 명확. 실제 인터페이스 설계도 어떤 내용을 주고받아야 하는지 명확해질 수 있음
  • 단 점 : 
    • 프로젝트가 늘어나면서 빌드 시간 증가 -> 개발 생산성 저하
    • cloud-config의  설정 파일(remote config server)을 수정하게 되면 GitHub webhook으로 이벤트를 전달하게끔 설정하여 데이터 리프레시 처리하였는데 해당 프로젝트의 변경만이 아닌 다른 프로젝트에도 이벤트가 반응하는 이슈 발생 (관리적 이슈)

 

멀티 모듈 프로젝트에 맞게 다시 한번 나누면

 

1. 변화가 가장 잦은 data, boot는 그대로 유지

2. cloud/system 그룹을 별도의 2개의 저장소로 분리

  • 하나는 시스템적 프로젝트
  • 다른 하나는 웹 훅 이벤트를 필요로 하는 remote config server 프로젝트

3. infra 그룹을 infra-library로 분리

 

  • 장 점 :
    • 빌드 시간 단축
    • 프로젝트 경계 명확해져서 인터페이스 구현 설계에서 어떤 내용을 주고받아야 하는지 확연히 명확해짐

 

 

✅ 분리되어 있는 각 저장소 별 구현 방법

1.  DATA(DOMAIN) -> INFRA 모듈 관계

 

background

- 뮤직 도메인에는 Playback 도메인이 존재

- Playback은 AOD 인프라 라이브러리에 모듈을 통해 외부에 존재하는 재생 관련 데이터를 요청하고 응답

구현 방식 : 일반적으로 중앙에 Artifactory 저장소에 빌드 타임에 라이브러리를 업로드하게 되고, 사용하고자 하는 프로젝트에서 의존성을 선언하여 구현 

 

내부 구현 클래스 다이어그램

문제점 : 해당 라이브러리에서 사용하는 batch job에 agent 수가 많다면, Too many Connections 문제 봉착 

 

 Solution


1. DB 접근을 data model 쪽으로 이동해서 구현 
2. TrackPlaybackService를 data 쪽에서 구현하여 DB 호출
3. infra aod 모듈에서 aod playback service 구현 - 요청/응답에 대해 책임

 

TIP

1. 모듈을 나누는 경계로 생각해보면 인프라 라이브러리 프로젝트는 호출하는 프로젝트와 관계없이 자신의 역할과 책임인 aod 서버를 올바르게 호출하기 위해 설계되어야 한다.

2. 협력관계에서 주고받는 메시지가 객체의 책임을 결정, 책임을 자율적으로 만드는 것이 애플리케이션의 성질을 결정하는 좋은 방법이다.

 

 

2. BOOT-DATA 관계 구현

: 서비스 구현체는 어디에 두는가

 

background : 

- 싱크가사가 없는 경우 후처리로 생성하는 기능

런타임에 이벤트를 전달하여 후 처리를 하려 함

요청이 오게 되면 boot-meta project -> data-meta repository를 통해 가사 전달

이때 없다면 생성 요청

 

서비스의 구현 위치를 어디에 두는가? 양쪽 모두에 구현되어야 한다

싱크가사를 생성하는 이벤트(카프카 이벤트 처리) -  boot-meta 모듈을 통해 발생

타임스탬프가 생성 이후 - Data-meta에서 service를 통해 저장 

 

서비스 구현체는 프로젝트별로 역할에 맞도록 각자 구현되어야 한다.

 

** Boot - data 간의 규칙

data에서는 반드시  서블릿 리퀘스트와 같은 웹 서버에 의존적인 객체를 전달하지 않는다.

=> 역할과 책임 협력관계에 올바르지 않음(쿠키 세션 포함),

Data-meta는 배치에도 사용될 수 있고, 웹 애플리케이션도 사용, 또 다른 원타임 애플리케이션에서도 사용 가능

모두가 웹 서버를 기반으로 동작되지 않을 수 있기 때문에 테스트 코드 작성 시 웹 서버 관련된 라이브러리가 모두 필요, 의존성을 갖게 된다면 발생되는 일들이 많아짐, 의미 상실

 

 

3. Cloud- boot 관계 구현

: discovery와 같은 제품을 사용한다면 문제 발생 -> 버전업의 경우 모든 서버 프로젝트가 의존성을 함께 갖기 때문에 다시 빌드한 후 배포가 되어야 함

 

문제 : 웹 애플리케이션의 변화가 없었는데도 전체 빌드를 다시 해줘야 하는 것은 의존성을 명확하게 분리할 필요가 있음

 

=> istio : 쿠버 네티스 기반의 서비스 매시 플랫폼

Envoy proxy를 통해 트래픽 관리

*sidecar pattern 방식으로 자신의 애플리케이션을 관리 및 제어

- 쿠버 네티스 기반이라면 도입 고려

 

 

📝 Summary

 

Conway’s law

: 시스템을 설계하는 조직은 어떤 조직이든 그 조직의 소통 구조를 닮은 구조를 가진 시스템으로 설계할 것이다.

 

-> 멀티 모듈프로젝트 역시 현재 조직의 소통 방식을 닮은 모습으로 개발될 것임

-> 구성하는 적절한 나만의 기준이 있다면 변화에 능동적으로 대처할 수 있을 것

 

좋은 멀티모듈 프로젝트 구조란? 

어떤 회사든 특정 시점에 부서가 나뉘고, 또 자연스럽게 합쳐질 것임

잘 설계된 멀티 모듈 프로젝트 역시 언제든 서비스 방향성에 맞게 하나로 합쳐질 수 있거나 다시 나눌 수 있도록 설계될 것

 

 

 

위 글은 인 프콘 2022 김대성 님의 실전! 멀티 모듈 프로젝트 구조와 설계 강연을 정리한 글입니다.

https://inf.run/H2MB

 

[무료] 인프콘 2022 다시보기 - 인프런 | 강의

인프런의 첫 오프라인 콘퍼런스, 인프콘 2022에서 진행된 오프닝 및 발표 세션을 영상으로 다시 보실 수 있습니다., - 강의 소개 | 인프런...

www.inflearn.com