이전 편에서는 클린 아키텍쳐에 대해 간략하게 소개해드렸습니다.
관련 내용 확인이 필요하시다면 아래 링크 참고 부탁드립니다.
이번에는 직접 구현해보는 작업을 진행해보려 합니다.
아키텍쳐는 3계층으로 구분하고, domain-data-presentation 으로 구현합니다.
각 계층들은 모듈 단위로 구성하고 의존 관계를 통해 계층간 관계를 설정하게 됩니다.
클린 아키텍쳐 구성은 다음과 같은 순서로 진행합니다.
아키텍쳐 구성은 프로젝트 생성할때 먼저 설정하는 것이 맞습니다.
그래야 적용하기도 용이하고 소요도 적습니다.
어느정도 개발이 완료된 프로젝트에 클린아키텍쳐 도입이 불가한 것은 아니지만, 소요가 상상 이상으로 커지는 일이 되니 이 점은 충분한 검토가 필요합니다.
저는 기존에 개발된 프로젝트를 이용해서 아키텍쳐를 적용하는 과정으로 진행해보겠습니다.
작업 예정 코드 링크
1. 모듈을 통해 각 계층을 생성합니다.
기존 프로젝트에는 app 및 buildSrc 모듈 만 존재합니다.
data, domain 이라는 모듈을 추가해줍니다.
모듈 추가 방법은 다음과 같습니다.
그리고 기존 app 모듈을 presentation 으로 변경해줍니다.
완료하고 프로젝트 뷰를 보면 다음과 같은 형태가 됩니다.
2. 생성한 모듈 내 구조를 설정합니다.
domain 모듈은 다음과 같습니다.
domain 모듈은 다음과 같습니다.
presentation 모듈은 다음과 같습니다.
3. gradle 을 통해 의존 관계를 설정합니다.
build.gradle.kts (domain)
...
dependencies {
// coroutines
api(SdDependency.Coroutines.core)
api(SdDependency.Coroutines.android)
// Hilt
implementation(SdDependency.Hilt.android)
kapt(SdDependency.Hilt.androidCompiler)
// tdd
testImplementation(SdTestDependency.Tdd.junit5)
testRuntimeOnly(SdTestDependency.Tdd.junit5Engine)
testImplementation(SdTestDependency.Tdd.junit5Params)
testRuntimeOnly(SdTestDependency.Tdd.junit5ParamsEngine)
testImplementation(SdTestDependency.Tdd.mockk)
}
...
domain 에서는 코루틴이나 힐트 같이 비즈니스 로직 구성에 필요한 라이브러리 위주로 구성합니다.
build.gradle.kts (data)
...
dependencies {
implementation(project(":domain"))
// SharedPreferences
implementation(SdDependency.preference)
// gson
implementation(SdDependency.gson)
// hilt
implementation(SdDependency.Hilt.android)
kapt(SdDependency.Hilt.androidCompiler)
// tdd
testImplementation(SdTestDependency.Tdd.junit5)
testRuntimeOnly(SdTestDependency.Tdd.junit5Engine)
testImplementation(SdTestDependency.Tdd.junit5Params)
testRuntimeOnly(SdTestDependency.Tdd.junit5ParamsEngine)
testImplementation(SdTestDependency.Tdd.mockk)
}
...
data 는 domain 의 value object 와 repository 등을 알아야하기에 의존 관계를 연결해주고, 데이터 처리 관련 라이브러리를 추가해줍니다.
추후 room 이나 okhttp, retrofit 등이 필요한 경우 data 모듈에 추가하면 됩니다.
build.gradle.kts (presentation)
...
dependencies {
implementation(project(":domain"))
implementation(project(":data"))
...
// tdd
testImplementation(SdTestDependency.Tdd.junit5)
testRuntimeOnly(SdTestDependency.Tdd.junit5Engine)
testImplementation(SdTestDependency.Tdd.junit5Params)
testRuntimeOnly(SdTestDependency.Tdd.junit5ParamsEngine)
testImplementation(SdTestDependency.Tdd.mockk)
testImplementation(SdTestDependency.Tdd.coroutines)
// bdd1
androidTestImplementation(SdTestDependency.Bdd.junit)
androidTestImplementation(platform(SdTestDependency.Bdd.composeBom))
androidTestImplementation(SdTestDependency.Bdd.composeJunit)
// bdd2
debugImplementation(SdTestDependency.Bdd.debugComposeTooling)
debugImplementation(SdTestDependency.Bdd.debugComposeManifest)
}
...
presentation 은 domain 과 data 모두 연결해줍니다.
data 를 알아야 하는 이유는 repository 및 dataSource 관련 di 처리를 해야하기 때문입니다.
실제 로직에서는 data 모듈에 있는 파일에 직접적으로 접근하는 일은 없어야하며, viewModel 에서 usecase 를 통해 접근하여 사용해야 합니다.
그 외 compose 를 비롯해 coil 이나 animation 처리와 같은 안드로이드 의존성은 모두 여기에 추가하면 됩니다.
4. 기존 모듈에 있던 클래스들을 각 계층 내 목적에 맞는 위치로 이전합니다.
5. 테스트를 진행합니다.
build 를 진행하였고 성공했다는 결과를 얻었습니다.
앱도 잘 실행되는 것을 확인하였습니다.
전체 코드는 다음과 같습니다.
감사합니다.
나만의 안드로이드 앱 만들기(중급자 편) - 테스트 코드 작성하기 (viewModel) (2) | 2023.12.25 |
---|---|
나만의 안드로이드 앱 만들기(중급자 편) - 테스트 코드 작성하기 (utils) (0) | 2023.12.24 |
나만의 안드로이드 앱 만들기(중급자 편) - 클린 아키텍쳐 개요(clean architecture) (1) | 2023.12.23 |
나만의 안드로이드 앱 만들기(중급자 편) - BuildConfig의 deprecated 대응하기 (4) | 2023.12.22 |
나만의 안드로이드 앱 만들기(중급자 편) - buildSrc 추가하기 (0) | 2023.12.22 |