나의 모듈 여정

들어가며

“이게 맞나?”

– 프로젝트를 설계 할 때 마다..

지금까지 개발자로 일해오면서 크고 작은 프로젝트, 적고 많은 프로젝트 등 다양한 프로젝트를 겪었다. 개발하고 운영해온 프로젝트들의 아키텍처 및 모듈 구조에 대한 개발 및 운영 경험에 대해 공유하고자 한다.

작은 규모의 단일 모듈 프로젝트

가장 간단한 형태의 프로젝트이다. 토이 프로젝트나 내부 시스템과 연관이 없는 간단한 서비스의 경우 많이 볼 수 있었다. 규모가 작기에 모듈에 대한 재사용성, 의존성 관리가 필요하다고 생각하지 않아 모듈화를 따로 진행하지 않았다. 그렇기에 운영 입장에서도 쉽게 이해하여 유지 보수가 가능했다.

단일 모듈 모놀리식 프로젝트

옛날에 개발된 프로젝트는 단일 모듈에 단일 프로젝트 형태인 모놀리식 아키텍쳐 형태가 많았다. 모든 DB Access, API, 비즈니스 로직 등 모든 것이 하나로 집약되어 있기에 쉽게 데이터 흐름을 따라가면서 해당 프로젝트를 이해할 수 있었다.

하지만, 이는 명확한 비즈니스 바운더리를 알기 어려웠다. 또한, 해당 프로젝트는 운영 상 문제가 가장 크게 다가왔다. 일부분의 이슈가 서비스 전체 장애로 전파되는 된다는 점이다. 데이터 수집 및 처리에서 이슈가 생겼지만 서비스 전체의 장애로 전파되어 API 호출이 원활히 이뤄지지 않았다.

장점

  • [개발] 모든 코드가 해당 프로젝트에 존재하여, 데이터 흐름을 따라가기 쉽다.
  • [개발] 빌드 및 배포가 간단하다.
  • [개발] 타 서비스와의 호출이 적기에 테스트하기 용이하다.
  • [개발] 하나의 언어로 작성되었기에 해당 언어만 잘 알고 있다면 쉽게 이해라 수 있다.

단점

  • [개발] 모든 코드가 해당 프로젝트에 존재하여, 자신이 보려는 비즈니스 바운더리를 알기 어렵다.
  • [개발] 규모가 커짐에 따라 빌드 및 배포 시간이 오래 걸린다.
  • [운영] 일부분의 오류가 서비스 전체의 장애로 전파된다.

단일 모듈 마이크로 서비스 프로젝트

기존 레거시 서비스가 운영상 문제가 많아 단일 모듈의 마이크로 서비스로 전환하기로 결정했었다. 각 모듈을 각각의 프로젝트로 만들어 활용하였다. 내부 레파지토리에 해당 라이브러리들을 배포하고 해당 모듈을 필요로 하는 서비스가 라이브러리를 임포트하여 사용했다. 기능별, 도메인별로 서비스를 나누어 개발, 운영하였다.

나누어진 서비스들은 해당 역할만을 담당하였기에 비즈니스 바운더리가 명확해졌다. 하지만 서비스 간 API 및 이벤트 호출이 많아져 분산된 서비스의 데이터 흐름을 따라가기엔 어려움이 있었다. 특히 메시지 기반의 통신을 구축할 경우 Publish와 Subscribe의 서비스를 알기 어려웠다. 해당 메시지가 어떤 서비스로부터 오는 것인지, 어떤 서비스가 해당 메시지를 받아 처리하는지 순수 코드상 알 수가 없어 문서에 의존할 수밖에 없었다. 또한, 각 의존하는 모듈들이 각 프로젝트로 구성되었기에 하나의 기능을 추가 개발하기 위해 여러 모듈의 프로젝트들을 수정해야 했다.

장점

  • [개발] 서비스 단위로 나뉘어져 있기에 자신이 보려는 비즈니스 바운더리를 알기 쉽다.
  • [개발] 서비스에 적합한 언어로 개발, 유지보수가 가능하다.
  • [개발] 빌드 및 배포가 빠르다.
  • [운영] 일부 서비스의 오류가 전체로 확산하지 않는다.
  • [운영] 하드웨어 성능을 효율적으로 사용할 수 있다.

단점

  • [개발] 프로젝트가 나뉘어져 있어 여러 IDE를 띄워놓고 개발해야 한다.
  • [개발] RPC, Message 등 서비스 간 통신이 많아 데이터 흐름을 따라가기 힘들다.
  • [개발] 기능 개발 및 수정 시 다수의 단일 모듈 프로젝트를 배포해야 한다.
  • [운영] 서비스가 분산되어 있기에 관리하기가 힘들어 관리하기 위한 써드파티가 필요하다.

멀티 모듈 마이크로 서비스 프로젝트

멀티 모듈 프로젝트란 하나의 프로젝트에서 여러 모듈을 포함하는 것을 의미한다. 그리하여 단일 모듈 프로젝트들에 비해 기능 개발 및 디버깅하기에 용이하다. 기존에 기능을 개발하기 위해서 단일 모듈로 이뤄진 여러 개 프로젝트를 기능 추가, 수정 및 배포하고 의존성 업데이트해야 하는 점이 무척 번거로웠다. 이러한 단점을 보완하고자 요즘에는 멀티 모듈을 적극적으로 활용하고 있다.

장점

  • [개발] 단일 모듈 마이크로 서비스와 달리 하나의 IDE로 개발이 가능하다.

단점

  • [개발] 다양한 모듈들이 존재하기에 빌드 및 배포 시 복잡성이 증가한다.

모듈

모듈은 의도를 가지고 책임과 역할이 부여되어야 한다.

멀티 모듈을 하기 위해선 어떻게, 어디까지 모듈을 나눌 것인지가 가장 큰 화두이다. 기능별, 도메인별, 아키텍쳐별 등 다양한 방식으로 모듈화를 진행하고 있다. 무엇이 정답이다라곤 답은 못하겠으나, 모듈이 가지는 의미, 의도를 돌이켜보며 모듈화를 진행해왔다. 모듈화에 가장 중요하다고 생각한 점은 의도를 지닌 시스템에서의 모듈 역할이다. 해당 모듈을 어떻게 사용할 것인가, 어디까지 사용할 것인가를 생각해야 한다. 또한 모듈들의 추상화 정도도 고려해야 한다.

도메인 공통 모듈

한 시스템에서 필요한 도메인들을 한곳에 모아 관리하면 좋을 것 같아 시도했던 방법이다. DB Access를 위한 Entity, DTO, Repository를 모아 구성하였다. 어떠한 마이크로 서비스던 해당 모듈을 의존하면 최신의 도메인을 사용할 수 있었다. 하지만 시간이 지남에 따라 더 다양한 마이크로 서비스가 생성되고, 시스템에 규모도 커지게 됨에 따라 거대해지기 시작했다. 해당 모듈에 MongoDB와 MariaDB가 같이 구현되어 있기에 불필요한 DB 커넥션을 가지게 되었으며, 도메인 기능 수정 시 다른 서비스와 연관도 고려해야 했다. 결국에는 시스템 전체의 도메인을 하나의 모듈로 관리하는 방법은 잘못된 방법이었다.

공통 모듈이 나쁜가?

재사용성 측면에서 공통 모듈이 가지고 있는 가치는 무시할 수 없다. 위에서 사용한 건 도메인을 하나의 공통 모듈로 관리하려는 게 잘못된 것이지 공통 모듈이 나쁜 것은 아니다. 물론 도메인 외에도 시스템에서 공통으로 사용되는 모듈을 사용하다 보면 해당 공통 모듈이 점점 거대해지는 것을 볼 수 있게 되고, 관리하기가 어려워질 것이다. 그렇기에 거대한 공통 모듈을 갖게 되는 것을 경계해야 한다. 그리하여 공통 모듈은 타입 정의, 유틸리티와 같은 기본적인 것들로 구성하고 어떠한 모듈에서도 사용될 수 있게 최소한의 의존성을 가져야 한다.

도메인 모듈

현재는 마이크로 서비스 프로젝트는 도메인 모듈을 지닌 형태로 개발 운영하고 있다. 도메인 모듈에는 Entity, DTO, Repository가 포함된다. DTO나 Repository 경우 마이크로 서비스에서 사용되는 모든 것을 포함하지 않는다. 특정 비즈니스에 결부된 경우엔 각 서비스에서 선언 및 처리를 담당하게 된다. 즉 도메인 모듈에 포함된 것들은 가장 기본적이며, 범용적이다.

마치며

많은 신규 프로젝트들은 멀티 모듈의 마이크로 서비스 프로젝트로 진행되고 있다. 무조건 모든 프로젝트를 멀티 모듈로 진행하지는 않는다. 각 프로젝트의 규모, 성격이 있기에 이를 고려하여 개발하고 있다. 계속해서 프로젝트를 개발하면서 끊임없이 “이게 맞나?” 자문하고, 다양한 멀티 모듈 경험을 듣고, 찾아보면서 적합한 환경으로 개발하려고 노력해나가야겠다.

참고 문헌

멀티모듈 설계 이야기 with Spring, Gradle

Multi-Project Build Basics

Leave a comment