Multi Module 과 Dagger2

굉장히 오랜만에 안드로이드 기술 블로그를 쓰게 되었습니다.

지난 1년가까이 안드로이드는 큰 변화가 있었는데 그 중에 Android 3.0 과 Android Gradle 3.0 이 나오면서 다중 Module 을 좀 더 적극으로 사용할 수 있도록 구글에서 도입하였습니다.

안드로이드 Module 개발

이러한 모듈 개발 방식을 지원함에 따라 다양한 모듈로 나누어서 앱을 개발 할 수 있는 다양한 시도가 이루어지고 있습니다. 다음과 같은 예시의 모습으로 앱을 개발할 수 있습니다.

위와 같이 수직적으로 계층화 하여 각 모듈을 나누고 각각 의존 관계를 모듈 설정으로 하여 1개의 거대의 소스 덩어리가 아니라 특화된 역할 단위로 나누어 개발 할 수 있습니다.

이런 방식은 서비스가 거대해 질 경우 독립적으로 모듈을 관리할 수 있다는 장점이 있습니다.

하지만 이러한 방식은 수평적인 관계에 있는 모듈 중에 다른 모듈이 의존성을 추가하려고 할 때 문제가 발생합니다. 다음의 그림을 보도록 하겠습니다.

수평적이던 User Repository 와 Content Repository 의 관계가 깨지고 Content Repository 가 User Repository 에 의존성을 가지게 된 것입니다.

이렇게 된 경우 어쩔 수 없이 모듈간 설정을 위해서 의존성이 높은 모듈을 상위로 올리게 됩니다. 문제는 이러한 경우가 누적이 되면 지속적으로 1개의 모듈이 점점 상위로 올라가다가 결국 다음과 같은 모습으로 바뀌게 될 수 있습니다.

물론 최악의 상황을 그린 모습이지만 깨진 창문 하나가 지속적으로 다른 것도 깨진 상태로 유지하게 되고 최종적으로는 이러한 모습이 될 수 있습니다.

Dagger, 해결책로 풀어보자

Dagger 를 이용하여 모듈간의 종속성을 최소화 하고 필요한 기능은 주입 받을 수 있도록 할 수 있습니다.

의존성에 문제가 있었던 모듈에서 추상화된 모듈을 별도로 분리를 하고 기존에 의존성이 필요하던 곳에서는 추상화된 객체를 통해 주입을 받아 구현체 모듈간에는 의존성을 없애고 최소한의 추상화 모듈에 대해서만 의존성을 유지함으로써 수직적 수평적 관계를 유지할 수 있도록 합니다.

예시로 알아보도록 하겠습니다.

before

책 검색 API 를 이용한 앱을 만들었다고 했을 때 각각의 검색 화면은 별개의 모듈로 관리하더라도 이를 관리해주는 화면은 그보다 상위의 모듈에 위치하게 됩니다.

위의 다이어그램은 SearchActivity 가 하위의 2개 검색 화면을 보여주기 위해 Naver, Daum 의 검색 화면을 각각 의존성을 가지고 있습니다.
기존에는 이러한 구조는 의존성을 가진 모듈간에는 피할 수 없는 수직적 구조입니다.

이런 모듈간의 수직적 구조는 모듈 단위로 코드를 작성하고 각각 나눠서 유지보수 형태를 띄는데 많은 걸림돌이 될 수 있습니다.

그래서 이러한 형태를 다음과 같은 구조로 바꿔보았습니다.

after

SearchActivity 를 위한 search module 을 별개로 두고 상세 화면들과 동등한 위치에 있도록 구성합니다. 대신 SearchActivity 에 필요한 Fragment 의 정보를 담을 수 있는 FragmentInfo 를 위한 fragment-info 모듈을 구성하였습니다.

Dagger 를 이용한 데이터 주입

수평적인 구조를 구성하였다면 이제 SearchActivity 에 필요한 데이터를 주입할 수 있도록 구성하여야 합니다.

Dagger 주입 관계 흐름

naver-search 와 daum-search 모듈에서는 기존의 FragmentInfo 에 맞춰서 NaverInfo 와 DaumInfo 를 주입하도록 각각의 Component 에 등록하고해당 Component 는 SearchBinder 라는 모듈에 등록하도록 하여 최종적으로 AppComponent 에 의해 관리되도록 합니다.
search 모듈의 SearchActivity 는 SearchComponent 로부터 AppComponent 에서 관리하던 FragmentInfo 를 주입받게 되어 최종적으로 SearchActivity 는 상세화면은 자세히 알 필요 없이 FragmentInfo 를 통해 NaverFragment 와 DaumFragment 를 받도록 합니다.

무엇을 위한 것인가?

어플리케이션의 기능이 다양해질수록 유지보수 해야하는 코드의 수는 기하급수적으로 늘어나게 됩니다. 따라서 각각을 모듈로 나누어서 독립성을 높이는게 중요합니다. 하지만 코드간의 의존성을 지속적으로 유지한다면 각각의 모듈이 독립성을 유지하기가 어렵습니다. 따라서 의존성을 최대한 추상화된 정보로 나누고 동적 의존성 주입을 통해서 독립성은 높이고 의존성은 낮추는 형태로 변경하는 것입니다.


기존의 Dagger 는 수직적인 구조를 위한 Graph 기반 DI 라고만 생각했으나 최근들이 모듈을 수평적 구조로 변경하면서 이러한 사용방법도 있다는 것과 문제 없이 동작할 수 있다는 것이 큰 감탄을 하였습니다.

예시 코드 : GitHub 을 참조하시면 상세 코드를 확인하실 수 있습니다.