욱'S 노트

컴파일타임 디펜던시 인젝션/Compile Time Dependency Injection (Kotlin 함수형프로그래밍 #8) 본문

Methdology/Functional Programming

컴파일타임 디펜던시 인젝션/Compile Time Dependency Injection (Kotlin 함수형프로그래밍 #8)

devsun 2025. 1. 21. 09:42
반응형

자바나 스프링을 미리 경험했다면 의존성 주입(Dependency Injection)이라는 것에 익숙할 것이다. 그러나 기존의 방식은 런타임시에 의존성 주입이 발생한다. 앞에서 살펴봤듯이 함수형 프로그래밍에서는 최대한 컴파일러가 타입 안전을 검사하기를 원한다. 코틀린에서는 이 문제를 어떻게 해결할 수 있을지 살펴보자.

Effects

앞에서 효과가 무엇인지 알아봤다. 효과를 명시적으로 함수의 시그니처에 포함시키자는 것이 주요 아이디어이다. 기본적으로 순수 함수라면 함수는 연산만을 수행한다라고 얘기한다.

fun add(x: Int, y: Int): Int = x + y

 

위의 간단한 순수 함수에 사이드 이펙트를 포함시켜 보자.

fun loggingAdd(x: Int, y: Int): Int {
   println("x = $x, y = $y")
   return x + y
}

 

더 심하게 만들어보면 다음과 같을 수도 있다.

fun crazyAdd(x: Int, y: Int): Int {
   if (Random.nextInt() == 42) throw WhatsHappeningException()
   return x + y
}

 

위의 잠재적인 행동을 시그니처에 표현하면 다음과 같다.

context(Raise<WhatsHappeningError>, Random)
fun crazyAdd(x: Int, y: Int): Int

 

만약 네트워크나 파일시스템 혹은 데이터베이스를 사용이라면 다음과 같다.

context(Raise<WhatsHappeningError>, UserRepository)
suspend fun getUserById(id: UserId): User?

 

하지만 위와 같이 표현할 필요가 없다. 코루틴에서는 이미 suspend 제공하기 때문이다. 아래의 시그니처는 서스펜더블 즉 중지가 가능하다는 것을 의미한다. 외부 효과 및 부수 효과가 있다면 suspend로 표시함으로써 사이드 이펙트가 있음을 명시할 수 있다.

suspend fun getUserById(id: UserId): User?

 

Context receiver

코틀린 1.6.20 이후 conext receiver를 제안한다. 간단히 얘기하자면 컨텍스트 리시버는 implict 파라미터를 전달하는 방식다. 이는 일련의 빌트인 디펜던시 인젝션 또는 컴파일타임 디펜던시 인젝션이다. UserRepository 인터페이스를 하나 선언해보자.

interface UserRepository {
   suspend fun getUserById(id: UserId): User?
}

 

해당 저장소를 함수의 선언에 넣어서 사용할 수 있게 한다.

context(UserRepository)
suspend fun getUserName(id: UserId): String? =
   getUserById(id)?.name

 

실제 주입하는 코드는 다음과 같다. with를 사용해서 주입한다.

fun example() {
   createDbConnection().use { db ->
      with(DbUserRepository(db)) {
         getUserName(UserId(1))
      }
   }
}

 

컨텍스트 리시버를 활용하면 여러가지 기능을 합성할 수도 있다.

context(UserRepository, ResourceScope)
fun whoKnowsWhatItDoes(name: String)

 

정리

  • 사이드 이펙트는 코틀린의 suspend 함수를 이용해서 표시할 수 있다.
  • 코틀린에서는 context receivers를 이용하여 빌트인 디펜던시 인젝션, 컴파일타임 디펜던시 인젝션을 지원한다.

 

참고자료 :

https://arrow-kt.io/

 

Arrow

Idiomatic functional programming for Kotlin

arrow-kt.io

 

반응형