Kotlin에서 Dagger2 쓰기 힘드니? 그럼 넌 Koin이야
제목을 뭐로 지을까하다가 우송대 드립(?)으로 지어보았습니다. 최근들어 많은 안드로이드 오픈소스나 프로젝트들이 Dagger를 도입하고있습니다. 그리고 정말 훌륭한 컨셉이라고 생각합니다.
하지만 학습곡선이 상당합니다. Provide로 메서드를 정의해서… Component로 주입하고… 그걸 또 주입하는 단위로 Scope를 달아주고… Inject를 해주고….심지어 간신히 어노테이션들을 이해하고 샘플 프로젝트를 열어보면
정말 많은 컴포넌트들 그리고 간단한 DI 조차도 파일들이 너무 많아지고 관리가 어렵게됩니다. 자바에서는 그럭저럭 도입을 했지만 특히 코틀린 이유를 알 수 없는 컴파일 에러들을 상당히 많이 마주하게되고 많은 파일들로 인해 디버깅을 더 어렵게합니다. 이렇게까지 해야해…? 라는 생각이 자주들었는데요.
그러다 발견했습니다. 코틀린을 위한 의존성 관리 라이브러리 Koin입니다. 코인을 사용하면 위에 나와있는 코드들을 단 몇줄로 정의할 수 있습니다.
물론 코인도 알고있어야할 용어는 있습니다. 용어를 간단히 설명드리자면
- applicationContext — context를 주입합니다.
- bean — 싱글톤 컴포넌트를 선언합니다.
- factory — 인스턴스를 가져올 Factory 패턴을 선언하며 inject할때마다 새로운 인스턴스를 가져오도록 합니다.
- bind — 종속시킬 class나 infterface를 주입합니다.
- get — bean이나 factory를 통해 정의된 컴포넌트들을 가져옵니다.
용어만 들으니 감이 안오시죠? 위에 설명드린 Dagger 코드와 연관지어 설명드리겠습니다.
Dagger를 사용한 경우
아까의 Dagger 소스를 다시보겠습니다. 최상위 Application 모듈을 선언하고 그 아래 Activity 모듈들이 종속되죠. 그리고 TaskActivity 모듈은 다시 TaskFragment와 TaskPresenter를 종속시켜줍니다.
그리고 다시 Application에서 Inject를 통해 주입을 해주죠. 그럼 TaskActivity에서는 Presenter나 Fragment 역시 Inject 어노테이션을 통해 주입을 받습니다. 하지만 Koin을 쓴다면 어떻게 될까요?
Koin으로 바꾼다면
TodoAppModule을 정의합니다. 그리고 Factory키워드를 통해 TasksFragment와 TaskPresenter가 필요하다고 알려줍니다.
위에서 만든 todoAppModuledmf 최상위Application 클래스를 통해 startKoin으로 선언만하면 모든 필요한 모듈 선언이 끝납니다. 그러면 실제로 각각의 Presenter와 Fragment에서는 어떻게 가져올까요?
by Inject()만 붙여주면 주입해줄 수 있습니다. Factory 키워드로 선언을 하면 Inject할때마다 새로운 인스턴스를 만들고 Bean으로 선언되었다면 싱글톤으로 가져옵니다.
이외에도 Android Architecture 패턴인 ViewModel을 하고있어 각각의 Activity나 Fragment에 개별 Viewmodel을 주입할 수 있고 Activity와 Fragment간 같은 Viewmodel을 쉽게 주입해줄 수 있습니다.
성능은?
Medium에 올라온 개발자글에 의하면 Dagger와 성능차이가 없다고 합니다. 하지만 스택오버플로우에 올라온 내용에 의하면 Koin이 아주 약간 느리다고하지만 아직 제대로 벤치마크를 해본 자료는 찾아보지 못했습니다.
마치며
튜토리얼보단 설명드리고자 적은 내용이라 많이 짧습니다. 코틀린으로 개발하시다가 Dagger 에지치셨다면 꼭 한번 보시기를 추천드립니다. 본 글의 예제들은 Koin의 개발자인 Arnaud Giuliani의 Moving from Dagger to Koin의 예제를 사용하였습니다. Dagger에 비해 짧은 역사를 가지고있고 곧 정식버전이 나온다는 점 그리고 점점 쓰는 개발자들이 늘어난다는 점이 큰 장점이 될 것 같습니다.