๐ Kotlin Flow์์ ์ค๋ณต๋๋ DTO-Domain ๋งคํ ์ค์ด๊ธฐ
Kotlin Flow๋ฅผ ์ฌ์ฉํ ๋, API๋ก๋ถํฐ ๋ฐ์ ๋ฐ์ดํฐ๋ฅผ DTO๋ก ํ์ฑํ ํ ์ด๋ฅผ Domain ๊ฐ์ฒด๋ก ๋ณํํ์ฌ ์ฌ์ฉํ๋ ๊ฒ์ด ์ผ๋ฐ์ ์ธ ํจํด์ ๋๋ค. ์ด๋ฌํ ๊ณ์ธต ๋ถ๋ฆฌ๋ ์ฝ๋์ ํ์ง์ ๋์ด๊ณ ์๊ธฐ์น ์์ ๋์์ ๋ฐฉ์งํ๋ ๋ฐ ๋์์ด ๋ฉ๋๋ค.
๊ทธ๋ฌ๋ Flow ๋ด์์ ๋งค๋ฒ map ์ฐ์ฐ์๋ฅผ ์ฌ์ฉํ์ฌ DTO๋ฅผ Domain์ผ๋ก ๋ณํํ๋ ๊ฒ์ ๋ฐ๋ณต์ ์ด๊ณ ์ค๋ณต๋ ์์ ์ด ๋ ์ ์์ต๋๋ค. ์ด๋ฅผ ๊ฐ์ ํ๊ธฐ ์ํด ๋ค์ํ ๋ฐฉ๋ฒ์ ์๋ํด๋ณด์์ต๋๋ค.
๐งช ์๋ #1: ์ธํฐํ์ด์ค๋ฅผ ํ์ฉํ ์ผ๋ฐํ
๋จผ์ , DTO ํด๋์ค์ asDomain ํจ์๋ฅผ ๊ตฌํํ๊ณ ์ด๋ฅผ ์ธํฐํ์ด์ค๋ก ์ถ์ํํฉ๋๋ค.
interface DomainConvertible<Domain> {
fun asDomain(): Domain
}
๊ทธ๋ฐ ๋ค์, Flow์ ๋ํ ํ์ฅ ํจ์๋ฅผ ๋ง๋ค์ด ๋ชจ๋ DTO-Domain ๋ณํ์ ์ฌ์ฉํ ์ ์์ต๋๋ค.
fun <T : DomainConvertible<R>, R> Flow<T>.mapToDomain(): Flow<R> = transform { emit(it.asDomain()) }
์ฅ์ :
- ๋ชจ๋ DTO ํด๋์ค์ asDomain ๊ตฌํ์ ๊ฐ์ ํ์ฌ ์ผ๊ด์ฑ์ ์ ์งํ ์ ์์ต๋๋ค.
- ์ผ๋ฐํ๋ ์ฐ์ฐ์๋ฅผ ํตํด ์ฝ๋ ์ค๋ณต์ ์ค์ผ ์ ์์ต๋๋ค.
๋จ์ :
- ๋ชจ๋ DTO ํด๋์ค์ ์ธํฐํ์ด์ค๋ฅผ ๊ตฌํํด์ผ ํ๋ฏ๋ก ์ฝ๋๊ฐ ๋ณต์กํด์ง ์ ์์ต๋๋ค.
- ๋งคํ ํจ์๊ฐ DTO ํด๋์ค ๋ด๋ถ์ ์์นํ์ฌ ๊ฐ๋ ์ฑ์ด ๋จ์ด์ง ์ ์์ต๋๋ค.
๐งช ์๋ #2: ํ์ฅ ํจ์๋ฅผ ํ์ฉํ ๋ถ๋ฆฌ
์ธํฐํ์ด์ค๋ฅผ ์ฌ์ฉํ์ง ์๊ณ , DTO์ Flow์ ๋ํ ํ์ฅ ํจ์๋ฅผ ๋ณ๋์ ํ์ผ์ ์ ์ํ์ฌ ๋งคํ ๋ก์ง์ ๋ถ๋ฆฌํ ์ ์์ต๋๋ค.
fun UserDto.asDomain(): User {
return User(id = id ?: 0, name = name ?: "")
}
fun Flow<UserDto>.mapToDomain(): Flow<User> = map { it.asDomain() }
์ฅ์ :
- ๋งคํ ๋ก์ง์ DTO ํด๋์ค ์ธ๋ถ์ ์ ์ํ์ฌ ๊ฐ๋ ์ฑ์ด ํฅ์๋ฉ๋๋ค.
- ํ์ํ ๊ฒฝ์ฐ์๋ง ํ์ฅ ํจ์๋ฅผ ์ ์ํ์ฌ ์ ์ฐํ๊ฒ ์ฌ์ฉํ ์ ์์ต๋๋ค.
๋จ์ :
- ๋ชจ๋ DTO์ ๋ํด ๋ณ๋์ ํ์ฅ ํจ์๋ฅผ ์์ฑํด์ผ ํ๋ฏ๋ก ๊ด๋ฆฌ๊ฐ ๋ฒ๊ฑฐ๋ก์ธ ์ ์์ต๋๋ค.
๐งช ์๋ #3: ์ ๋ค๋ฆญ์ ํ์ฉํ ๋จ์ผ ํ์ฅ ํจ์
๋ชจ๋ DTO-Domain ๋ณํ์ ํ๋์ ์ ๋ค๋ฆญ ํ์ฅ ํจ์๋ก ์ฒ๋ฆฌํ ์ ์์ต๋๋ค.
inline fun <reified T, R> Flow<T>.mapToDomain(): Flow<R> = map {
when (T::class) {
UserDto::class -> (it as UserDto).asDomain() as R
// ๋ค๋ฅธ DTO-Domain ๋งคํ ์ถ๊ฐ
else -> throw IllegalArgumentException("Unknown type")
}
}
์ฅ์ :
- ๋จ์ผ ํ์ฅ ํจ์๋ก ๋ชจ๋ DTO-Domain ๋ณํ์ ์ฒ๋ฆฌํ ์ ์์ต๋๋ค.
- ์ฝ๋ ์ค๋ณต์ ์ต์ํํ ์ ์์ต๋๋ค.
๋จ์ :
- ํด๋์ค ํ์ ์ ๋ช ์์ ์ผ๋ก ํ์ธํด์ผ ํ๋ฏ๋ก ์ ์ง๋ณด์๊ฐ ์ด๋ ค์ธ ์ ์์ต๋๋ค.
- ์๋ก์ด DTO-Domain ๋งคํ์ ์ถ๊ฐํ ๋๋ง๋ค when ์ ์ ์์ ํด์ผ ํฉ๋๋ค.
โ ๊ฒฐ๋ก
๊ฐ ์ ๊ทผ ๋ฐฉ์์ ์ฅ๋จ์ ์ด ์์ผ๋ฉฐ, ํ๋ก์ ํธ์ ๊ท๋ชจ์ ํ์ ์ ํธ๋์ ๋ฐ๋ผ ์ ์ ํ ๋ฐฉ๋ฒ์ ์ ํํ๋ ๊ฒ์ด ์ค์ํฉ๋๋ค. ์ฐ๋ฆฌ ํ์ ๊ฒฐ๊ตญ ๊ฐ์ฅ ๋จ์ํ map ์ฐ์ฐ์์ DTO์ ๋ํ ํ์ฅ ํจ์๋ฅผ ์ฌ์ฉํ๋ ๋ฐฉ๋ฒ์ ์ ํํ์ต๋๋ค. ์ด ๋ฐฉ๋ฒ์ ๋ช ์์ ์ด๊ณ ์ดํดํ๊ธฐ ์ฌ์ฐ๋ฉฐ, ์ ์ง๋ณด์ ์ธก๋ฉด์์๋ ์ ๋ฆฌํ๋ค๊ณ ํ๋จํ์ต๋๋ค.
๐ ์ถ์ฒ
Florent Blot, Redundant DTO-Domain Mapping in Kotlin Flow (Medium)