선생님, 개발을 잘하고 싶어요.

[나의 작은 모닝루틴] 의존성 주입 koin 사용해보기 본문

개발/android 개발

[나의 작은 모닝루틴] 의존성 주입 koin 사용해보기

알고싶은 승민 2019. 4. 20. 00:23

tistory 글 쓰는 거 번거로워서 안 쓰고 있었는데 어느 날 들어와 보니 에디터가 변경돼있었다. 그래서 오랜만에 써보는 안드로이드 개발 관련 이야기

 

의존성 주입이 뭔지 책으로 읽고 koin 사용해봐도 감이 잘 안왔는데 이번에 개인 프로젝트 진행하면서 편함을 체감한 경험을 해서 공유하려고 한다.

 

프로젝트 상황 설명

 

안드로이드 MVP 패턴을 적용해서 모닝루틴 기록하는 앱을 만드는 프로젝트를 진행 중이었다.

 

Model : 모닝 루틴 객체를 정의하고, 모닝루틴 데이터의 읽기, 쓰기를 위해 repository 객체를 만들었다. 작은 범위부터 구현하기 위해 간단히 메모리 상에서 데이터를 관리하는 memory repository를 구성했다.

 

Presenter : Model을 참조하며 View의 변경 이벤트에 의해 Model의 repository를 사용해 데이터를 읽고, 변경한다.

 

View : Presenter를 참조하며 사용자의 이벤트를 Presenter에 전달한다.

 

그래서 각각 Presenter는 Model을 참조하기 위해 Model 생성을, View는 Presenter를 참조하기 위해 Presenter 생성을 하였다.

 

의존성 주입이 없을 때?

 

memory repository를 넘어서 이제 영속적으로 데이터를 관리하기 위해 room repository를 제작하였다.(room repository 제작법도 추후에 블로깅 해보자) 그리고 프로젝트에 적용하고자 한다.

 

이런 젠장 repository 변경 같은 Model의 변경사항이 있으니 Presenter들이 전부 변경되어야 한다. 기존에 memory repository 사용하던 것을 room repository로 변경해야 하는 상황. 

 

변경 하려니까 repository 변경해야하는 곳이 많아...

RoutineMemoryModel을 전부다 RoutineRoomModel로 변경해야 하는 상황에 봉착하자 번거로움이 최고로 올라갔다. 이미지는 3개지만 실제로는 7-8군데의 수정이 필요했고, 더 큰 프로젝트였다면 샐 수도 없이 많은 곳에서 변경이 일어났어야 할 것이다.

 

분명 이런 상황을 피하려고 인터페이스로 정의된 Model을 인자로 받았는데? 하지만 결국 실제로 참조를 얻기 위해선 생성자를 호출할 필요가 있다. 결합도를 낮추려고 인터페이스를 정의해봤자 생성자 호출을 하기 위해 구체적인 클래스 접근을 하게 되는 딜레마에 빠진 것이다.

 

의존성 주입 도입을 위해 koin의 사용

 

이런 개 같은  상황을 피하려면 어떻게 하면 좋을까? Model의 생성을 담당하는 별도의 객체, Presenter의 생성을 담당하는 별도의 객체가 있어서 Presenter와 View가 각각 다른 레이어인 Model, Presenter의 인터페이스만 알고 구체 클래스를 코드상에 적을 필요가 없도록 하면 될 것이다.

 

별도의 object를 만들어서 생성, 관리하는 방법도 있겠으나 우아하지 않다. 찾다가 우아한 방법인 의존성 주입 라이브러리 koin을 발견했다.

 

코인을 사용하는 것은 심플했다.

 

1. 필요한 모듈을 제작한다.

presenter에 필요한 repositoy를 interface 형으로 생성하는 모듈
view에 필요한 presenter 구체 클래스를 생성하는 모듈

 실제로 구체 클래스를 생성해서 문제인 repository가 가장 주요한 모듈이라고 볼 수 있다. 메모리 테스트용 모듈은 나중에 메모리 테스트시에 유용하게 쓰일 것이다. 

 

2. Application 객체를 만들고 startKoin을 이용해 모듈들을 등록한다.

 

 startKoin에 androidContext를 전달해서 의존성 트리에서 context get() 해야 할 때 전달된다. 그리고 1번에서 정의한 모듈들을 등록한다.

 

3. 안드로이드 매니페스트에 Application을 등록시킨다.

 

android:name 태그에 만든 application 클래스명을 적어놓는다. 앱이 시작할 때 startKoin으로 모듈 등록을 끝마칠 수 있다.

 

4. 기존에 객체 생성자 호출 대신 by inject()를 사용해 객체를 주입시켜준다.

이제 by inject() 호출 한 번으로 생성자 호출 없이 모듈에서 정의된 repository 객체로 생성된 presenter를 사용할 수 있다. 만세!

 

결론 

위의 예제에서 model module을 통해 Model - Presenter 사이에 Model의 생성을 Presenter가 신경 쓸 필요가 없어졌다.

presenter module 을 통해 Presenter - View 사이에 Presenter의 생성을 View가 신경쓸 필요가 없어졌다.

 

의존성 주입을 사용하면 MVP 각 레이어가 각자의 생성에 대한 책임이 없이 더욱 모듈화 된 형태로 코드 구성이 가능해진다.

 

이 말은 A레이어의 구현 변경이 B, C구현 변경으로 연결되지 않는다는 뜻이다.

 

첫 예에서 repository 하나 변경하려고 7-9군데를 수정했던 필자는 이제는 한 줄의 코드 변경만으로 memory - room repository를 변경할 수 있게 되었다.

debugModule 로 변경하면 바로 memory repository를 사용하는 앱이 완성된다!

 

참고자료

 

드로이드 나이츠 2019 콘퍼런스 Koin vs Dagger2 : https://youtu.be/mbntrG0LKtE

koin reference : https://insert-koin.io/docs/2.0/documentation/reference/index.html#_koin_core_dsl_container_api

Comments