본편에서는 멀티 모듈 프로젝트를 직접 구성해보도록 하겠습니다.
기준 코드는 다음과 같습니다.
저번 편에서 설명드린 것 처럼 전 4가지 관점을 주로 적용하여 멀티 모듈 프로젝트를 구성하고 있습니다.
기능은 저는 주로 탭을 기준으로 구분하고 있으며, 이번편에서도 탭을 기준으로 구분하고자 합니다.
만약 제가 카카오톡 개발자라면 친구 관리 모듈, 채팅 모듈 등으로 멀티 모듈을 구성 했을 것 같습니다.
계층은 이미 클린 아키텍쳐가 도입 되어 있어서 이번편에서는 넘어가고자 합니다.
UI 관련 여부는 앱에서 공통으로 사용되는 컴포넌트 및 ui 기능(navigation)들을 UI 모듈들에서도 똑같이 적용하고자할때 사용합니다.
테스트 가능성은 기능 관점에서 멀티 모듈 프로젝트를 구성하면서 같이 적용해볼 예정입니다.
멀티 모듈 프로젝트 구성 소개
현 프로젝트에서는 홈과 저장소 2개의 탭으로 구성되어 있습니다.
본편에서는 기존 프로젝트에서는 presentaion 내에 homeTab 과 storageTab, baseUiKit 4가지 모듈을 추가하고자 합니다.
homeTab 과 storageTab 은 메인 서비스를 관리하는 모듈이며, baseUiKit 은 공용 컴포넌트 및 네비게이션, 캘린더, 그래프 등 공통 기능들을 관리하는 모듈입니다.
구조는 다음과 같습니다.
제약 조건은 다음과 같습니다.
모듈 생성하기
모듈 생성 방법은 다음과 같습니다.
presentaion 모듈에서 우클릭을 하고 New -> Module 을 클릭합니다.
그 다음 Android Library 를 선택하고 baseUiKit, homeTab, storageTab 를 생성합니다.
생성이 완료되면 다음과 같습니다.
의존 관계 설정하기
presentaion
...
dependencies {
implementation(project(mapOf("path" to ":presentation:baseUiKit")))
implementation(project(mapOf("path" to ":presentation:homeTab")))
implementation(project(mapOf("path" to ":presentation:storageTab")))
...
}
...
추가된 baseUiKit, homeTab, storageTab 을 각각 추가해주고, 불필요한 의존성을 제거합니다.
baseUiKit
...
dependencies {
api(project(":domain"))
api(project(":data"))
// ktx
api(SdDependency.Ktx.core)
api(SdDependency.Ktx.lifecycleRuntime)
api(SdDependency.Compose.activity)
api(platform(SdDependency.Compose.bom)) // compose
api(SdDependency.Compose.ui)
api(SdDependency.Compose.graphics)
api(SdDependency.Compose.preview)
api(SdDependency.Compose.material3)
api(SdDependency.Navigation.compose) // navigation
api(SdDependency.Navigation.hilt)
api(SdDependency.Compose.constraint)
api(SdDependency.Navigation.animation)
api(SdDependency.coil) // coil
// Hilt
implementation(SdDependency.Hilt.android)
kapt(SdDependency.Hilt.androidCompiler)
// tdd
testImplementation(SdTestDependency.Tdd.junit5)
testRuntimeOnly(SdTestDependency.Tdd.junit5Engine)
testImplementation(SdTestDependency.Tdd.junit5Params)
testRuntimeOnly(SdTestDependency.Tdd.junit5ParamsEngine)
testImplementation(SdTestDependency.Tdd.mockk)
testImplementation(SdTestDependency.Tdd.coroutines)
// bdd1
androidTestImplementation(SdTestDependency.Bdd.junit)
androidTestImplementation(platform(SdTestDependency.Bdd.composeBom))
androidTestImplementation(SdTestDependency.Bdd.composeJunit)
// bdd2
debugImplementation(SdTestDependency.Bdd.debugComposeTooling)
debugImplementation(SdTestDependency.Bdd.debugComposeManifest)
}
...
presentaion 에서 공통으로 사용될 의존성을 이전합니다.
homeTab 및 storageTab
...
dependencies {
implementation(project(mapOf("path" to ":presentation:baseUiKit")))
// Hilt
implementation(SdDependency.Hilt.android)
kapt(SdDependency.Hilt.androidCompiler)
// tdd
testImplementation(SdTestDependency.Tdd.junit5)
testRuntimeOnly(SdTestDependency.Tdd.junit5Engine)
testImplementation(SdTestDependency.Tdd.junit5Params)
testRuntimeOnly(SdTestDependency.Tdd.junit5ParamsEngine)
testImplementation(SdTestDependency.Tdd.mockk)
testImplementation(SdTestDependency.Tdd.coroutines)
// bdd1
androidTestImplementation(SdTestDependency.Bdd.junit)
androidTestImplementation(platform(SdTestDependency.Bdd.composeBom))
androidTestImplementation(SdTestDependency.Bdd.composeJunit)
// bdd2
debugImplementation(SdTestDependency.Bdd.debugComposeTooling)
debugImplementation(SdTestDependency.Bdd.debugComposeManifest)
}
...
baseUiKit 을 비롯하여 테스트 라이브러리까지 추가해주었습니다.
소스코드 이전하기
presentaion 은 root 경로로 NavGraph.kt, MainActivity, SdApplication 3 파일만 있으면 됩니다. 하지만 지금은 불필요한 모듈 추가를 지양하고자 main 과 splash 는 남겨두었습니다. 추후 회원가입 이나 소개 페이지 등이 추가되면서 점점 비대해진다면 그땐 별도 모듈로 분리할 예정입니다.
baseUiKit 에는 presentaion 에 있던 base 파일을 비롯하여 navigation 과 같이 ui 구성에 공통적으로 사용될 파일들을 이전시켜두었습니다.
homeTab 에는 presentaion 에 있던 홈 관련 page 및 screen 들을 이전해두었습니다.
마지막으로 storageTab 에도 homeTab 과 같이 저장소 관련 page 및 screen 들을 이전해두었습니다.
마치며
위 이미지는 저장소 탭에서 홈 탭의 페이지를 불러오려고 하는 상황입니다.
의존 관계가 설정되어 있지 않으니 당연히 호출이 불가능한 상황입니다. 개발자들 간 제약 사항을 아무리 잘 맺는다고 하더라도 이렇게 물리적으로 분리가 되어있어야 더 안정적으로 개발에 임할 수 있다고 생각합니다.
본편에서의 작업은 프로젝트 크기가 워낙에 작고 초기 인 점을 감안했을때 큰 공수없이 작업을 마무리 할 수 있었지만, 실제로 운영중인 서비스를 멀티 모듈 프로젝트로 마이그레이션 하는 작업은 생각보다 훨씬 어렵고 복잡한 작업이 될 수 있다고 생각합니다.
mvp 로 빠르게 시장 검증을 할때부터 클린 아키텍쳐나 멀티모듈 등을 모두 도입하기는 매우 어려울 것이라고 생각합니다.
다만 지금은 적용 못하지만 추후 적용 시에 어떠한 구조로 발전 시킬 수 있을지 지속적으로 탐구하는 과정이 동반되어야 적용 시점이 되었을때 만족스러운 결과를 얻을 수 있지 않을까 싶습니다.
멀티 모듈을 적용한 전체 소스코드입니다.
감사합니다.
나만의 안드로이드 앱 만들기(고급자 편) - 멀티 모듈 프로젝트란? (2) | 2023.12.26 |
---|