Modularization
지방 소기업에 재직했던 저는, 개발을 시작하고 1년 이상 지나서야 모듈화(Modularization) 에 대해 알게 되었습니다. 사실 모듈화는 제 퇴직 사유(?) 이기도 했는데, 쏟아지는 수주를 받아내기 위해서는 모듈화가 필수였으나, 제대로 적용되고 있지 않았기 때문입니다. 그 시절의 저를 떠올리면서 오늘은 모듈화에 대해 정리하고자 합니다.
모듈화의 장, 단점
모듈화에는 수많은 장점이 있는데요. 보통 다음과 같습니다.
- 유지보수 용이
- 각 모듈이 독립적으로 작동하므로, 특정 기능에 문제가 발생했을 때 해당 모듈만 수정하면 됩니다.
- 재사용성
- 모듈은 특정 기능을 수행하므로, 다른 프로젝트나 시스템에서도 이를 재사용할 수 있습니다.
- 가독성
- 각 모듈이 특정 기능을 수행하기 때문에, 임의의 기능에 대한 이해가 필요할 때 해당 모듈만 살펴보면 됩니다.
- 병렬 개발
- 여러 개발자가 동시에 각기 다른 모듈을 개발할 수 있으므로, 개발 시간을 단축할 수 있겠습니다.
- 테스트 용이
- 모듈 내에 문제가 있는 경우, 해당 모듈에 대한 별도의 테스트가 가능합니다.
- 빌드 소요 시간 감소
장점이 있으면 당연히 단점도 있겠습니다. 단점은 다음과 같습니다.
- 설계 복잡성
- 모듈 간 상호 작용과 인터페이스를 올바르게 설계해야하므로, 초기 설계 단계가 복잡해집니다.
- 성능 저하
- 모듈 간 상호 작용이 많아지면, 이로 인한 추가적 처리가 요구되므로, 성능 저하가 발생할 수 있습니다.
- 통합 문제
- 개별 모듈에 대한 개발과 테스트가 완료되어도, 이 모듈들을 통합하였을 때 문제가 발생할 수 있습니다.
- 오버헤드
- 불필요하게 세분화된 모듈은 관리 비용과 시간, 그리고 자원의 오버헤드를 초래할 수 있습니다. 프로젝트 구조가 복잡해지기 때문에 개발 시에도 이리 저리 헤맬 수 있습니다.
- 의존성 문제
- 잘못 설계된 경우, 모듈 간 과도한 의존성이 생길 수 있으며, 이는 유지보수와 확장성에 문제를 일으킬 수 있습니다.
- (Android) Gradle 관리에 대한 고려 요구
- 안드로이드 프로젝트에 모듈이 추가되면 해당 모듈에 대한 build.gradle 이 추가되고, 모듈이 과도하게 세분화된 경우 너무나 많은 build.gradle 이 생성되며 프로젝트가 더욱 복잡해집니다.
단점들은 그 영향권이 다양한 것에 반해, 대부분의 장점들은 개발 속도와 관련되어 있음을 확인할 수 있습니다. 납기 준수 및 성공적인 애자일 공법을 위해서는 개발 속도 측면의 개선이 필수적입니다. 즉, 현 시대의 개발자라면 모듈화를 피하는 것이 쉽지 않다고 할 수 있습니다.
안드로이드에서의 모듈화
안드로이드 프로젝트에 Clean Architecture 를 적용하는 것이 평범한 일이 되면서, Data, Domain, Presentation 영역을 구분하고 이를 그대로 모듈화하는 것 역시 우리에게 너무나 익숙한 일이 되었습니다. 아마 가장 많은 안드로이드 개발자들이 채택하고 사용 중인 모듈화 방식이 아닐까 싶은데요. 저 역시도 해당 방식으로 모듈화를 수행하고 있습니다.
보시다시피, 굉장히 단순하고 가볍게 사용할 수 있습니다. 이 구조에서의 모듈은 Clean Architecture 의 각 영역을 의미하며, 각 모듈의 특징은 다음과 같습니다.
Data
Data 모듈은 Domain 모듈에 의존하며, Presentation 모듈에는 의존하지 않습니다. 즉, Domain 모듈만 통한다면 얼마든지 다른 소스에 활용할 수 있습니다. Data 모듈은 말 그대로 데이터를 다루는 모듈이며, 데이터에 대한 CRUD 를 해당 모듈에서 수행합니다. 안드로이드의 경우 Repository-RepositoryImpl(Implementation) 패턴을 사용하는데, RepositoryImpl 이 Data 모듈에 포함됩니다.
대부분의 애플리케이션에서는 Http 통신을 통해 CRUD 를 진행하는데, Http 요청과 응답에 사용하는 폼 역시 해당 모듈에서 선언합니다.
Domain
Domain 모듈은 그 어떤 모듈에도 의존하지 않으므로, 다른 프로젝트에 얼마든 적용할 수 있습니다. 해당 모듈은 프로젝트의 Domain 을 담당하는 역할을 수행하며, Domain 에 상응하는 데이터 명세도 이 모듈에 선언해두면 되겠습니다. 또한 Clean Architecture 의 꽃인 UseCase 가 이 모듈에 포함됩니다. 추가로, Data 모듈의 RepositoryImpl 은 Domain 모듈에 선언한 Repository(Interface)를 상속받는 형식으로 구현하는 것이 보통입니다.
Presentation
Data 모듈과 Domain 모듈은 유저 행태에 따른 데이터 관리(CRUD)를 담당한다면, Presentation 모듈은 애플리케이션의 View 와 Interaction 을 담당합니다. 저는 이 모듈을 프로젝트에서 가장 중요하게 여기는 편입니다. 옛날에 비해 앱의 UI/UX 가 가지는 영향력이 크게 증대되었기 때문입니다. 데이터를 아무리 잘 다루어도 UI 가 별로거나, 끔찍한 UX 를 갖고 있다면 사용하기 불편하고, 이는 곧 애플리케이션의 실패로, 또 프로젝트의 실패로 이어지게 됩니다.
해당 모듈은 애플리케이션의 UI/UX 를 책임지는 모듈이므로, 데이터 CRUD 를 직접 수행하는 코드는 포함되어선 안 됩니다. 조금 더 딥하게 들어가자면, UI 표시를 위한 데이터 편집까지도 Data 모듈에서 수행해주면 최고입니다.
안드로이드의 경우, Activity, Fragment, ViewModel 이 해당 모듈에 속하게 됩니다. UI Animation 역시 해당 모듈 내에 선언해서 사용해주면 되겠습니다. Jetpack Compose 를 사용한다면, @Composable 어노테이션이 붙는 모든 함수도 이 모듈에 선언하면 됩니다.
이 모듈화 방식의 장점은 다음과 같습니다.
- Clean Architecture 를 기반으로 하기 때문에 이해하기 쉽습니다.
- Clean Architecture 를 사용하는 프로젝트가 많기 때문에, 재사용성이 매우 높습니다.
- 학습 곡선이 완만한 편입니다.
다음, 단점입니다.
- 개별 모듈의 사이즈가 과도하게 커질 가능성이 있습니다.
- 가독성이 그렇게 좋지는 않습니다. 특히, 작은 기능을 파악하려고 할 때에는 유독 복잡할 수 있습니다.
또 다른 방법이 있습니다. 이 방법은 Core 와 Feature 를 나누어 구현하는 방식입니다.
UI/UX, DI 등을 위한 app 모듈은 그대로 두고, 데이터 통신 등을 관할하는 Core 모듈과, 각 기능을 담당하는 Feature 모듈을 별도로 생성합니다. 두 모듈 내에 추가적인 모듈을 생성하는 것도 좋습니다. Data 모듈을 추가로 구성하기도 하고요.
Core
Core 모듈에는 Http 통신을 위한 코드가 배치됩니다. 이 외에도 Model 등의 모듈을 추가 구현하여 더욱 세분화할 수 있습니다. 안드로이드 코드가 포함될 수 있지만 UI/UX 와는 관련이 없는 코드들이 해당 모듈에 구현됩니다.
Feature
Feature 모듈에는 모듈명과 같이 각 기능에 해당하는 코드들이 포함됩니다. ViewModel 과 UI 코드들이 배치될 수 있는데, Jetpack Compose 를 사용하면 Composable 함수가 해당 모듈에 선언되기도 합니다.
Core 모듈과 Feature 모듈로 나누는 방식은 Clean-Architecture-Based-Modularization 의 장, 단점과는 조금 차이가 있는데요.
장점의 경우, 다음과 같습니다.
- Feature 모듈을 다른 안드로이드 프로젝트에 이식하기 좋습니다. 즉, 제대로 만들어두면 두고두고 쓰기 좋습니다.
- 이 역시, 학습 곡선이 완만합니다.
- 작은 기능을 파악할 때에 굉장히 가독성이 높습니다.
다음, 단점입니다.
- 개별 모듈의 사이즈는 작으나, 모듈의 양이 많아지기 쉽고, 그렇게 되면 의존성 관리가 복잡해지며, 전체 구조를 가늠하기 어려워집니다.
- Core 모듈에 Retrofit 등의 코드가 생성되기 때문에, 다른 영역의 소스 코드에 이식할 수 없습니다.
두 가지 방식 외에도 Mono-Module 이나 BottomNavigation 의 각 탭을 기준으로 모듈화하는 방식 등, 수 많은 모듈화 방식이 존재합니다. 통상적으로 사용되는 '템플릿' 개념의 모듈화 방식이 존재하긴 하지만, 그렇다고 꼭 그것에 국한될 필요 없이 각자 개발하는 프로젝트의 상황에 따라 유연하게 모듈화하면 좋을 것 같습니다.
즉, 모듈화에 정석적인 방법론이 존재하는 것이 아닌, 각 프로젝트나 팀의 스탠다드를 먼저 수립하고 그에 맞게 모듈화를 수행하면 될 것입니다.
그 어떠한 방법도 '무조건 좋다' 라고 할 수는 없을 것 같습니다. 더 다양한 방법으로 모듈화를 시도해보면서, 내게 맞는, 또는 우리 팀에게 맞는 모듈화 방식을 찾아가는 것이 개발 리소스를 감소시키고 생산성을 증가시키는 방향이 아닐까 생각합니다.
'Android > Tech' 카테고리의 다른 글
Kapt, 그리고 KSP (0) | 2023.09.01 |
---|---|
내부 리소스 접근에 왜 Context 가 필요한 걸까? (0) | 2023.08.21 |
HLS, DASH, 그리고 오디오 포맷 (feat.속도 비교) (0) | 2023.07.07 |
Android Context Details (feat.LocalContext) (0) | 2023.06.28 |
StateMachine 과 Stackless Coroutine (0) | 2023.05.31 |