핵심
- 소프트웨어를 고수준과 저수준으로 경계 짓고, 의존성 단방향 원칙을 따르는 아키텍처
- 자주 변경되는 것(저)과 변경되지 않는 것(고)의 경계를 나눠 분리시키자는 것
- 핵심: 계층 분리(layering) 를 통한 관심사 분리
- presentation, domain, data layer로 나눔
특징
- 소스 코드 의존성은 반드시 안쪽으로, 고수준의 정책을 향해야 한다: 의존성 단방향 원칙
- 내부: 고수준, 추상화되어 변경이 잘 안됨
- 외부: 저수준, 구체화되어 변경이 잘 됨
- 외부는 내부를 의존, 내부는 외부의 존재를 모른다.
- 내부는 외부에 영향을 주지 않음
- 경계를 넘을 때는 추상화된 고수준의 인터페이스를 통한, 의존성 역전과 주입을 적용
- 저수준의 구현에 의존하던 것을 인터페이스에 의존하게 변경 (저->고)
- 소스 코드의 의존성(저→고) 과 제어 흐름(고→저) 을 반대(역전)로 됨
구글 권장 아키텍처와 차이
구글 권장 아키텍처에서 domain layer이 옵셔널
구글 권장 아키텍처는 domain -> data layer를 참조함 (알고 있음)
- domain layer가 프레임워크나 라이브러리에 종속될 수 있음
서비스가 커지고 비즈니스 로직이 늘어날 수록 ViewModel이 비대해지고,
반복되는 비즈니스 로직들도 생겨났다. Domain layer 를 도입하여 관심사 분리가 필요
domain layer는 자체가 어떠한 언어로든 프레임워크나 라이브러리에 종속되지 않아(순수 kotlin) 테스트, 모듈화가 용이
왜 쓰냐?
- 모바일 환경에서 사용자가 다양한 앱을 시도때도 없이 바꾸기도 하고 전화나 알림 등의 작업도 동시에 하기 때문에
- 앱에서 사용자 흐름이 중단되지 않고 연속적으로 흘러가도록 처리해야 함
- App 컴포넌트 에 앱 데이터나 상태를 저장해서는 안되며, 앱 구성요소가 서로 종속되도록 개발해선 안됨
- 단위 테스트 하기 매우 어려워짐
- 생명주기에 의해, 메모리 릭이 발생 할 수도 있음
우리의 경우 멀티 모듈을 도입 -> 클린 아키텍처가 멀티 모듈에는 적합하다 생각
여러 모듈들을 조립하여 다른 앱 개발에 활용: 확장성 UP
수정된 모듈만 빌드, 시간 단축: 생산성 UP
- 모듈화를 통해 클린 아키텍쳐의 계층을 분리하고, 모듈들 간에 알아야 하는 대상과 몰라야 하는 대상의 제약이 강제됨: 휴먼 에러 제거
app 모듈: app 의 진입점이다.
feature 모듈 ( = presentation layer)
- 독립적인 기능을 분리하였다. (home, playlist, search, my, player 등등)
core 모듈
- 다른 모듈에서 자주 사용 하는 공통 모듈이다.
ui ( = presentation layer) : 다양한 기능에서 공통적으로 사용하는 UI를 포함하여 UI의 일관성을 유지하는데 도움을 준다.
domain ( = domain layer) : 앱의 비즈니스 로직을 캡슐화 한다. domain 모듈은 안드로이드의 의존성이 없는 순수 Java/Kotlin 코드로만 구성한다.
data ( = data layer) : data를 CRUD 한다.
장점
도메인 단위 혹은 viewmodel 의 단위 테스트가 쉽게 가능
유저의 동작으로 시작해서 화면에 보여지는 뷰의 데이터들의 흐름에 대해 파악하기 쉬워짐
- UI(View) → VM(프레젠터) → Usecase → Repository → Datasource
신규 개발자들도 파일 이름이나 클래스 명으로 어떤 기능을 해야 하고, 하고 있는지 알기 쉬워짐
domain과 data간의 분리가 이루어져 있기 때문에, 데이터 소스를 변경해도 domain 모듈에는 영향이 없기 때문에 비즈니스 로직은 피해없이 안전
모듈간의 결합도가 낮아짐 (서로 영향을 덜 줌)
단점
- 많은 파일들이 생겨남
- 단순 포워딩을 위한 Usecase가 생겨남
- 과도하게 집착하면, layering을 위한 수단으로 코드를 짜게 됨 (주객전도)
구성 요소
- Entitiy : 핵심 비지니스 규칙을 캡슐화
- Use Case : 비즈니스 로직을 정의
- Interface Adapter : 어댑터들로 구성, Controller, Presenter, Gateway 가 속함. 인터페이스 역할
- Framwork & Drivers : 시스템의 핵심 업무와는 관련 없는 세부 사항.
layer
Presentation
- 뷰(View): 직접적으로 플랫폼 의존적인 구현, 즉 UI 화면 표시와 사용자 입력을 담당합니다.단순하게 프레젠터가 명령하는 일만 수행합니다.
- 프레젠터(Presenter): MVVM의 ViewModel과 같이, 사용자 입력이 왔을 때 어떤 반응을 해야 하는지에 대한 판단을 하는 영역입니다. 무엇을 그려야 할지도 알고 있는 영역입니다.
Domain
유즈 케이스(Use Case): 비즈니스 로직이 들어 있는 영역입니다.
모델(Entity): 앱의 실질적인 데이터가 정의
Data
리포지터리(Repository): 유즈 케이스가 필요로 하는 데이터의 저장 및 수정 등의 기능을 제공하는 영역으로,
- 데이터 소스를 인터페이스로 참조하여, 로컬 DB와 네트워크 통신을 자유롭게 할 수 있습니다.
데이터 소스(Data Source): 실제 데이터의 입출력이 여기서 실행됩니다.