멀티모듈은 왜 쓰는걸까?

GongBaek·2024년 5월 15일
0
post-thumbnail

📍 멀티모듈을 알아보자


모듈이란?

공식문서 기준으로 모듈의 정의는 다음과 같습니다.

모듈은 소스 파일 및 빌드 설정으로 구성된 모음이며, 이를 통해 프로젝트를 별개의 기능 단위로 분할할 수 있습니다. 프로젝트에는 하나 이상의 모듈이 포함될 수 있으며, 하나의 모듈이 다른 모듈을 종속성으로 사용할 수 있습니다. 각 모듈은 개별적으로 빌드, 테스트 및 디버그할 수 있습니다.


위 그림의 예시는 단일 모듈로 구성했을 경우의 구조도라고 볼 수 있습니다.

  • 하나의 App 모듈로만 구성된 예시입니다.
  • 앱의 규모가 작다면, 가장 이해하기 쉽고 간편하게 개발이 가능합니다.
  • 하지만 그만큼 자연스럽게 소스코드 간의 결합도가 높아집니다.
  • 결합도가 높아진 만큼, 유지보수성에 취약해집니다.

멀티모듈이란?

결국 멀티모듈이란 하나의 프로젝트를 여러 개의 독립적인 모듈로 분리하여 구성하는 방식입니다. 이러한 구성 방식을 사용하면 다음과 같은 장점이 존재합니다.

  • 코드의 재사용성이 증가합니다.
  • 관심사의 분리를 통해 의존성을 줄입니다.
  • 앱 빌드 속도를 유의미하게 단축시킵니다.
  • 앱 무결성 및 유지보수성이 향상됩니다.

그래서 어떻게 분리하는데?

01. 계층별 모듈 분리


한 아키텍처에서의 각 계층별로 모듈을 할당하는 방식을 예시로 가져왔습니다. 위의 예시에서는 presentation, domain, data라는 모듈로, 아키텍처의 각 계층에 따라 모듈을 분리한 모습을 볼 수 있습니다.

쿠팡의 서비스를 보면 app, feature, core로 역시 계층별 분리를 한 모습을 볼 수 있습니다.

세부적인 모듈의 역할을 알아볼까요?

  • Domain 모듈
    - 앱의 핵심 비즈니스 로직이 담겨 있습니다. 가장 순수한 형태의 코드를 포함하며, 특정 프레임워크나 라이브러리에 의존하지 않습니다.
  • Data 모듈
    - 앱의 데이터 소스를 추상화하는 모듈입니다. local과 remote 데이터 소스로 이루어져 있으며, 도메인 모듈과 안드로이드 프레임워크 사이를 이어주는 매개체 역할을 합니다. 최종적으로는 도메인 객체로 변환하여 반환합니다.
  • Presentation 모듈
    - 앱의 UI를 구성하는 모듈입니다. 우리가 그려내는 Activity, Fragment 등의 UI 컴포넌트를 포함합니다. UI 이벤트를 처리하고, 도메인 모듈에서 받아오는 데이터를 표시하는 역할을 합니다.
  • DI 모듈
    - 이러한 의존성을 활용하려면 DI가 필요합니다. DI란 Dependency Injection의 약자로, 말 그대로 의존성 주입을 뜻합니다. 의존성에 관해서는 기존 게시글에서 다루었으니 넘어가도록 하겠습니다. 일반적으로 Dagger, Koin, Hilt 등의 DI 프레임워크를 사용하여 구현합니다.

이러한 분리의 단점은 무엇일까요?

서비스에서 Domain 모듈에 변화가 생긴다면 결국 Presentation 모듈에서도 변화가 생길 것이고, 이러한 변화는 새로운 컴파일을 요구합니다. 따라서, 기존에 제시된 빌드시간 단축과 코드의 결합도를 분리한다는 멀티모듈의 장점을 활용할 수 없게 됩니다.

02. 기능별 모듈 분리


그렇게 나온 방식이 기능별로 모듈을 세분화하는 방식입니다.
위 그림을 보면 books, authors, reviews라는 세 가지의 기능으로 분리된 모습을 볼 수 있습니다.

하지만 이렇게 되면 어떤 문제가 생길까요?

중복되는 코드를 다른 모듈에서 활용하는 경우가 생긴다면, books에서 생긴 변화를 authors와 reviews도 활용하게 됩니다. 이러한 코드로 날짜나 문자열 등을 처리해주는 로직, 사용자 인증 등을 관리하는 로직, 에러를 처리해주는 로직 등이 있을 수 있습니다.

계층별로 나누어져 있을 때는 중복되는 코드가 있다면 해당 코드가 있어야 할 계층에 위치시켜서 재활용할 수 있었습니다.

하지만 기능별로 분리했을 때 위와 같은 의존성이 생긴다면, 이 역시 멀티모듈의 결합도를 분리해준다는 장점을 활용할 수 없게 됩니다.

03. 혼합 분리 (계층별 + 기능별)


앞서 나온 문제를 해결할 수 있는 방법은 위에서 나온 계층별, 기능별 분리 방식을 혼합하는 방식입니다. 계층별이나 기능별로 분리하였을 때, 나올 수 있는 단점을 보완하는 방향으로 모듈을 분리합니다. 이렇게 하면 다음과 같은 이점을 얻을 수 있습니다.

  • 각 모듈은 각자의 역할에 전문적이며 독립적이기 때문에 코드 응집도를 높일 수 있습니다.
  • 각 모듈의 결합도가 느슨해져 코드 수정이 생길 경우에 좀 더 용이하게 수정이 가능합니다.
  • 모듈이 더 작은 덩어리로 세분화되어 쉽게 활용이 가능합니다.

하지만 이러한 방식은 구조의 복잡성이 증가해 개발자가 전체적인 구조를 파악하는데 오랜 시간이 걸릴 수 있습니다. 이로 인해 의존성을 잘못 관리한다면, 오히려 유지보수가 어려워지는 문제를 낳을 수 있습니다.

그렇다면 우리는 어떻게 해야 할까?

사실 따지고 보면 정답은 없습니다. 크고 복잡한 프로젝트의 경우, 기능별로 모듈을 분리하면 모듈 간의 의존성이 복잡해질 수 있습니다. 각 기능이 서로 다른 모듈과 상호 작용하는 경우에는 이러한 의존성 관리가 어려워질 수 있습니다.

전자상거래 서비스를 기능별 모듈로 분리한다면, 다음과 같은 상호 작용이 발생할 수 있습니다.

  • 사용자 모듈 <-> 상품 모듈 : 상품의 찜이나 리뷰
  • 상품 모듈 <-> 주문 모듈 : 상품의 재고 관리
  • 주문 모듈 <-> 결제 모듈 : 상품의 주문 및 결제

위와 같은 의존성 속에서 더 복잡한 연결이 요구될 수 있습니다.

반면에 계층별로 모듈을 분리하면 이러한 의존성을 더 잘 관리할 수 있습니다.

예를 들어, presentation 계층, domain 계층, data 계층과 같이 계층별로 모듈을 분리하면 각 계층 간의 역할이 명확해집니다. 각 계층은 특정 역할에 집중하고, 다른 계층과의 인터페이스를 통해 상호 작용합니다. 이렇게 하면 모듈 간의 의존성을 줄이고, 각 모듈의 역할이 명확하게 분리됩니다. 또한, 각 계층을 독립적으로 개발하고 테스트할 수 있으므로 개발 및 유지 보수가 용이해집니다.

위와 같은 이유로 크고 복잡한 프로젝트에서는 계층별 모듈 분리가 관리와 유지보수를 용이하게 할 수 있습니다. 반면, 작은 프로젝트에서는 기능별 모듈 분리가 더 효율적일 수 있습니다.

팀 멤버들이 어느 구조를 선호하는지, 추후 유지보수나 확장성 측면에서 어떻게 분리하는 것이 효율적인지 등을 고려해 앞서 나온 장단점에 따라 선택하면 좋을 것 같습니다.

사실 직접 해보면서 시행착오를 통해 적합한 구조를 찾아가는게 가장 바람직하다고 봅니다~~ 멀티모듈을 사용하는 방법론적인 부분이나, 클린 아키텍처 부분에서는 좀 더 세부적인 설명이 있으면 좋을 것 같은데🤔 추후 다른 글에서 다뤄보도록 하겠습니다 🫡

profile
Junior Android Developer

0개의 댓글