[Android] Koin vs Dagger 그리고 추가된기능
작년 여름에 처음 Koin을 도입하며 썻던글인데 벌써 시간이 이렇게 빨리 지나가다니… 맨 처음 스타수 800개여서 이거 도입을 해도 괜찮을까 많은 고민을 했지만 벌써 스타수가 3천개에 다가가고 제가 최근 도입했던 라이브러리중 가장 큰 만족감을 주었던 라이브러리입니다. 정식버전기념 Daager와의 차이점과 정식버전에서 추가된점을 기술하려합니다.
Koin과 Dagger의 차이점은?
당시 Koin을 만든 Arnaud Giuliani에게 제가 한가지 물어봤던게 있습니다. “Koin하고 Daager하고 속도차이는 얼마나 나?” 그랬더니 답으로 “큰 차이 없어 비슷비슷해"라고했던말이 기억이 납니다. 물론… 지금 생각해보면 과일가게에가서 “아저씨 이 과일 맛있어요?” 라고 물어보는것과 같다는걸 깨달았습니다.우선 Koin은 Dagger보다 당연히 빠를 수 없고 성능면에서도 Dagger가 유리합니다.
Dagger는 Annotation을 통해서 컴파일과정에서 DI를 주입합니다. 물론 Annotation을 처리하는 과정에서 컴파일속도가 느려질순 있지만 논리적으로는 런타임과정에서 에러가 발생하지않고 순수한 자바로 되어있습니다. 반대로 Koin은 런타임과정에서 DI를 주입하고 컴파일시 오버헤드가 없는반면에 런타임중 Crash가 자주 발생합니다. 또한 Kotlin DSL에 의존하고있기때문에 순수한 코틀린 코드로 되어있습니다.
Dagger
장점
- 순수자바
- 안정적이고 유연함
- 런타임 에러가 발생하지 않음
- 런타임시에 매우 빠름
단점
- 컴파일시 오버헤드가 발생
- 학습곡선이 상당함
Koin
장점
- Annotation 과정이 없어 컴파일이빠름
- 학습하기 쉽고 설치도 쉬움
단점
- 런타임중 에러가 발생
- Daager에 비해 런타임시 오버헤드가 있음
Koin 정식버전에서 바뀐점
Bean이 아닌 Single
기존 싱글톤을 만들때 bean{}으로 만들던것이 이제는 single{}을 이용해서 만듭니다.
val myModule = module {
single { Controller(get()) }
single { BusinessService() }
}
Scope가 추가
MVP패턴을 사용한다면 일반적으로 Presenter에 Scope를 주어 메모리를 효율적으로 관리하게합니다.
val appModule = module {
// Scope로 Session을 주고있습니다.
// 맨처음 Application Level에서 Module을 정의할때 사용합니다. scope("session") { MyScopePresenter(get())}
}
그 후 Activity나 Fragment레벨에서 아래와같이 사용합니다.
class MyScopeActivity : AppCompatActivity() {
// 스코프에 바인딩된 Presenter를 만듭니다.
val scopePresenter: MyScopePresenter by inject()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_simple)
// session 스코프가 현재 액티비티의 라이프사이클을 따름을 선언합니다.
bindScope(getOrCreateScope("session"))
}
}
Dagger처럼 Scope를 도입하기는하였지만 생각보다 유연하지는 않은것같습니다. 자세한 내용은 링크를 확인해주세요.
Parameter 전달
Viewmodel등에 Parameter를 주는 신택스가 조금 바뀐것같습니다. Parameter를 주고싶다면 Viewmodel을 선언할때
viewModel { parameterList ->
SomeViewModel(
parameterList[0], parameterList[1], parameterList[2],
.....더 많은 파라미터(?) )
}
위와같이 람다식으로 파라미터를 선언하고
class SomeViewModel:ViewModel(val paramFirst:String, val paramTwo:String)
뷰모델 클래스에서 인자만큼 선언해준 뒤
by viewModel<DialogViewModel>{parametersOf("param1","param2")}
위와같이 parametersOf를 이용해서 인자들을 전달합니다.
Koin Test하기
Gradle
testCompile 'org.koin:koin-test:1.0.1'
예제
open class BaseTest: KoinTest {
@Before
fun before() {
/* StandAloneContext로 코인을 시작합니다.*/
StandAloneContext.startKoin(listOf(contextModule, networkModule, repositoriesModule))
}
@Test
fun myTest() {
// DI를 주입합니다.
val service : BusinessService = get() //테스트코드작성 }
@After
fun after() {
/* 테스트 후 Koin을 정지합니다.*/
StandAloneContext.stopKoin()
}
}
위 예시에서는 간략히 설명했지만 Koin에서는 정말 많은 테스트 메서드들을 제공하고있습니다. 이곳에서 확인할 수 있습니다.
로그를통해 DI 관계보기
Logcat에서 Log Filter를 위와같이 설정하면 대략적으로 어떠한 순서로 주입이 이루어지는데 볼 수 있습니다.
Koin을 사용하다보면 런타임에러가 많이 발생하기때문에 정 에러를 못찾고 헤메는 상황에서 유용하게 쓰일 수 있습니다.
마치며
분명 Koin보다 Dagger가 우수한것은 사실입니다. 하지만 자바스크립트라는 언어가 우수했기때문에 살아남은것이 아닌 적합했기때문에 살아남은것처럼 Koin도 안드로이드와 코틀린 환경에서 오래오래 살아남아 DI에 관해선 더이상 다른걸 안배우게 해줄 수 있었음 (?) 좋겠습니다…