안드로이드 아키텍처 학습 노트 목차

의존성 주입 — Hilt·Koin

ViewModelRepository가 필요하고, RepositoryApiDao가 필요하다. 이 의존성 그래프각자 new로 직접 만들면강하게 결합되고, 테스트에서 가짜로 바꿀 수 없고, 객체 생성 코드가 사방에 흩어진다. **의존성 주입(DI)**은 필요한 객체를 밖에서 만들어 넣어줘 이 문제를 푼다. 안드로이드 공식 권장이 Hilt(Dagger 기반)이고, 경량 대안이 Koin이다. (출처: Android — Dependency injection / Hilt.)

DI가 푸는 문제 — 결합도와 테스트

// ❌ 직접 생성 — 강결합, 테스트에서 api를 가짜로 못 바꿈
class MemberViewModel {
    private val repo = MemberRepositoryImpl(RetrofitApi(), RoomDao())  // 박혀버림
}

// ✅ 주입 — 의존성을 생성자로 받음 → 테스트에서 가짜 주입 가능
class MemberViewModel(private val repo: MemberRepository)

*"의존성을 밖에서 받는다"*는 한 가지 전환이 — 결합도를 낮추고(인터페이스로 받음), 테스트에서 가짜(fake/mock)로 교체하게 하며, 객체 수명·재사용을 중앙에서 관리하게 한다.

Hilt — Dagger 기반 컴파일 타임 DI

HiltDagger를 안드로이드용으로 감싼 공식 DI다. 컴파일 시점에 의존성 그래프를 생성·검증런타임 오버헤드가 없고 그래프 오류를 빌드 때 잡는다.

@HiltAndroidApp                         // Application에 — 그래프 진입점
class MyApp : Application()

@Module @InstallIn(SingletonComponent::class)
object DataModule {
    @Provides @Singleton                // 어떻게 만드는지 알려줌
    fun provideApi(): MemberApi = Retrofit.Builder()...create()

    @Provides @Singleton
    fun provideRepo(api: MemberApi, dao: MemberDao): MemberRepository =
        MemberRepositoryImpl(api, dao)   // 인자(api·dao)도 그래프에서 주입됨
}

@HiltViewModel                          // ViewModel 주입
class MemberViewModel @Inject constructor(
    private val repo: MemberRepository   // 자동 주입
) : ViewModel()

@AndroidEntryPoint                      // Activity/Fragment 주입 진입점
class MainActivity : ComponentActivity()

핵심 어노테이션 — @HiltAndroidApp(진입점)·@AndroidEntryPoint(Activity/Fragment)·@HiltViewModel·@Inject constructor(생성자 주입)·@Module+@Provides(만드는 법)·@Binds(인터페이스↔구현 연결).

스코프 — 객체의 수명

Hilt는 컴포넌트별 스코프객체 수명을 정한다.

스코프수명
@Singleton앱 전체 (하나)
@ActivityRetainedScoped회전에도 유지(ViewModel 수명)
@ViewModelScopedViewModel당
@ActivityScopedActivity당
다이어그램 로딩 중…

스코프를 안 붙이면 주입할 때마다 새 인스턴스, 붙이면 그 컴포넌트 안에선 같은 인스턴스가 공유된다.

Koin — 경량 런타임 DI

Koin코틀린 DSL로 의존성을 선언하는 경량 서비스 로케이터다. 런타임에 해석하므로 어노테이션 처리·빌드 부담이 없고 설정이 간단하지만, 그래프 오류를 런타임에야 발견하고 해석 비용이 약간 있다.

val appModule = module {
    single<MemberRepository> { MemberRepositoryImpl(get(), get()) }  // get()=의존성 해석
    viewModel { MemberViewModel(get()) }
}
// ViewModel에서: by inject() / by viewModel()

Hilt vs Koin — 트레이드오프

HiltKoin
검증 시점컴파일 타임(안전)런타임
빌드KAPT/KSP 처리(느림)가벼움
러닝 커브가파름(Dagger)완만
공식성구글 공식 권장커뮤니티 인기

큰 팀·안전 우선이면 Hilt(컴파일 검증), 작은 앱·빠른 시작이면 Koin이 흔한 선택이다.

정리 — 만들지 말고 받아라

DI의 핵심 — 의존성을 직접 new 하지 말고 밖에서 주입받아 결합도를 낮추고 테스트에서 교체하게 한다. Hilt컴파일 타임에 그래프를 생성·검증(@Module/@Provides/@Inject·스코프), Koin런타임 DSL로 가볍게. 둘 다 생성자 주입을 기본으로 — 의존성을 인터페이스로 받는 습관이 테스트 가능한 코드를 만든다.

한 줄 요약 — DI=의존성을 밖에서 주입(결합도↓·테스트 교체). Hilt(공식·Dagger·컴파일 검증): @HiltAndroidApp·@AndroidEntryPoint·@HiltViewModel·@Inject constructor·@Module/@Provides/@Binds·스코프(@Singleton/@ViewModelScoped). Koin(경량·런타임 DSL·single/viewModel/get()). 컴파일 안전(Hilt) vs 간편(Koin).

(출처: Android — Hilt / Dependency injection / Koin docs.)

Repository·UseCase — 단일 출처·비즈니스 캡슐화멀티 모듈화 — 빌드 속도·경계·재사용