Clean Architecture
클린 아키텍처 사용 이유와 개념을 알고 실제로 프로젝트를 구축할 수 있다.
Clean Architecture
1. 클린 아키텍처란 ?
계층을 크게 나누어 관심사를 분리하고 분리된 클래스가 한가지 역할만 할 수 있도록 구현하는 방식이다. 외부에서 내부로 의존성을 가지는 계층 구조이다. (내부로 갈 수록 의존성이 낮아짐) → 어떤 동작을 할 때 기준보다 내부에 있는 계층이 변화하면 동작을 행하는 외부계층에도 영향을 줄 수 있다. (의존성이 있다.) 하지만 기준의 외부에 있는 계층이 변화하는 것 때문에 동작을 행하는 내부계층에 영향을 주면 안된다. (의존성이 없다.)
1-1. 엔티티 (Entities)
- 엔티티는 핵심 업무 규칙을 캡슐화한다. (→ 비즈니스 규칙이 무엇인지 추가 조사 !!)
- 메소드를 가지는 객체이거나 데이터 구조와 함수의 집합이다.
- 외부가 변경 되더라도 수정될 가능성이 매우 적다.
- 순수한 비즈니스 로직(자바 or 코틀린으로만 작성된 비즈니스 로직)만 담당한다. → 순수한 비즈니스 로직이 아닐 경우 유닛 테스트가 어렵다.
1-2. 유즈 케이스 (Use cases : 개별 기능, 비즈니스 논리 단위 : 하나의 행동만 담당한다.)
- 애플리케이션의 고유 규칙을 캡슐화한다.
- 엔티티로 들어오고 나가는 데이터 흐름을 조정하고 조직한다.
- 유스케이스 계층이 변경이 엔티티에 영향을 주면 안된다.
- 데이터베이스, 공통 프레임워크, UI에 대한 변경과 관련이 없어야한다.
- Model, Repository, Executor 등이 속한다.
1-3. 인터페이스 어댑터 (Interface Adapters : Presenters)
- 엔티티나 유스케이스로 받은 데이터를 받아 필요한 형식으로 변경한다. → DB 및 HTTP 요청, 혹은 UI 업데이트에 적용할 수 있는 형태로 변환
- 순수한 비즈니스 로직을 담당하는 역할이다.
- 비즈니스 로직과 프레임워크 코드가 잘 녹아 들게 하는 역할이다.
- ViewModel(MVVM), Presenter(MVP), View(MVVM, MVP), Controller(MVC) 등이 속한다.
1-4. 프레임 워크 & 드라이버 (Frameworks & Drivers : Web, DB)
- 웹 프레임 워크, 데이터 베이스, UI, HTTP 클라이언트 등으로 구성된 계층이다.
- UI(Activity, Fragment), Retrofit 같은 네트워킹 관려 프레임워크이다. → 실제로 개발자가 해야할 일은 거의 없다.
2. Android에서 Clean Architecture란 ?
Presentation, Data, Domain 3개의 계층으로 나누어진다. Presentation → Domain, Data → Domain 방향으로 의존성을 가진다.
2-1. Presentation
- 화면과 입력에 대한 처리 등 UI와 관련된 부분을 담당한다. Activity, Fragment, View, ViewModel을 포함한다.
- Domain 계층에 대한 의존성을 가지고 있다.
2-2. Domain
- 애플리케이션의 비즈니스 로직을 가지고 있다.
- 비즈니스 로직(UseCase)에서 필요한 Model을 포함하고 있다.
- Presentation, Data 계층에 대한 의존성을 가지지 않는다.
- 안드로이드의 의존성을 갖지 않고 순수한 비즈니스 로직으로 구성한다.
도메인에서 안드로이드 의존성을 갖지 않는다는 의미란 ?
안드로이드 의존성은 안드로이드 시스템과 밀접한 객체, 클래스(안드로이드 프레임워크에 속한 클래스나 API)를 의미한다. 도메인 레이어는 순수 비즈니스 로직으로 구성되기 때문에 안드로이드 환경이 아니라도 문제 없이 동작이 가능하게 구성 되어야한다는 뜻이다.
안드로이드 의존성 예시
- Context
Context는 안드로이드 환경에서 UI, 리소스, 시스템 서비스 접근 등을 위해 사용되는 객체이다. context는 안드로이드에 의존성이 강하기 때문에 domain에서 사용하면 안된다. SharedPreferences, getSystemService(), getResources() 등
- View (Activity, Fragment)
안드로이드에서 화면을 구성하는데 사용되는 UI 관련 클래스는 안드로이드 시스템에 의존적이다.
- 안드로이드 SDK 라이브러리
LiveData, Handler, Looper, Parcel, Intent 같이 안드로이드 환경에서만 동작하는 것을 이야기한다.
2-3. Data
- Domain 계층에 의존성을 가지고 있다.
- Repository 구현체를 포함한다.
- 데이터베이스, 서버와의 통신이 이루어지는 계층이다.
- Mapper 클래스를 통해 Data 계층 모델을 Domain 계층 모델로 변환해주는 역할도 한다.
3. Domain, Data 각 계층 Model 차이점
두 계층에서 사용하는 데이터의 모델은 서로 같을 수 있다. 하지만 도메인 계층은 데이터 계층에 의존성을 가질 수 없기 때문에 데이터 통신이나, 디비에 필요로하는 데이터 클래스에 직접적으로 접근이 불가능하다. 이런 문제를 해결하기 위해 도메인과 데이터 계층은 각각 데이터 모델을 가지게 되고 데이터 계층의 Mapper를 통해 도메인 계층에서 사용이 가능한 데이터 모델로 변경 과정을 거치게 된다.
두 계층에서 사용하는 Data Model은 서로 동일할 수 있지만 다를 수도 있다. 도메인 데이터 모델은 Presentation 계층에서도 사용하기 때문에 모든 데이터를 Domain Model로 만들기 보다는 실제로 필요로한 값만 가지고 사용할 수 있도록한다.
- Data 계층 Model은 DB(Local), API를 통해 Data를 저장, CRUD, Mapper를 통해 필요한 데이터를 도메인 계층의 모델로 넘긴다.
- Domain 계층 Model은 실제로 사용하는 데이터 클래스라고 할수 있다.
4. UI 전용 데이터 모델이 필요하다면 ?
만일 UI에서만 사용되는 모델이 필요하다면 presentation 계층에 생성하는게 적절하다.
- UI에서만 사용되는 데이터가 다른 계층에 존재하게 된다면 불필요한 의존성이 생기게 된다.
- domain에서 제공하는 모델을 그대로 사용하지 않고 UI에 맞게 데이터를 가공할 수 있어 유연성이 좋다.
- UI 전용 데이터 모델은 UI 로직과 깊은 연관성이 있기 때문에 데스트와 유지보수가 더 용이해진다.
단, ViewModel에서 UI로 전달할 데이터가 domain 계층 모델과 다를때만 생성해야하고 Fragment, Activity, ViewModel에서만 사용되어야하며 다른 계층과 상호 작용하지 않아야한다.
5. UseCase란 ?
- Domain layer에서 사용된다.
- 사용자가 서비스에서 수행하고자 하는 것들이다.
- 게시글을 ‘검색’한다.
- ‘댓글’을 남긴다.
- ‘공유’ 버튼을 누른다.
5-1. UseCase를 사용하는 이유는 ?
- ViewModel이 어떤것을 하고자 하는지 직관적으로 파악이 가능하다.
- ViewModel(presentation layer)은 UseCase(Domain)을 의존한다.
- UseCase는 한가지의 기능만 가지기 때문에 직관정인 명칭을 가진다.
- ViewModel에서 파라미터로 전달받은 UseCase를 보고 어떤일을 하는지 알수 있다.
- 의존성을 줄일 수 있다.
- UseCase가 없다면 Respository를 주입받게 된다.
- Respositroy를 수정하게 된다면 해당 Repositroy를 사용하는 모든 로직에서 수정이 필요할 수도 있다.
- Repository ➡️ UseCase ➡️ ViewModel
- useCase를 수정하면 Repository를 수정할 필요가 없어 변경을 최소화 할 수 있다.
- UseCase가 없다면 Respository를 주입받게 된다.
5-2.하나의 ViewModel에서 많은 UseCase를 호출한다면 ?
UseCase가 많아지고 공통적으로 사용하는 부분이 많아질 경우 UseCase를 하나로 합치는 UseCase를 만들어 사용할 수 있다. 직관적인 명칭으로 UseCase를 선언하고 그 안에 합치고 싶은 UseCase들을 전달 받아서 사용하면 된다.
6. 모듈별 gradle 코틀린 컴파일 차이
// 1번
plugins {
id ("org.jetbrains.kotlin.jvm")
}
// 2번
plugins {
alias(libs.plugins.kotlin.android)
}
둘 다 동일하게 JVM 위에서 동작하는 코틀린 컴파일이지만 1번은 표준 JVM 코틀린 컴파일이고 2번은 안드로이드 친화된 코틀린 컴파일이다. domain 모듈은 안드로이드에 종속되지 않기 때문에 가능한 1번 방법으로 컴파일하는 방법을 지향한다.
Difference between Kotlin plugins
What are the differences between these three Kotlin plugins and what do they actually do? plugins { id 'kotlin-android' id 'org.jetbrains.kotlin.android' id "org.jetbrains.kotlin.jvm&
stackoverflow.com