[Android] Clean Architecture For Android

kimgwon·2024년 10월 11일

Android

목록 보기
2/7

Software Architecture

아키텍처는 소프트웨어의 시스템 구조와 그 구성요소들을 설계하는 것이다.
크기와 복잡도가 증가하게 될 경우 코드 파악이 어려워지고, 같이 개발하는 개발자의 수에 따라 명확하고 일관된 아키텍처가 필요하다.

예시

before

data class User(val id: Int, val name: String, val email: String)

fun main() {
	println(fetchUserFromNetwork(1))
}

private fun fetchUserFromNetwork(userId: Int): User? {
	// ... 네트우크에서 userId에 해당하는 사용자 정보를 가져오는 코드 ...
    return if (userJson != null) {
    	User(userJson)
    } else {
    	null
    }
}

after

-- domain layer
interface UserRepository {
	fun getUser(userId: Int): User?
}

data class User(val id: Int, val name: String, val email: string)

// -- data layer
class NetworkUserRepository(private val apiClient): UserRepository {
	override fun gtUser(userId: Int): User? {
    	val userJson = apiClient.fetchUser(userId)
        return if (userJson != null) {
        	User(id = userId, name = "", email = "")
        } else {
        	null
        }
    }
}
class ApiClient {
	fun fetchUser(userId: Int): Stirng? {
    	// ... 네트워크에서 userId에 해당하는 사용자 정보를 가져오는 코드 ...
        return "{}"
    }
}

// -- presentation layer
fun main() {
	val apiClient = ApiClient()
    val userRepository: UserRepository = NetworkUserRepository(apiClient)
    val user = userRepository.getUser(1)
    println(user)
}


Clean Architecture

내부 구조를 변경하더라도 시스템 전반에 안정성을 보장시키며 각 레이어 사이의 의존성을 최소화한다.
의존성 주입을 중심으로 모듈화를 통해 코드의 가독성, 확장성, 유지보수성이 향상된다.

  • Entities: 시스템의 비즈니스 로직과 데이터 모델을 담당하는 레이어
    가장 핵심적인 부분으로, 변경이 되지 않을 만한 것들이 들어가야 한다.
  • Use Cases: 시스템의 비즈니스 로직을 구현하는 레이어
    SRP(단일 책임 원칙)을 준수하며, 하나의 기능을 수행하도록 구현한다.
    사용자 목록을 가져오는 기능이 있다면, 이를 캡슐화한 GetUserListUseCase 클래스를 만들 수 있다. 보통 상세한 구현 내용을 작성하지는 않으며, interface, abstract와 같이 추상적으로 구현한다.
  • Interface Adapters: 시스템의 외부와의 인터페이스를 처리하는 레이어
    보통 Use Cases에서 선언한 추상화 된 내용을 상세 구현한다.
    계층을 이동해야 할 때, 변환을 해준다.
  • Frameworks and Drivers: 시스템과 외부 시스템의 인터페이스를 제공하는 레이어

장점

  • 유연성: 시스템의 변경에 대한 대응력이 높아지며, 새로운 요구사항에 대응할 때 기존 코드를 수정할 필요가 적어짐
  • 테스트 용이성: 의존성을 최소화하고 모듈화하므로, 단위 테스트가 쉬워짐
  • 유지보수성: 시스템 구조가 명확하게 나뉘어져 있어서 코드를 이해하고 수정하기 쉬워짐
  • 확장성: 새로운 기능을 추가하거나 기존 기능을 변경할 때 다른 레이어에 영향을 주지 않음
  • 코드 가독성: 코드가 간결하고 명확해져서 코드를 이해하는 데 시간이 적게 걸림


Recommendations for Android Architecture

Clean ArchitectureAndroid에서 권장하는 Architecture는 의존성 방향에서 차이가 있다.

Android Architecture는 UI Layer가 Data Layer를 의존하고 있지만,
Clean Architecture에서는 DB에서 UI에 접근하려면 Entities에 우선 접근 한 후, UI에 접근해야만 한다.

Android Architecture는 범용성을 갖고, Clean Architecture는 대규모 시스템에 적합하다.

Layer

  • Presentation Layer:
    사용자 인터페이스를 담당하는 레이어.
    Activity, Fragment, View, ViewModel 등으로 구성.
    사용자 입력을 처리하고, 데이터를 화면에 표시하며 이 레이어는 UI와 관련된 코드만 포함하며, 비즈니스 로직은 포함하지 않음

  • Domain Layer:
    애플리케이션의 비즈니스 로직을 담당하는 레이어.
    Use case, Entity, Interface로 구성
    Use case는 애플리케이션의 기능을 구현하는 로직을 담당, Entity는 모델을 담당, Interface는 Data Layer의 구현체를 표현

  • Data Layer:
    애플리케이션에서 사용하는 데이터를 관리하는 레이어.
    Repository, DataSource 등으로 구성
    데이터를 로컬 데이터베이스나 서버에서 가져와 Use case에 전달



Clean Architecture For Android

최종적으로는 Data가 UI에 표현이 되어야 한다. 하지만 의존관계가 없기 때문에 interface를 통해 경계를 횡단한다.

과정은 다음과 같다.
1. ViewModel이 UseCase에게 데이터를 요청한다.
2. UseCase는 Repository를 통해 Entity를 모델 삼아 데이터를 불러온다.

  • UI: View, ViewModel
  • Data: Repository, LocalDataSource, RemoteDataSource
  • Use Cases: UseCase
  • Interface Adapters: Repository

모듈화

Clean Architecture 도입을 위해 안드로이드 모듈화를 진행할 수 있다.

Presentation과 Data는 서로 의존하지 않기 때문에 단독적으로 테스트를 할 수 있게 된다.



Reference

안드로이드 공식 문서 - Recommendations for Android architecture
패스트캠퍼스 - Android 앱 개발 feat. Jetpack Compose
패스트캠퍼스 - 의존성 주입 완전정복 by Hilt

0개의 댓글