logo
logo
모바일
Dagger
자바와 Android를 위해 완전히 정적으로 컴파일 타임 의존성 주입(Dependency Injection) 프레임워크
StackOverflow 질문 수: 1499
Github Stars : ★ 17531
사용 기업
직장
교육
패션
소셜/컨텐츠
푸드테크
이커머스
헬스케어
모빌리티
금융/보험
부동산/인테리어
기타
여행
techstack-logo
드라마앤컴퍼니
techstack-logo
뤼이드
techstack-logo
에이블리
techstack-logo
당근
techstack-logo
마켓컬리
techstack-logo
아이디어스
techstack-logo
버드뷰
techstack-logo
위메프
techstack-logo
하이퍼커넥트
techstack-logo
카카오모빌리티
techstack-logo
더스윙
techstack-logo
카카오페이
techstack-logo
브랜디
techstack-logo
쿠팡
techstack-logo
큐피스트
techstack-logo
매스프레소
techstack-logo
버킷플레이스
techstack-logo
엔라이즈
더 보기
기술 블로그 글
사람인에이치알
사람인 Android App Refactoring
안녕하세요. 사람인HR 서비스인프라개발팀 안드로이드 앱 개발 담당 한동훈입니다. 해당 내용은 지난 2021년에 아이엠그라운드앱 구조개선을위해 진행했던 앱리펙토링 공유하는 포스팅입니다. 필요성? 기존에 서비스중인 아이엠그라운드 앱은 MVC패턴구조로 아래와 같은 문제점들이 있었습니다. 기존 문제점 * MVC패턴을 사용하고 있어 Activity,Fragment가 Controller역할을 해서 view,model에 대해 프로세스를 정의하기 때문에 프로젝트가 진행될수록 코드가 비대해지고, 그결과 가독성이 떨어지고 서비스가 확장될수록 유지보수의 비용이 많이 발생함. * Activity마다 같은 로직을 사용할경우 각각에 구현되기 때문에 중복이 발생하고 수정사항 발생시 관련부분 전부를 수정해야하며 뷰와 종속적이기 때문에 화면마다 데이터와 뷰간의 로직이 상이하여 로직에 대한 재검증이 필요함. * repository와 api인터페이스가 비지니스로직 특성에 따라 구분되어 있지 않고, 하나의 class에 모두 나열되어 있음. * 구조상 클래스간 의존성, 결합도가 높음. * dataSource영역의 코드들이 구분없이 한 class와 interface에 정의되어 있어 분석에 비효율적 * 비지니스로직이 분리되어 있지 않아 UnitTest가 어려움. 그래서 이를 해결하고자 리팩토링에서 MVVM패턴을 채용하였고, MVVM패턴 구성과 함께 최적화되어 사용할수 있는 AAC(Android Architecture Components), DI(Depecndency Injection) dagger-hilt, DataBinding, ViewBinding, RXjava를 적용하여 개선하였습니다. 적용내용 * MVVM패턴(AAC Componnents(LiveData, Lifecycle, ViewModel, Room) 와 조합) * Dagger-hilt * DataBinding, ViewBinding * RxJava 1. MVVM 1) MVC 와 MVVM 차이 MVC는 안드로이드 개발에서 화면에 기본이 되는 Activity, Fragment가 직접 Controller가 되어 model과 뷰를 조합하여 화면을 구성하고 유저의 인터렉션을 정의하는 구조입니다. 그래서 controller에서 타이밍상 호출순서에 따라 화면이 갱신되지 않거나 하는경우도 있으며, 생명주기에 영향을 받기 때문에 메모리릭 발생확률도 있어 신경써주어야 합니다. 반면 MVVM의 경우 Activity, Fragment는 뷰의 역할만 담당하고 viewModel에서 repository를 통해 비지니스로직의 정제된 결과값 데이터를 Rx나 liveData같이 observing 가능한 형태로 반환하고, 해당 viewModel의 결과를 사용하고자 하는 view에서 viewModel의 결과값을 observe(관찰)하여 비지니스 로직이 어떤구조로 돌아가는지 알필요없이 결과데이터만 가지고 화면을 구성할수 있게 되는 방식입니다. 이경우 데이터를 observe하는 형태이기 때문에 데이터가 변경시 화면을 구성하기 되어 타이밍문제로 누락이 발생
dagger
retrofit
뱅크샐러드
뱅크샐러드 안드로이드 앱에서 Koin 걷어내고 Hilt로 마이그레이션하기
안녕하세요, 뱅크샐러드 안드로이드팀 이기정입니다. 뱅크샐러드 안드로이드 앱은 클린아키텍쳐를 기반으로 각 도메인 별 화면과 유틸리티, 이벤트 로거, 매퍼, 실험 도구 등 프로그램을 운영하기 위한 수많은 클래스로 이루어져 있습니다. 클래스의 객체 생성에 있어 의존성을 줄이고, 원할한 테스트 코드 작성을 위해 Dependency Injection(의존성 주입) 도구를 사용하여 문제를 해결해오고 있습니다. 이번 시간에는 뱅크샐러드 안드로이드 앱에서 과거부터 사용해오고 있던 DI도구인 Koin에서 구글에서 권장하는 공식 DI 라이브러리 Hilt로 넘어갔던 과정, 그리고 이를 통해 느낀 점에 대해 여러분들께 공유 드리려고 합니다. KOIN에서 힐트로 넘어간 이유? 안드로이드 팀에서 사용하고 있던 스펙 2021년 4월까지 저희 서비스는 아래 코드 구성과 함께 DI도구로 Koin을 사용해오고 있었습니다. 100% Kotlin Multi Module(:app, :feature, :data, :domain, etc) DI Tool : Koin(명목 상 DI이나, Service Locator Pattern) Presentation Architecture : MVP & MVVM WHAT IS KOIN? 과거에 저희가 사용해 온 Koin에 대해 간단하게 소개하자면, 아래와 같은 특징을 갖고 있습니다. Kotlin DSL을 사용 런타임에서 의존성 주입을 해줌 Annotation Processing으로 빌드 시간에 Stub 파일을 생성하지 않음 AAC ViewModel 사용 시 별도의 라이브러리를 통해 의존성 주입이 가능 Koin으로 의존성 주입을 하는 것을 코드로 표현하자면 아래와 같이 작성이 가능합니다. Application 시작 시, startKoin 이라는 DSL 함수내에 modules(...) 함수 내에 선언된 Koin Module을 변수로 넣어주면 Application 런타임 시 객체를 할당합니다. [클래스 정의 & 모듈 주입] 안드로이드 라이프사이클에 해당하는 컴포넌트가 아니라면, 다음과 같이 KoinComponent 인터페이스를 구현하여 모듈에서 컴포넌트 선언을 통해 어디서든 inject() 함수로 주입이 가능합니다. [Activity에 컴포넌트 주입] 코드로만 보면 굉장히 간단하게 주입이 가능하다라는 장점이 있었지만, 크리티컬한 단점이 존재했습니다. KOIN의 장점과 단점 Koin의 장점은 아래와 같은 장점과 단점이 존재합니다. [KOIN의 장점] 러닝커브가 낮아 쉽고 빠르게 DI를 적용할 수 있다. Kotlin 개발 환경에 도입하기 쉽다. 별도의 어노테이션을 사용하지 않기 때문에 컴파일 시간이 단축된다. ViewModel 주입을 쉽게 할 수 있는 별도의 라이브러리를 제공한다. [KOIN의 단점] 런타임에 서비스 로케이팅을 통해 인스턴스를 동적으로 주입해주기 때문에 런타임 퍼포먼스가 떨어진다. (특히, 뱅크샐러드와 같이 점점 기능이 많아진 서비스는 충분히 런타임 시 퍼포먼스가 떨어질 수 있다) 리플렉션을 이용하기 때문에
dagger
원티드랩
koin 에서 hilt 로 이전하기
정식 출시를 기다리고 있던 친구 중 하나입니다 :)원티드 안드로이드 앱은 DI 프레임워크로 Koin 을 사용중이었는데요, 6.6.0 출시 버전부터 Hilt 가 도입되었습니다. 새로운 기술을 실제 프로덕트에 적용하여 기술적, 경험적으로 성장하고 자 하는 니즈와 Jetpack AAC 를 활용하여 프로덕트를 개발하고 있기 때문에 Hilt 를 사용하는 것이 장기적으로 필요할 것이라는 공감대가 있어, 작은 범위부터 시작하여 순차적으로 적용하는 식으로 전환하는 것을 목표로 시작하였습니다. 이번 출시버전에는 익명투표 두런두런 기능에 반영이 이루어 졌고, 앞으로 신규 프로젝트나 기존 코드에서 변환 작업을 계속 진행할 예정입니다.hilt 는 어떤 장점이 있을까?Hilt 는 Dagger2 기반으로 안드로이드 프레임워크서 표준적으로 사용되는 DI 컴포넌트 및 스코프를 기본적으로 제공합니다. DI 는 Dependency Injection (의존성 주입) 의 약자로, 외부에서 의존 객체를 생성하여 전달하는 것을 의미합니다. 의존성 주입에 대하여 잘 고려하여 설계 및 코드를 작성한다면 , 소스코드의 유지보수가 크게 용이해지고 효율적으로 테스트코드 작성이 가능해지는 장점이 있는데요, 좀 더 자세한 내용은 Hilt 의 종속성 주입 개요 섹션을 추천 드립니다.안드로이드 개발에서 DI 를 제공하는 도구들은 몇 가지가 있습 니다. 크게 생각나는 것은 아래와 같습니다. 각 라이브러리에 대한 차이 및 비교는 Dagger, Koin, Hilt 는 어떤 차이가 있는지 소개하는 글을 추천 드립니다.Koin 에서 Hilt 로 변경 후 개인적으로 좋았던 점은, 유저는 더 빠르게 서비스를 이용할 수 있는 것과 개발자는 더 안정적으로 서비스를 제공이 가능해졌다는 부분입니다. Dagger 기반으로 동작방식, 즉 어노테이션에 따라 컴파일 타임에 Generated Code 로 의존 객체 주입이 실행되므로 런타임 퍼포먼스에 영향을 주지 않으며, 기존 Dagger 의 단점이었던 러닝커브가 높고 안드로이드 프레임워크 디펜던시한 요소를 주입하기 위하여 필요했던 많은 보일러플레이트코드를 생성하지 않아도 되어, 다른 개발자 분들도 손쉽게 적응을 할 수 있었습니다. 또한, Koin 을 어느정도 사용하다보니 의존성 주입 시 파라미터를 누락하였을 때 출시 후 예상치 못한 곳에서 사이드이펙트가 발생하곤 했는데요, 이러한 부분을 이제는 컴파일타임에서 체크가 되어 더욱 더 안정성 있게 의존객체 주입이 가능해졌 다고 생각합니다.get(), get(), get() 그땐 어쩔수 없었지만, 이제 안녕Hilt 에 대한 종속 항목 삽입은 공식 문서 및 Hilt - Jetpack 통합 문서를 추천 드립니다.Hilt 적용 상세 내용 및 Trouble-ShootingJetpack Navigation 으로 구성되 어있는 요소 중 화면 전환 시 효과로 지정되어있는 리소스 참조가 더 이상 되지 않는 현상이 있었습니다. Hilt 의 경우 2.36버전을 추가 하였는데, 해당 버전의 컴파일 디펜던시 중 fragment 버전이 기존 사용하던 버전과
dagger
브랜디
HiltViewModel 이해하고 쓰기
안드로이드 앱 개발시 뷰모델을 구현할 때, 액티비티 또는 프래그먼트의 구성 변경에도 데이터가 유지되는 AAC-ViewModel 클래스를 상속하는 것을 권장합니다. AAC-ViewModel 을 사용한다면 뷰모델 객체를 생성할 때 생명주기에 맞춰 데이터를 보존하기 위해 프로그래머는 ViewModelProvider.Factory 만 구현하고 ViewModelProvider 클래스가 뷰모델 인스턴스를 관리하도록 해야 합니다. class MainActivity : AppCompatActivity() { private val viewModel: MainViewModel by lazy { ViewModelProvider( this, object : ViewModelProvider.Factory { override fun <T : ViewModel?> create(modelClass: Class<T>): T { return MainViewModel() as T } } ).get(MainViewModel::class.java) } // ... } 매번 ViewModelProvider.Factory 를 구현 하려면 많은 보일러 플레이트 코드가 생길 수밖에 없는데, 기존에는 위와 같이 직접 팩토리를 생성해주어야 했지만 Dagger2, Koin 등의 의존성 주입 라이브러리를 통해 비교적 편리하게 이용할 수 있었습니다. 하지만 Dagger2 라이브러리를 사용하더라도 복잡한 어노테이션, 높은 러닝커브 때문에 불편함이 많았는데 최근 Dagger Hilt 가 새로 나오면서 적은 코드만으로도 뷰모델 주입이 가능해졌습니다. Dagger Hilt 에 대해 학습해보면서 어떻게 아래의 코드가 동작하는 것인지 궁금증이 생겨서 동작 원리를 알아보게 되었습니다. @HiltAndroidApp class MyApplication : Application() @AndroidEntryPoint class MainActivity : AppCompatActivity() { private val viewModel : MainViewModel by viewModels() } @HiltViewModel class MainViewModel @Inject constructor() : ViewModel() 결론부터 말하자면, Dagger hilt 도 Dagger2 에서의 방식과 마찬가지로 멀티바인딩 기능을 활용하여 뷰모델을 생성하고 주입해줍니다. 따라서 대거의 멀티바인딩 기능, 기존 Dagger2 에서 뷰모델 생성 방식, 마지막으로 Hilt 에서 뷰모델 생성 방식을 차례대로 알아보겠습니다. 멀티바인딩 우선 먼저 알아야 하는 기능이 있습니다. 기존 Dagger2 를 사용할 때, Dagger2 에서 지원하는 기능인 멀티바인딩을 활용하여 ViewModelProvider.Factory 를 매번 구현하지 않고도 사용할 수 있었습니다. 멀티바인딩은 대거 모듈 안에 @IntoMap 어노테이션이 지정된 모든 주입 대상 객체를 컴포넌트 내부에 선언된 Map 인스턴스에 모아주는 기능입니다. @Module class
dagger
Copyright © 2025. Codenary All Rights Reserved.