회사 프로젝트 멀티 모듈 도입기(2)

이영훈·2025년 6월 9일
0
post-thumbnail

Common

먼저 공통 모듈인 core와 utils 모듈을 구성하였습니다.

core 모듈에는 도메인과 무관한 공통 기능들이 포함되어 있으며,
예를 들어 광고, 푸시 알림 처리 모듈, 그리고 API 통신을 위한 기본 인터페이스 및 NetworkManager 등이 이곳에 위치합니다.

utils 모듈은 이름 그대로, 전역에서 재사용 가능한 각종 유틸리티 함수 및 확장 함수들을 모아두었습니다.

이러한 공통 모듈 구성을 통해 기능 간 의존성을 분리하고, 각 도메인 모듈들이 필요한 기능만 가져다 쓸 수 있도록 하였습니다.

Data

서버는 v1, v2, ..., vN 형태로 도메인이 다르게 운영되며, 이에 따라 총 5개의 data 모듈(data-v1, data-v2 등)을 구성하였습니다.
각 data 모듈은 내부적으로 기능(feature) 단위로 패키지를 분리하여 관리하며, 다음과 같은 구성 요소를 포함합니다:

  • 각 API 서버에 대응하는 HTTP 요청 함수가 정의된 Retrofit 인터페이스 클래스 (Api 클래스)
  • 공통된 API 생성/관리 로직을 캡슐화한 ApiService 추상 클래스
  • 이 추상 클래스를 상속하여, 실제 API 인터페이스를 생성하고 Base URL을 동적으로 설정하거나 재설정(reset) 하는 기능을 제공하는 구체적인 ApiService 클래스

이러한 구조를 통해, 도메인별 API를 모듈 단위로 명확하게 분리하고, 서버 전환이나 디버깅 환경에서도 유연하게 대응할 수 있도록 설계하였습니다.

Domain

domain 모듈은 data 모듈의 구조를 그대로 따르며, 각 data 모듈과 일대일로 대응되는 1 data ↔ 1 domain 구조를 유지합니다.

presentation 모듈과 data 모듈은 오직 domain 모듈에만 의존하고 있으며,
비즈니스 로직을 담당하는 repository, usecase, 도메인 모델(model)은 모두 domain 모듈에 위치합니다.

이러한 구조는 도메인 계층의 독립성과 각 계층 간의 명확한 역할 분리를 보장하며,
신규 기능 추가나 기존 기능 수정 시에도 유연하고 유지보수가 쉬운 구조를 제공합니다.

실제 API 호출은 presentation 계층(ViewModel 등)에서 domain 모듈의 usecase를 통해 간접적으로 이루어지며,
이를 통해 UI 계층과 데이터 계층 간의 느슨한 결합(Loosely Coupled Architecture)을 실현하고 있습니다.

Presentation

presentation 모듈은 앱의 UI/UX를 구성하는 모든 요소들을 담당합니다.
Activity, Fragment, XML 레이아웃, Compose View 등 사용자 인터페이스와 직접적으로 연결된 클래스들이 이곳에 위치합니다.

사용자와의 상호작용을 처리하고, 화면에 데이터를 표시하며, domain 모듈의 usecase를 호출하여 필요한 데이터를 가져오고 상태를 갱신하는 역할을 수행합니다.

Service

Application모듈로, 서비스별로 각각 추가 및 관리됩니다. 자사에서 운영중인 어플리케이션 서비스는 1개였고 그 서비스의 인프라를 토대로 새로운 서비스를 준비중이었기에 총 두개의 app모듈(service)가 존재합니다.

후기: 내가 멀티 모듈을 선택한 이유, 그리고 느낀 점

제가 멀티 모듈 구조를 선택한 이유는 몇 가지가 있습니다.

우선, 안드로이드 앱 개발을 혼자 담당하고 있었기 때문에(😅) 구조 설계에 대한 자율성이 컸고, 자유롭게 시도해볼 수 있는 상황이었습니다

그리고 결정적으로, 개발팀 리더분께서 항상 가장 중요하게 생각하신 부분이 "큰 수정 없이 재사용 가능한 모듈 구성"과 그로 인한 생산성 향상이었습니다.
백엔드 또한 이 방향성을 고려해서 API 구조나 도메인을 설계하고 있다고 느꼈고요.

이러한 배경 속에서, 앞으로 어떤 신규 서비스를 런칭하더라도 비슷한 아키텍처와 유사한 개발 환경이 반복될 것이라고 판단했고,
자연스럽게 “그렇다면 공통 코드와 기능을 여러 서비스에서 쉽게 활용할 수 있어야겠다” 는 생각에 도달했습니다.
그 결과로, 멀티 모듈 구조가 가장 효과적인 선택이라고 결론 내렸습니다.

✅ 잘된 점

  • 모듈 간 의존성 분리가 명확해짐
    기능 단위로 역할이 나뉘다 보니, 각각의 모듈이 어떤 책임을 가지는지 구조적으로 드러났고, 추후 협업 시에도(안할 것 같지만) 설명이 쉬울것으로 예상됩니다.

  • 빌드 시간 약 25% 단축
    기능이 많은 앱 특성상 전체 빌드 시간이 부담이었는데, 멀티 모듈 도입 후 변경된 모듈만 incremental하게 빌드되면서 생산성이 크게 향상됐습니다.

❗ 아쉬운 점

결국 또 다른 레거시에 갇힌 건 아닐까?
모듈화를 하면서 처음엔 ‘모듈을 쪼개면 모든 게 유연해질 거야!’라고 기대했지만, 시간이 지나며 프로젝트 크기에 비례해 모듈 간 의존 관계가 복잡해지고,
오히려 core 모듈 등 수정 시 ripple effect(연쇄 변경)가 생기는 지점도 있었습니다.
특히 공통 모듈(core/util 등)에 기능이 점점 몰리면서 결합도가 다시 높아질 위험성도 보였습니다.
또한 새로운 기능 추가 시 생각보다 반복되는 작업도 많아졌었습니다.

다음에 보완하고 싶은 점

  • 모듈 간 의존성 흐름을 더 명확히 시각화하고 관리하기
    예: Graphviz 또는 Gradle의 project-report 플러그인으로 모듈 간 관계를 시각적으로 점검

  • 공통 모듈(core/util)에 지나치게 많은 책임이 집중되지 않도록 리팩터링 주기 마련하기
    core-* 형태로 더 쪼개거나, 단위 책임별로 network-core, ads-core, auth-core 등 분산시키는 전략

  • 모듈 템플릿/스캐폴딩 자동화
    새로운 서비스나 도메인을 추가할 때 반복되는 작업이 많았는데, 이를 Gradle script나 CLI 템플릿으로 자동화한다면 구조를 더 잘 유지할 수 있을 것 같음

아쉬운 점들도 있었지만, 개선을 위해 새로운 시도를 온전히 혼자 해냈다는 사실만으로도 꽤 뿌듯했습니다.
언젠가는 이러한 작업들을 혼자가 아닌, 함께 머리를 맞대며 고민하고 만들어가는 경험도 꼭 해보고 싶습니다.

감사합니다!

profile
안드로이드 개발자입니당

0개의 댓글