권용근님의 우아한 멀티 모듈 세미나를 보고 정리한 내용
클린 아키텍처 - "좋은 아키텍처는 시스템이 모놀리틱 구조로 태어나 단일 파일로 배포되었더라도, 후에 독립적으로 배포 가능한 단위들의 집합으로 성장하고, 또 독립적인 서비스나 마이크로서비스 수준까지 성장할 수 있도록 만들어져야한다. 또한 좋은 아키텍처라면 나중에 상황이 바뀌었을 때, 이 진행 방향을 거꾸로 돌려 원래 형태인 모놀리틱 구조로 되돌릴 수 있어야 한다."
개요
실제, 필자는 한이음 공모전에서 MSA 기반 프로젝트를 진행하면서 공통 모듈을 관리했었다. 그리고 이 공통 모듈로 인해 발생했던 다양한 문제점을 몸소 겪었다. 때문에, 공통 모듈이 꼭 정답이 아니란 것을 깨달았고, 공통 모듈을 어떻게 설계해야 할 지 생각을 해보았고 MSA 혹은 멀티 모듈로 개발을 진행할 때 가장 중요한 것이 무엇인지 알고 싶었다.
문제점 살펴보기
MSA는 간단하게 서비스가 내부적으로 받는 도메인 단위를 상세하게 분리하고 그 안에 격리되는 서비스를 구상한 방식이다.
Monolithic 구조는 하나의 Service에서 API, ADMIN, BATCH, WEB, DB 등이 관리되는 구조이다. 그리고 'Monolithic'은 단일 모듈 멀티 프로젝트와 멀티 모듈 단일 프로젝트로 나뉜다.
단일 모듈 멀티 프로젝트
각 프로젝트 단위 : IDE를 쓴다면 3개의 IDE 화면을 띄워둔 상태로 개발 진행하는 형태이다. 위에서 보면 'User Class'가 공유(중복)되고 있다. 때문에, 사용자 내부 API에서 'User' 수정 시, 나머지 프로젝트도 수정을 해야한다. 즉, 사람에게 의존되고 있고 이는 장애 위험성 올라간다.
멀티 모듈 단일 프로젝트
이는 프로젝트는 하나이고, 그 안에 여러 모듈을 설치 가능한 방법이다. 즉, 단일 모듈 멀티과는 다르게 IDE도 1개만 사용하고 시스템적으로 보장되는 일관성, 빠른 개발 사이클을 확보할 수 있게 되었다. 하지만, 멀티 모듈을 확립해 나가는 과정에서 겪을 수 있는 문제점들이 있다.
문제점
우리는 멀티 모듈 단일 프로젝트를 보면서 "공통 코드는 따로 관리할 수 있지 않을까?"란 생각을 할 수 있다.
- 멀티 모듈을 통한 단순한 공통 로직 접근.
- 공통 로직을 분리해 'Core Module'을 생성하여 관리.
하지만 이는 큰 문제점을 야기한다.
예를 들어, "코드를 모듈화 한다" -> "중복을 최소화한다" 란 생각으로 위 그림처럼 세 모듈이 모두 공통되지 않아도 'Core Module'에 포함시켜보자. 이러다 보니, 점점 'Core Module'이 커지고 'Core Module' 안에서 비즈니스가 흐르기 시작했다. 즉, 원래는 다른 모듈에 플로우를 추가 해야 하지만, 어쩔 수 없이 'Core Module'에 플로우를 추가하는 사태가 발생할 것이고 다른 애플리케이션은 굉장히 가볍지만, 'Core Module'만 매우 무거운 프로젝트로 구성될 것이다.
공통 모듈의 스파게티 코드
우리는 스파게티 코드로 인해, 특정 기능이 사라져도 의존도가 높으면 클래스를 제거할 수 없게 되었고 분해하고 싶어도 분해할 수가 없게 되었다. 예를 들어, 'Core Module'에서는 애플리케이션이 사용할 수 있는 의존성을 모두 품게 되기 때문에, 사용하지 않는 것조차 의존을 하고 있었다.
성공적인 멀티 모듈
위에서 발생한 문제점을 해결하기 위해 우리는 레이어 아키텍처 시점이 아닌, 애플리케이션 시점으로 바라보자.
해당 모듈들이 어떤 역할을 해야할 지 다음과 같이 생각해보고 하나하나 살펴보자.
독립 모듈
- 시스템과 무관하게 어디서나 사용 가능한 라이브러리 성격의 모듈을 이 계층에 배치하자.
- 즉, 프로젝트 내 가장 프로젝트와 성격이 먼 모듈이 이 계층에 위치한다.
- 예를 들어, 시스템/도메인의 비즈니스와 전혀 별개로 자체 제작한 라이브러리 같은 모듈이 이 계층에 들어갈 것이다.
독립 모듈 원칙
- 자체로서 독립적인 역할을 갖는다. (즉, 따로 오픈 소스로 업로드 해도 될 정도의 스펙을 가진 모듈)
- 이 계층의 모듈을 대처할 탄탄한 라이브러리가 나온다면 프로젝트에서 이 모듈은 제거 될 것이기 때문에, 프로젝트 내에 의존 관계를 두지 않는다.
정리)
build.gradle에 어떤 것도 의존하지 않는다.
오픈 소스화해도 괜찮은 정도의 모듈이지만, 우리 시스템에는 필요한 모듈
공통 모듈
- 공통 모듈은 위에서 설명했듯 최대한 피하자. 하지만 만들어야 한다면, 'Type', 'Util' 등을 정의하는 용도로 사용하자.
- 그리고 공통 모듈에는 다음과 같은 엄청 큰 제약을 걸어두자.
- 의존성 걸지 않기. -> 전체 시스템에 물려 있어야 하기 때문에,
- 순수 자바 코드 사용하기. -> 왜? 의존을 물어도 무거워지지 않기 위해.
도메인 모듈
- 시스템의 중심 도메인을 다루는 모듈을 이 계층에 배치한다.
- 내부 모듈 계층과 비슷한 성격의 계층이지만, 저장소와 밀접한 중심 도메인을 다루는 계층은 더 견고하고 특별하게 격리 후 관리해야하기 때문에, 반드시 분리해야 한다.
- 이 계층에선 프로젝트 안의 어떠한 실행 가능한 어플리케이션에서도 사용 가능한 모듈이 위치해야 한다.
- 즉, 저장소 외 시스템 특성을 알지 않아야 하기 때문에 내무 모듈 계층을 의존하지 않도록 한다.
도메인 모듈 원칙
- 서비스 비즈니스를 모르게 한다.
- 하나의 모듈은 최대 하나의 'Infrastructure'에 대한 책임만 갖도록 한다.
- 도메인 모듈을 조합한 더 큰 단위의 도메인 모듈이 있을 수 있다.
- 도메인 모듈을 구성할 땐 객체지향 설계를 전제로 하고 있다.
이해를 돕기 위해 다음 예시를 보자.
- Domain : JPA 기준으로 테이블과 맵핑되는 클래스
- Repository : 도메인의 CRUD 역할
- Service : 도메인의 비즈니스를 책임 (트랜잭션 단위 정의, 요청 데이터 검증, 이벤트 발생 등)
다중 Infrastructure 사용하는 모듈
- 도메인 계층에서 'Infrastructure'를 사용해야할 때 꼬이는 의존 관계가 발생한다.
- 즉, 하나의 모듈은 하나의 'Infrastructure'만 책임지도록 모듈을 작성하는 것 추천한다.
결론)
도메인 모듈은 오로지 도메인에 집중하도록 하자.
예를 들어, 좋은 도메인 구성을 위해 도메인이 'Infrastructure'를 모르게 하자.
하지만 우리는 "객체지향을 무조건 100% 지켜야 하나? -> No"를 항상 생각해야 한다.
즉, 순수성을 위해 실용성을 포기하는 건 어리석은 일이다.
왜냐하면, 실제로 'Infrastructure' 대한 탈바꿈이 일어날 일은 거의 없다. 근데 만약, 인프라와 도메인이 서로 모르는 상태로 존재하면 도메인 계층에 수많은 인터페이스가 생성된다. 즉, 어중간한 모듈화가 중복 코드보다 좋지 못하게 될 것이다.
내부 모듈
- 저장소/도메인 외 시스템에서 필요한 모듈들이 이 계층에 속한다.
- 독립 모듈 계층은 시스템에 전혀 관여되지 않았다면, 이 계층은 시스템과는 연관이 있는 모듈을 말한다. 즉, 시스템 안에서 의미를 갖는다.
- 때문에, 시스템 전체적인 기능을 서포트하기 위한 기능 모듈이 만들어질 수 있고 이 계층 역시 프로젝트 안의 어떤 실행 가능한 어플리케이션에서도 독립 사용이 가능한 모듈이 위치해야 한다. 즉, 도메인 계층을 의존하지 않는다.
내부 모듈 원칙
- 어플리케이션 비지니스를 모른다.
- 도메인 비지니스를 모른다.
어플리케이션 모듈
- 독립적으로 실행 가능한 어플리케이션 모듈 계층으로 모든 모듈들을 조합하는 곳이다.
- 즉, 하위 설계 했던 모듈들을 조립하여 서비스 비즈니스를 완성한다.
- 때문에, 이 계층의 모듈에게는 ‘APP’ 이라는 'Naming'을 넣어서 모듈 내의 실행 가능한 어플리케이션이라는 것을 명확하게 하자.
- 어플리케이션 모듈은 독립 모듈 계층, 도메인 모듈 계층, 내부 모듈 계층, 공통 모듈 계층 을 사용성에 따라 의존성을 추가하여 사용.
멀티 모듈 구성 효과
1) 명확한 추상화 관계
- 각 모듈이 갖는 책임과 역할이 명확하여 리펙토링, 기능의 변경의 영향 범위를 파악하기 용이.
- 경계가 명확해짐으로써 기능의 제공 정도를 예측 가능하여 스파게티 코드 발생 가능성이 줄어듬.
- 역할과 책임에 대한 애매함이 없어짐으로써 어떤 모듈에서 어느 정도까지를 개발되야할지 명확.
2) 최소 의존성
'Activity > 한이음 - MSA 기반 시스템' 카테고리의 다른 글
한이음 - API Gateway, Eureka (0) | 2022.06.02 |
---|---|
한이음 - MSA를 공부하면서 고민했던 것들. (0) | 2022.06.02 |
한이음 - MSA 기반 인사이력 블록체인 검증 시스템 (0) | 2022.06.02 |