본문 바로가기

Android/Tech

안드로이드와 Clean Architecture

Clean Architecture on Android

안드로이드에서의 클린 아키텍쳐는 어떤 모습일까요?

현재 DND 8기로 활동하면서 진행 중인 프로젝트에 클린 아키텍쳐를 적용했습니다.

Presentater-Domain-Data 로 이루어진 Three Layers 방식을 도입하여 개발하고 있습니다.

 

이번 포스트에서는 Android 프로젝트에 클린 아키텍쳐를 적용하는 방식 및 그 효과를 알아가고자 합니다.

 


 

클린 아키텍쳐를 도입하는 이유 중 가장 중요한 것은 관심사 분리입니다. 안드로이드 프로젝트에 클린 아키텍쳐를 적용해보거나 공부해 보신 분들은 아시겠지만, 각 레이어가 별도의 모듈로 존재하고, 각 모듈은 꼭 필요한 모듈에만 의존하도록 구현됩니다. (별도의 모듈화가 진행되지 않는 경우도 있습니다)

 

각 레이어는 특정화된 모델을 통해 데이터를 패싱하고 활용합니다. 이를 통해 레이어 간 결합도를 확실하게 끊어 낼 수 있습니다. 각 모듈은 거의 독립적으로 존재하게 되고, 이식성이 증대되어 다른 앱에도 손 쉽게 모듈을 적용할 수 있습니다.

레이어

각각의 레이어는 다음과 같은 역할을 가집니다.

  • Presentater - UI 를 그려내는 역할 및 UI 로 입력된 이벤트 핸들링
  • Domain - 서비스에 필요한 필수 로직
  • Data - 앱에 필요한 데이터를 가져오고 저장하는 역할

 

프레젠테이션 레이어는 UI 를 그려냅니다. 즉, Activity 나 Fragment 가 포함되어야 합니다. Presentater 엔 ViewModel 이 포함되는데, MVVM 에서의 ViewModel 과 역할이 같습니다. 다만, 이벤트에 대한 직접적인 핸들링 권한을 갖게 됩니다.

 

클린 아키텍쳐의 레이어들 중 가장 깊이가 깊은 것은 도메인 레이어입니다. 도메인 레이어는 어느 모듈에도 의존하지 않습니다. 서비스에서 가장 중요한 핵심 로직을 갖고 있으므로, 유즈케이스도 도메인 레이어에 포함됩니다. 또한, 유즈케이스는 기능이나 상황에 알맞는 데이터를 요청할 수 있어야 하기 때문에 레포지토리 인터페이스도 역시 이에 포함됩니다.

 

데이터 레이어는 레포지토리 구현체 및 데이터 소스가 포함됩니다. 레포지토리 구현체는 도메인 레이어의 레포지토리 인터페이스를 구현하며, 데이터 소스에 대한 접근 권한을 가집니다.

 


Flow

클린 아키텍쳐를 적용한 앱에서 UI 상호작용을 통해 특정 정보를 요청하면, 다음과 같은 순서로 요청이 수행됩니다. 데이터는 그 반대로 흐르고요.

 

 

  1. 유저의 입력을 받은 Activity / Fragment / Composable 에서 참조 중인 ViewModel 에 특정 데이터를 요청합니다.
  2. 의존하고 있는 유즈케이스를 호출하여 데이터를 요청합니다.
  3. 요청을 받은 유즈케이스는 레포지토리를 통해 레포지토리 구현체에 데이터를 요청합니다.
  4. 레포지토리 구현체는 데이터 소스에서 적합한 데이터를 가져옵니다.
  5. 레포지토리 구현체는 이를 도메인 레이어에 알맞는 모델로 변환, 유즈케이스로 반환합니다.
  6. 유즈케이스는 받아온 데이터를 프레젠테이션 레이어에 알맞는 모델로 변환, ViewModel 로 반환합니다.
  7. ViewModel 은 반환받은 데이터를 UI 로 전달합니다.

 

위와 같은 과정을 거쳐 데이터를 요청 및 반환받는데, 구현해야 할 것이 수없이 많아 러닝 커브가 상당합니다. '꼭 이렇게 까지 해야 하나?' 싶은 생각도 들지만, 소프트웨어의 수명 자체가 길어져서 개발 및 유지보수 기간이 확장될 수록, 분리가 철저한 아키텍쳐의 효험을 경험할 수 있습니다.

 


 

제가 처음 클린 아키텍쳐를 경험하고 적용하면서 궁금했던 것들은 다음과 같습니다.

 

Q. 왜 데이터를 레이어마다 모델로 변환해야 하는가?

A. 각 레이어끼리 의존 사항이 일치하는 경우는 없습니다. (프레젠테이션 레이어는 도메인 레이어의 의존성을 갖지만 그 반대는 아닙니다. 데이터 레이어는 도메인 레이어의 의존성을 갖지만 도메인 레이어는 그 어떠한 의존성도 갖지 않습니다.) 각 계층간 데이터 전달을 위해서는 서로의 의존성을 가져야 하는데, 그렇지 않으므로 별도의 모델을 구현하지 않으면 데이터를 전달할 수 없습니다.

 

간단한 예로, 데이터 레이어에서 특정 값을 도메인 레이어로 반환할 때, 도메인 레이어에서 데이터 레이어의 모델을 기반으로 데이터를 받아 올 수 없습니다. 도메인 레이어는 데이터 레이어에 대한 의존성을 갖고 있지 않기 때문입니다. 반대로 데이터 레이어는 도메인 레이어의 의존성을 갖고 있기 때문에, 데이터 레이어에서 도메인 레이어의 모델에 맞춰 데이터를 변환하여 전달하는 것입니다.

 

Q. DI 는 왜 프레젠테이션 레이어에 존재하는가?

A. 프레젠테이션 레이어는 도메인 레이어와 데이터 레이어의 의존성을 모두 갖고 있습니다. DI 를 수행하여야 하는 클래스는 전체 레이어에 분포되어 있기 때문에, 두 의존성을 모두 갖는 프레젠테이션 레이어에서 DI 를 관장해야하는 것입니다.

또한, 도메인 레이어나 데이터 레이어의 경우, 특히 모듈화를 진행하여야 하는 경항이 강한데, 그 이유는 충분히 다른 프로젝트에 이식될 수 있기 때문입니다. 최소한의 조건(데이터 레이어의 경우입니다. 라이브러리의 종류 등을 의미합니다.) 만 충족이 되면 얼마든지 다른 프로젝트에 적용되어, 독립된 모듈로서의 역할을 수행할 수 있습니다. 그러므로, 이들은 언제든 프로젝트에서 분리가 가능하여야 하며, 이를 위해 필요한 객체를 주입해주는 DI 는 프레젠테이션 레이어에 존재하여야 하는 것입니다.

 

Q. 레포지토리 인터페이스가 꼭 필요한가? 중요한 것은 레포지토리 구현체이니, 그것만 있으면 되는 것 아닌가?

A. 그 해답은 첫번째 의문의 그 것과 비슷한 맥락인데, 도메인 레이어는 데이터 레이어에 의존하지 않기 때문에, 도메인 레이어에서 데이터 레이어에 접근하여 특정한 값을 가져오도록 명령할 수 없습니다. 다만, 데이터 레이어는 도메인 레이어에 의존하기 때문에, 데이터 패싱을 위해 도메인 레이어에 선언한 인터페이스를 바탕으로 데이터 레이어에 레포지토리 구현체를 생성, 이를 활용하는 것입니다.

 


 

워낙 유명한 아키텍쳐라 언젠가 한 번 쯤은 꼭 적용해보고 싶었는데, 이번 DND 8기 활동으로 좋은 동료들을 만나 이를 경험할 기회가 생겨 매우 즐겁게 개발하고 있습니다.

혹자는 클린 아키텍쳐에 대해 의문이나 반감을 갖곤 하는데, 적자생존이라고, 오랜 기간동안 수많은 개발자에게 사랑을 받는 데에는 모름지기 다 이유가 있는 것 같습니다.

 

'Android > Tech' 카테고리의 다른 글

코루틴과 그린 스레드  (0) 2023.03.09
[Jetpack Compose] Glide 와 Coil, 무엇을 사용하면 좋을까.  (2) 2023.03.07
JVM 의 Garbage Collector  (0) 2023.02.01
Jetpack Compose 의 remember  (0) 2023.01.19
Serializable, Parcelable  (0) 2023.01.12