안드로이드 연구소

[여기가 DI 설명 제일 잘함] 의존성 주입 하는 법 & DI 라이브러리들 본문

안드로이드 연구소/의존성주입

[여기가 DI 설명 제일 잘함] 의존성 주입 하는 법 & DI 라이브러리들

안드로이드 연구원 2023. 5. 16. 16:17

지난 챕터2에서 MVVM만들기 시리즈에서 

안드로이드 아키텍처 컴포넌트에 대해서 알아보았습니다.

 

오늘부터 "챕터3 안드로이드 테스트 코드"를 시작해보겠습니다.

지난 챕터2에서도 ViewModel이나 Lifecycle들을 사용하면 "테스트를 잘 할 수 있도록 하였다."라는

말들을 종종하였는데 그렇다면 이제 어떻게 애플리케이션에서 테스트를 할 수 있는지를 보겠습니다.

 

그전에 테스트를 잘 할 수 있도록 세팅 하기위해서 "의존성 주입 라이브러리"에 대해서 배워볼 예정입니다.

이전에 배웠던 ViewModel이나 Lifecycle 테스트를 잘 할 수 있도록 한 까닭은 무엇일까요?

그건 바로 기능별로 클래스를 분리해놓았기 때문입니다.

 

"정확하게는 UI로직과 비즈니스로직을 분리하였다"라고 하는데요.

이는 UI로직과 비즈니스 로직이 하나의 클래스안에 동시에 적혀있으면

UI로직에서 에러가 나도 해당 클래스에서 에러가 난 것이고

비즈니스 로직에서 에러가 나도 똑같은 클래스에서 에러가 난 것으로 나오기 때문입니다.

 

그렇다면 위처럼 의존성이 있는 코드들은 어떤 문제가 있으면

어떻게 하면 위처럼 분리시켜서 테스트를 더 쉽게할 수 있을까요?

하나씩 차근차근 시작해보겠습니다.

 

 

1. 두 클래스가 서로 의존중인 코드에 대한 예시를 보여줘.

class UserViewModel : ViewModel() {
    private val userRepository = UserRepository()
    // using userReposiroty instance ...
}

위의 코드는 MVVM 만들기에서 많이 사용했었던 예제인데요.

UserViewModel 클래스안에서 UserRepository클래스의 인스턴스를 사용하고 있습니다.

그말은 즉슨 UserViewModel을 사용하려면 무조건 UserRepository클래스를 호출하게된다는 것인데요.

이것이 바로 UserviewModel 클래스는 UserRepository 클래스를 의존하고 있는 상태임을 나타냅니다.

 

이러한 코드에는 어떤 문제들이 있을까요?

첫번째, UserRepository클래스를 수정하면 UserViewModel클래스도 함께 수정해야한다.
두번째, UserViewModel클래스에서 에러가 발생하면
UserViewModel클래스 문제인지, UserRepository클래스의 문제인지 확인 어렵다. 

그렇다면 어떻게 하면 이 문제를 어떻게 해결할 수 있을까요?

 

 

2. 위의 문제를 해결하려면 어떻게 해야해?

위의 문제를 해결하기 위해서는 아래와 같은 세가지 방법이 있습니다.

1. 생성자 주입(Constructor Injection)
: 이 유형에서는 종속성이 클래스의 생성자를 통해 제공됩니다.
생성자의 파라미터로 선언되며 의존성 주입이 선언되고, 인젝터는 객체를 생성할 때 인스턴스를 확인하고 제공합니다.

2. 메서드 주입(Method Injection)
: 메서드를 통해 종속성을 주입하는 작업이 포함됩니다.
이러한 메서드는 일반적으로 object 생성 후에 호출되며 종속성은 매개 변수로 제공됩니다.

3. 필드 주입(Field Injection)
: 종속성을 클래스의 필드에 직접 주입하는 것입니다.

이해하기 어렵네요. 그렇다면 바로 아래에서 예제로 확인해볼까요?

 

 

3. 예제 코드를 보여줘

첫번째 방법으로 생성자 주입(Constructor Injection)이 있습니다.
class UserViewModel(private val userRepository: UserRepository) : ViewModel() { 
   // using UserRepository instance ...
}

 

위 UserViewModel에서 외부 클래스인 UserRepository인스턴스를 파라미터로 받습니다.
이렇게 하면 UserViewModel에서는 UserRepository클래스를 호출할 없게 됩니다.
호출은 엑티비티나 프레그먼트에서 하기 때문입니다. 

 

두번째 방법으로는 메서드 주입(Method Injection)이 있습니다.
class UserViewModel : ViewModel() {
    private var userRepository: UserRepository? = null

    fun setUserRepository(userRepository: UserRepository) {
        this.userRepository = userRepository
    }

    // using UserRepository instance ...
}​

 

엑티비티나 프레그먼트에서 userRepository 클래스를 호출한 클래스의 인스턴스를

setUserRepository() 함수를 사용하여 ViewModel로 가져오게됩니다.

이렇게 하면 또한 UserRepository클래스를 호출할 일이 없겠죠?

 

세번째 방법으로 필드 주입(Field Injection)이 있습니다.
class UserProfileViewModel : ViewModel() {
    @Inject
    lateinit var userRepository: UserRepository

    // ViewModel methods and logic...
}​

이게 끝입니다.

userRepositoy변수를 선언해놓고

그 위에 @Inject 어노테이션을 선언합니다.

 

이렇게 사용하면 간단해 지는걸 쓰지 않을 이유가 없겠죠?

세번째 필드 주입이 바로 앞으로 사용할 의존성 주입(DI) 라이브러리입니다.

어떤 DI라이브러리들이 있고 어떻게 사용하는지에 대해서 알아볼까요?

 

 

4. DI 라이브러리에 대해 설명해줘.

DI라이브러리는 종속성 주입 프로세스단순화하고 자동화하는 기능 세트를 제공합니다.
DI 라이브러리를 사용하여 느슨한 결합을 촉진하고 보일러플레이트 코드를 줄임으로써
Android 애플리케이션의 모듈성, 테스트 가능성 및 유지 관리 가능성을 크게 개선할 수 있습니다
안드로이드에서 3가지 대표 DI라이브러리가 존재합니다.

1. Dagger
: 2012년에 발표된 Google에서 개발한 컴파일 타임 DI 프레임워크입니다.
어노테이션을 사용하여 효율적이고 최적화된 코드를 생성합니다.
기능이 향상된 Dagger2는 2015년에 릴리즈되었다.

2. Hilt
: 2020년 Google에서 개발한 Dagger을 베이스로 구축된 DI 라이브러리입니다.
이는 Dagger를 사용해 앱에 통합하는 프로세스를 단순화합니다.

3. Koin
: 2017년에 개발된 Kotlin용 경량 DI 프레임워크입니다. 단순성과 사용 편의성에 중점을 둡니다.
리터럴 함수와 프로퍼티를 사용하여 프로세스를 단순화하였다.

Dagger가 가장 먼저 소개된 DI라이브러리였고

Hilt가 Dagger를 좀 더 쉽게 사용할 수 있게 개선하였고

쫌 더 단순화시킨 라이브러리가 Koin정도로 보면 되겠네요.

 

그렇다면 Dagger에 대해서 알아볼까요?

다음 포스트에서

 

 

 

 

 

 

 

 

 

 

 

Comments