Skip to content

2week_AOS_tech_post_3

sey2 edited this page Jan 9, 2024 · 3 revisions

DI, Hilt ๋ฝ€๊ฐœ๊ธฐ


Hilt๋ž€?

์•ˆ๋“œ๋กœ์ด๋“œ ๊ฐœ๋ฐœ์„ ํ•ด๋ณด๋ฉด ์˜์กด์„ฑ ์ฃผ์ž…, ์˜์กด์„ฑ ์ฃผ์ž… ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ, Hilt ๊ฐ™์€ ๋‹จ์–ด๋“ค์„ ๋งŽ์ด ๋“ฃ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

์˜์กด์„ฑ์€ ๋˜ ๋ญ๊ณ , ๊ทธ๊ฑธ ๋˜ ์ฃผ์ž…??โ€ฆ Hilt๋Š” ๋˜ ๋ญ์•ผ ๋“ฃ๊ธฐ๋งŒ ํ•ด๋„ ๋จธ๋ฆฌ๊ฐ€ ์–ด์ง€๋Ÿฌ์›Œ ์ง€๋Š” ๊ธฐ๋ถ„์ด์—์š”~

์ž ~ ๊ทธ๋Ÿฌ๋ฉด ์ง€๊ธˆ๋ถ€ํ„ฐ ์ฒœ์ฒœํžˆ step by step์œผ๋กœ ํ•œ๋ฒˆ ์•Œ์•„๊ฐ€ ๋ด์š”!

์šฐ์„  Hilt ์˜์กด์„ฑ ์ฃผ์ž… ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์•Œ๊ธฐ ์ „์— ์˜์กด์„ฑ์ด ๋ญ”์ง€ ์•Œ์•„์•ผ ํ•  ํ•„์š”๊ฐ€ ์žˆ์–ด์š”

์ €ํฌ ํ•จ๊ป˜ ์˜์กด์„ฑ์ด ๋ญ”์ง€ ํ•จ๊ป˜ ์•Œ์•„๊ฐ€ ๋ณผ๊นŒ์š”?


DIP (Dependency Inversion Principle)

์˜์กด ์—ญ์ „์˜ ์›์น™์ด๋ผ๊ณ ๋„ ๋ถˆ๋ฆฌ๋Š” ์š”๋†ˆ์€ ์–ด๋””์„œ ๋‚˜์˜จ ๋ง์ผ๊นŒ์š”?

DIP๋Š” ๊ฐ์ฒด์ง€ํ–ฅ์„ค๊ณ„ 5์›์น™(SOLID)์—์„œ D์— ํ•ด๋‹นํ•˜๋Š” ์›์น™์ด๋ฉฐ ์˜์กด ์—ญ์ „์˜ ๋ฒ•์น™์ด๋ผ๊ณ ๋„ ํ•ฉ๋‹ˆ๋‹ค.

์˜์กด ์—ญ์ „์˜ ์›์น™

์˜์กด ๊ด€๊ณ„๋ฅผ ๋งบ์„์„ ๋•Œ ๋ณ€ํ•˜๊ธฐ ์‰ฌ์šด ๊ฒƒ์— ์˜์กดํ•˜๊ธฐ ๋ณด๋‹ค๋Š” ๋ณ€ํ™”ํ•˜์ง€ ์•Š๋Š” ๊ฒƒ์— ์˜์กดํ•˜๋ผ!

์œ„์˜ ๋ง์€ ์–ด๋–ค ์˜๋ฏธ๊ฐ€ ๋‹ด๊ฒจ ์žˆ์„๊นŒ์š”?

์˜ˆ๋ฅผ ๋“ค์–ด

์ €ํฌ๊ฐ€ ์‡ผํ•‘๋ฌผ์—์„œ ์‚ฌ์šฉ์ž๊ฐ€ ๋ฌผ๊ฑด์„ ๊ตฌ์ž…ํ•˜๋ฉด ๊ตฌ์ž…ํ•œ ๋‚ด์—ญ์„ ์•Œ๋ ค์ฃผ๊ธฐ ์œ„ํ•ด ์•Œ๋ฆผ ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ•œ๋‹ค๊ณ  ์ƒ๊ฐํ•ด ๋ด…์‹œ๋‹ค.

์ด๋ฉ”์ผ๋กœ ์‚ฌ์šฉ์ž์—๊ฒŒ ์•Œ๋ ค์ฃผ๊ธฐ๋กœ ๊ฒฐ์ •์„ ํ–ˆ๊ณ  ์•„๋ž˜์™€ ๊ฐ™์ด ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ ํ–ˆ์Šต๋‹ˆ๋‹ค

class EmailMessenger {
    fun sendNotification(message: String): String{
        println("Sending email: $message")
    }
}
class NotificationService {
    private val messenger = EmailMessenger()

    fun sendNotification() {
        messenger.sendNotification("๊ตฌ์ž… ๋‚ด์—ญ์— ๋Œ€ํ•ด ์•ˆ๋‚ด ๋“œ๋ฆฝ๋‹ˆ๋‹ค.")
    }
}

ํ•˜์ง€๋งŒ ๋ฌธ์ œ๊ฐ€ ์žˆ๋„ค์š”!

๋ฌธ์ž ์•Œ๋ฆผ ์„œ๋น„์Šค๋ฅผ ๋งŒ๋“ค์–ด ๋‹ฌ๋ผ๊ณ  ์š”์ฒญ์ด ๋“ค์–ด์˜ค๊ฑฐ๋‚˜ ์ด๋ฉ”์ผ ๋ฉ”์‹ ์ € ๊ธฐ๋Šฅ์„ ๋ฐ”๊ฟ”๋‹ฌ๋ฆฌ๋Š” ์š”๊ตฌ์‚ฌํ•ญ์ด ์ƒ๊ธฐ๋ฉด ์–ด๋–ป๊ฒŒ ๋ ๊นŒ์š”?

NotificationServiceย ํด๋ž˜์Šค๋Š”ย EmailMessengerย ํด๋ž˜์Šค์— ์˜์กด์„ฑ์„ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค๊ณ  ํ•  ์ˆ˜ ์žˆ๋Š”๋ฐย ,

EmailMessengerย ํด๋ž˜์Šค์— ๋ณ€ํ™”๊ฐ€ ์ƒ๊ธฐ๋ฉดย EmailMessengerย ํด๋ž˜์Šค๋ฅผ ์ฐธ์กฐํ•˜๋Š” ๋ชจ๋“  ํด๋ž˜์Šค๋ฅผ ์ˆ˜์ •ํ•ด์ค˜์•ผ ํ•˜๋Š” ์ƒํ™ฉ์ด ์ƒ๊ธฐ๊ฒ ์ฃ ?

ํ•œ๋ฒˆ์— ์ง๊ด€์ ์œผ๋กœ ์ดํ•ด๊ฐ€ ์•ˆ๋˜์‹œ์ฃ ? ์–ด๋–ค ์ƒํ™ฉ์ผ์ง€ ๊ถ๊ธˆํ•˜์‹ค๋ถ„ ๋“ค์ด ์žˆ์„ ๊ฒƒ ๊ฐ™์•„์š”

๋ฐฑ๋ฌธ๋ถˆ์—ฌ์ผ๊ฒฌ์ด๋ผ๋Š” ๋ง์ด ์žˆ๋“ฏ์ด ํ•จ๊ป˜ ์•„๋ž˜ ์˜ˆ์ œ๋ฅผ ํ•œ๋ฒˆ ๊ฐ™์ด ๋ด๋ณผ๊นŒ์š”?

์•„๋ž˜ ์˜ˆ์ œ ์ฒ˜๋Ÿผย EmailMessenger์˜ย sendNoticifationย ๋ฉ”์†Œ๋“œ๊ฐ€ ์ด์ œ ๋ฌธ์ž์—ด ๋งค๊ฐœ ๋ณ€์ˆ˜ ๋Œ€์‹  ๊ฐ์ฒด๋ฅผ ๋ฐ›๋„๋ก ๋ณ€๊ฒฝ ๋˜์—ˆ๋‹ค๊ณ  ๊ฐ€์ •ํ•ด ๋ด…์‹œ๋‹ค.

data class EmailMessage(val content: String, val id: Int)

class EmailMessenger {
    fun sendNotification(message: EmailMessage): String{
        println("Sending email: ${message.content}")
    }
}

NotificationService ํด๋ž˜์Šค์—์„œ๋Š” sendNoticifation() ๋ฉ”์†Œ๋“œ๋ฅผ ํ˜ธ์ถœํ•  ๋•Œ ๋ฌธ์ž์—ด ๋Œ€์‹  EmailMessenger ๊ฐ์ฒด๋ฅผ ์ „๋‹ฌํ•˜๋„๋ก

๋ณ€๊ฒฝํ•ด์•ผํ•ฉ๋‹ˆ๋‹ค.

class NotificationService {
    private val messenger = EmailMessenger()

    fun sendNotification() {
        messenger.sendNotification(EmailMessage("๊ตฌ์ž… ๋‚ด์—ญ์— ๋Œ€ํ•ด ์•ˆ๋‚ด ๋“œ๋ฆฝ๋‹ˆ๋‹ค.", 1))
    }
}

์Œ? ๊ทธ๋ƒฅ ๋ฐ”๊พธ๋ฉด ๋˜๋Š”๊ฑฐ ์•„๋‹Œ๊ฐ€?? ๋ผ๊ณ  ์ƒ๊ฐํ•˜์‹ค ์ˆ˜ ๋„ ์žˆ์–ด์š”!

์ด๋ ‡๊ฒŒ ๊ฐ„๋‹จํ•œ ์˜ˆ์ œ์—์„œ๋Š” ๊ทธ๋ƒฅ ๋ฐ”๊พธ๊ณ  ๋ง์ง€ ํ•˜๋Š”๋ฐ ๋งŒ์•ฝ NotificationService ํด๋ž˜์Šค์ฒ˜๋Ÿผ EmailMessenger ํด๋ž˜์Šค๋ฅผ ์˜์กดํ•˜๋Š” ํด๋ž˜์Šค๊ฐ€

์—„์ฒญ ๋งŽ์•„์ง„๋‹ค๋ฉด ์–ด๋–ป๊ฒŒ ํ• ๊นŒ์š”?

ํ”ผ ๊ฐ™์€ ์‹œ๊ฐ„์— ๊ทธ๊ฑธ ์ผ์ผ์ด ๋ฐ”๊พธ๊ณ  ์žˆ์œผ๋ฉด ๋ˆˆ๋ฌผ์ด ์ ˆ๋กœ ๋‚ ๊ฑฐ์—์š” ๐Ÿฅฒ

์ด๋ ‡๊ฒŒ ํ•˜๋‚˜์˜ ํด๋ž˜์Šค๊ฐ€ ๋‹ค๋ฅธ ํด๋ž˜์Šค์— ์˜์กดํ•˜๋Š” ๊ฒฝ์šฐ, ํ›„์ž๊ฐ€ ๋ณ€๊ฒฝ๋˜๋ฉด ์ „์ž๋„ ๊ทธ์— ๋”ฐ๋ผ ๋ณ€๊ฒฝํ•ด์•ผ ํ•˜๋Š” ์ƒํ™ฉ์ด ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ด๋Ÿฐ ์ƒํ™ฉ์„ ํ”ผํ•˜๊ธฐ ์œ„ํ•ด ์˜์กด์„ฑ ์ฃผ์ž…์„ ์‚ฌ์šฉํ•˜์—ฌ ํด๋ž˜์Šค ๊ฐ„์˜ ๊ฒฐํ•ฉ๋„๋ฅผ ๋‚ฎ์ถœ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ทธ๋Ÿฌ๋ฉด ์ฒซ ๋ฒˆ์งธ ์˜ˆ์ œ์˜ ์ฝ”๋“œ์— ๋Œ€ํ•ด ๋ฆฌํŒฉํ† ๋ง ๊ณผ์ •์„ ๊ฑฐ์ณ์„œ ์กฐ๊ธˆ ๋” ์œ ์ง€๋ณด์ˆ˜๊ฐ€ ์‰ฌ์šด ์ฝ”๋“œ๋กœ ์ž‘์„ฑํ•ด ๋ด…์‹œ๋‹ค!

์šฐ์„  ๊ณตํ†ต ๋ถ€๋ถ„์„ ์ถ”์ƒํ™”ํ•œ Interface๋ฅผ ๊ตฌํ˜„ํ•œ ๋’ค

interface Messenger {
    fun sendNotification()
}

๊ตฌํ˜„ ํด๋ž˜์Šค๋“ค์„ ๋งŒ๋“ค์–ด ์ค๋‹ˆ๋‹ค.

class EmailMessenger() : Messenger {
    override fun sendNotification(): String {
        return "Sending email:"
    }
}

class SMSMessenger() : Messenger {
    override fun sendNotification(): String {
        return "Sending SMS"
    }
}

๋น„์ง€๋‹ˆ์Šค ๋กœ์ง์„ ๋‹ด๋‹นํ•˜๋Š” ํด๋ž˜์Šค๋ฅผ ๋งŒ๋“ค์–ด ์ค€ ๋’ค

class NotificationService(private val messenger: Messenger) {
    fun sendNotification(message: String) {
        println(messenger.sendNotification() + message)
    }
}

์•„๋ž˜์™€ ๊ฐ™์ด ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

class NotificationServiceTest {
    @Test
    fun sendNotification_givenEmail_shouldReturnEmailMessage() {
        // Given
        val notificationService = NotificationService(EmailMessenger())

        // When
        val message = emailService.sendNotification("๊ตฌ์ž… ๋‚ด์—ญ์— ๋Œ€ํ•ด ์•ˆ๋‚ดํ•ด ๋“œ๋ฆฝ๋‹ˆ๋‹ค")

        // Then
        assertEquals("Sending email:๊ตฌ์ž… ๋‚ด์—ญ์— ๋Œ€ํ•ด ์•ˆ๋‚ดํ•ด ๋“œ๋ฆฝ๋‹ˆ๋‹ค", message);
    }

  @Test
   fun sendNotification_givenSms_shouldReturnSmsMessage() {
        // Given
        val notificationService = NotificationService(SMSMessenger())

        // When
        val message = notificationService.sendNotification("๊ตฌ์ž… ๋‚ด์—ญ์— ๋Œ€ํ•ด ์•ˆ๋‚ดํ•ด ๋“œ๋ฆฝ๋‹ˆ๋‹ค")

        // Then
        assertEquals("Sending SMS:๊ตฌ์ž… ๋‚ด์—ญ์— ๋Œ€ํ•ด ์•ˆ๋‚ดํ•ด ๋“œ๋ฆฝ๋‹ˆ๋‹ค", message);
    }
}

์œ„์™€ ๊ฐ™์€ ์„ค๊ณ„๋ฅผ ํ•˜๊ฒŒ ๋œ๋‹ค๋ฉด,

์™ธ๋ถ€์—์„œ EmailMessenger์˜ ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•ด NotificationService ํด๋ž˜์Šค ๊ฐ์ฒด๋ฅผ ๋งŒ๋“ค ๋•Œ ์ƒ์„ฑ์ž๋กœ ์ฃผ์ž…์„ ํ•ด์ฃผ๊ฒŒ ๋œ๋‹ค๋ฉด

EmailMessengerํด๋ž˜์Šค์— ์ˆ˜์ •์ด ์ผ์–ด๋‚˜๋”๋ผ๋„ NotificationServiceํด๋ž˜์Šค๋ฅผ ์ˆ˜์ •ํ•  ํ•„์š”๊ฐ€ ์—†๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

์œ„ ์ฒ˜๋Ÿผ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๋ฉด NotificationService ํด๋ž˜์Šค๋Š” ์ธ์ œ Messenger ์ธํ„ฐํŽ˜์ด์Šค์— ์˜์กดํ•˜๊ฒŒ ๋˜๋ฏ€๋กœ EmailMessenger ํด๋ž˜์Šค๋‚˜

SMSMessgenger ํด๋ž˜์Šค๊ณผ ๊ฐ™์€ ๋ณ€ํ•˜๊ธฐ ์‰ฌ์šด ํด๋ž˜์Šค ๋ณด๋‹ค ๋” ๋ณ€ํ•˜์ง€ ์•Š๋Š” Messenger ์ธํ„ฐํŽ˜์ด์Šค์— ์˜์กดํ•˜๊ฒŒ ๋˜๋ฏ€๋กœ ์ฝ”๋“œ์˜ ์œ ์—ฐ์„ฑ์ด ๋†’์•„์ง€๊ฒŒ ๋˜์—ˆ๋„ค์š”.

Messenger ์ธํ„ฐํŽ˜์ด์Šค์˜ ๊ตฌํ˜„์ด ์ถ”๊ฐ€ ๋˜๋”๋ผ๋„ NotificationService ํด๋ž˜์Šค๋ฅผ ๋ณ€๊ฒฐํ•  ํ•„์š”๊ฐ€ ์—†์–ด์กŒ์Šต๋‹ˆ๋‹ค.

DI๋ฅผ ํ•˜๋Š” ์ด์œ ๋‚˜ ์žฅ์ ์€ ๋ญ˜๊นŒ์š”?

  • boilerplate code๋ฅผ ์ค„์—ฌ์ฃผ๋ฏ€๋กœ ์œ ์—ฐํ•œ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์ด ๊ฐ€๋Šฅํ•ด ์ง‘๋‹ˆ๋‹ค.
  • ์žฌ์‚ฌ์šฉ์„ฑ์ด ๋†’์•„์ง€๊ณ  ์œ ์ง€๋ณด์ˆ˜๊ฐ€ ๋” ์‰ฌ์›Œ์ง‘๋‹ˆ๋‹ค.
  • ๋” ํŽธํ•œ ์œ ๋‹› ํ…Œ์ŠคํŠธ๊ฐ€ ๊ฐ€๋Šฅํ•ด์ง‘๋‹ˆ๋‹ค.
  • ๊ฒฐํ•ฉ๋„๋ฅผ ๋‚ฎ์ถ”์–ด์„œ ํ™•์žฅ์„ฑ์„ ๋†’์—ฌ ์ค๋‹ˆ๋‹ค.

Hilt?

๊ทธ๋ ‡๋‹ค๋ฉด ์˜์กด์„ฑ ์—ญ์ „์˜ ๋ฒ•์น™์— ๋Œ€ํ•ด ์•Œ์•„ ๋ดค์œผ๋‹ˆ ์ด๊ฒƒ์„ ์กฐ๊ธˆ ๋” ์‰ฝ๊ฒŒ ๊ตฌํ˜„ํ•ด์ฃผ๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ Hilt์— ๋Œ€ํ•ด ํ•จ๊ป˜ ์•Œ์•„๋ด์š”

Hilt๋Š” Android์—์„œ Dependency Injection๋ฅผ ์‰ฝ๊ฒŒ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๋„๋ก ๋•๋Š” ๋„๊ตฌ์ž…๋‹ˆ๋‹ค.

ํ•„์š”ํ•œ ์˜์กด์„ฑ์„ ์ œ๊ณตํ•˜๋Š” **Module**์„ ์ž‘์„ฑํ•˜๊ณ , ํ•„์š”ํ•œ ๊ณณ์— @Inject ์ฃผ์„์„ ์‚ฌ์šฉํ•˜์—ฌ ์˜์กด์„ฑ์„ ์ฃผ์ž…๋ฐ›์Šต๋‹ˆ๋‹ค.

Hilt๋Š” ์ด๋Ÿฌํ•œ ์ž‘์—…์„ ์ž๋™ํ™”ํ•˜์—ฌ ์ฝ”๋“œ๋ฅผ ๊น”๋”ํ•˜๊ฒŒ ์œ ์ง€ํ•˜๊ณ  ํ…Œ์ŠคํŠธ๋ฅผ ์šฉ์ดํ•˜๊ฒŒ ํ•ด์ค๋‹ˆ๋‹ค.

๊ทธ๋Ÿผ Hilt๋ฅผ ์‚ฌ์šฉํ–ˆ์„ ๋•Œ์™€ ์‚ฌ์šฉํ•˜์ง€ ์•Š์•˜์„ ๋•Œ์˜ ์˜ˆ์ œ๋ฅผ ํ•œ๋ฒˆ ๋ด๋ณผ๊นŒ์š”?

Hilt๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ณ  ์ƒ์„ฑ์ž ์ฃผ์ž…์„ ํ†ตํ•ด ์˜์กด์„ฑ์„ ์ฃผ์ž… ํ•˜๋Š” ๊ฒฝ์šฐ

class CarRepository(private val apiService: ApiService) {
    // ...
}
class MainActivity : AppCompatActivity() {
    
    // ์ง์ ‘ ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•˜์—ฌ ์ฃผ์ž…
    private val apiService = ApiService()
    private val userRepository = UserRepository(apiService)
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        // ...
    }
}

Hilt๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ

@Module
@InstallIn(SingletonComponent::class)
object AppModule {

    @Provides
    @Singleton
    fun provideApiService(): ApiService {
        return ApiService()
    }
}
class CarRepository @Inject constructor(private val apiService: ApiService) {
    // ...
}
@AndroidEntryPoint
class MainActivity : AppCompatActivity() {
    
    // Hilt๋ฅผ ํ†ตํ•ด ์ž๋™์œผ๋กœ ์˜์กด์„ฑ ์ฃผ์ž…
    @Inject
    lateinit var userRepository: UserRepository
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        // ...
    }
}
  • ์œ„ ์˜ˆ์ œ์—์„œ ๋ณด์ด๋“ฏ์ด Hilt๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ApiService ์ธ์Šคํ„ด์Šค ์ƒ์„ฑ ๋ฐ **CarRepository**์— ์ฃผ์ž…ํ•˜๋Š” ์ฝ”๋“œ๋ฅผ ๋ช…์‹œ์ ์œผ๋กœ ์ž‘์„ฑํ•  ํ•„์š”๊ฐ€ ์—†์–ด์ง‘๋‹ˆ๋‹ค.
  • Hilt๋Š” ์˜์กด์„ฑ ์ฃผ์ž… ์ฝ”๋“œ๋ฅผ ๊ฐ„์†Œํ™”ํ•˜๊ณ  ์ž๋™ํ™” ํ•จ์œผ๋กœ์จ ์ฝ”๋“œ์˜ ๋ณต์žก์„ฑ์„ ์ค„์—ฌ์ฃผ๊ณ  ๊ด€๋ฆฌ๋ฅผ ๋” ์‰ฝ๊ฒŒ ํ•ด์ค๋‹ˆ๋‹ค.

Hilt ์‚ฌ์šฉ ์˜ˆ

**Applicationย ํด๋ž˜์Šค์— Hilt ์ดˆ๊ธฐํ™”**

@HiltAndroidApp
class CarArtApplication : Application()

CarExteriorImageRepository๋ฅผ ์ œ๊ณตํ•˜๋Š” ๋ชจ๋“ˆ์„ ์ž‘์„ฑ (Optional)

  • RepositoryModule ํด๋ž˜์Šค๋Š” Hilt๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์˜์กด์„ฑ ์ฃผ์ž…์„ ์„ค์ •ํ•  ๋•Œ ์‚ฌ์šฉ๋˜๋Š” ๋ชจ๋“ˆ ํด๋ž˜์Šค์ž…๋‹ˆ๋‹ค.
  • Hilt์˜ ๋ชจ๋“ˆ์€ ์˜์กด์„ฑ ๊ทธ๋ž˜ํ”„์— ๊ฐ์ฒด๋ฅผ ์ œ๊ณตํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์ •์˜ํ•ฉ๋‹ˆ๋‹ค.
  • ์ฆ‰, ์–ด๋–ค ํƒ€์ž…์˜ ๊ฐ์ฒด๋ฅผ ์š”์ฒญํ•  ๋•Œ ์–ด๋–ค ๊ตฌํ˜„์ฒด ๋˜๋Š” ์ธ์Šคํ„ด์Šค๋ฅผ ์ œ๊ณตํ•ด์•ผ ํ•˜๋Š”์ง€ Hilt์— ์•Œ๋ ค์ฃผ๋Š” ์—ญํ• ์„ ํ•ฉ๋‹ˆ๋‹ค.
  • ๋ชจ๋“ˆ ํด๋ž˜์Šค๋ฅผ ์–ธ์ œ ์ž‘์„ฑํ•˜๋Š”์ง€?
    • ๋ชจ๋“ˆ ํด๋ž˜์Šค๊ฐ€ ํ•„์š” ์—†๋Š” ๊ฒฝ์šฐ

      ๋‹จ์ˆœํ•œ ์˜์กด์„ฑ (์ƒ์„ฑ์ž ์ฃผ์ž… ๊ฐ€๋Šฅ):

      ๋‹จ์ˆœํ•œ ์˜์กด์„ฑ์€ ์ฃผ๋กœ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ํŠน์ง•์„ ๊ฐ–์Šต๋‹ˆ๋‹ค.

      • ํด๋ž˜์Šค์˜ ์ƒ์„ฑ์ž๊ฐ€ ๋‹ค๋ฅธ ์˜์กด์„ฑ ์—†์ด ์‰ฝ๊ฒŒ ์ธ์Šคํ„ด์Šคํ™”๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
      • ํด๋ž˜์Šค์˜ ์ƒ์„ฑ์ž์— ํ•„์š”ํ•œ ํŒŒ๋ผ๋ฏธํ„ฐ๋“ค์ด ์ด๋ฏธ Hilt์— ์˜ํ•ด ์ œ๊ณต๋  ์ˆ˜ ์žˆ๋Š” ํƒ€์ž…์ด๊ฑฐ๋‚˜, ๊ทธ ์ž์ฒด๋กœ ์ฃผ์ž… ๊ฐ€๋Šฅํ•œ ๋‹ค๋ฅธ ํด๋ž˜์Šค๋“ค์ž…๋‹ˆ๋‹ค.

      ์˜ˆ์ œ:

      kotlinCopy code
      class UserService @Inject constructor(private val api: UserApi) {
          // ์—ฌ๊ธฐ์„œ UserApi๋Š” Hilt๊ฐ€ ์•Œ๊ณ  ์žˆ๋Š” ํƒ€์ž…์ด๊ฑฐ๋‚˜ ๋‹ค๋ฅธ ๊ณณ์—์„œ ์ฃผ์ž…๋  ์ˆ˜ ์žˆ๋Š” ํƒ€์ž…์ด์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
      }

      ์œ„์˜ **UserService**๋Š” UserApi ํƒ€์ž…๋งŒ ํ•„์š”๋กœ ํ•˜๋ฉฐ, ์ด **UserApi**๊ฐ€ Hilt์— ์˜ํ•ด ์ด๋ฏธ ์ฃผ์ž… ๊ฐ€๋Šฅํ•œ ํƒ€์ž…์ด๋ผ๋ฉด, **UserService**๋Š” ์ž๋™์œผ๋กœ ์ฃผ์ž…๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค

    • ๋ชจ๋“ˆ ํด๋ž˜์Šค๊ฐ€ ํ•„์š”ํ•œ ๊ฒฝ์šฐ

      ๋ณต์žกํ•œ ์˜์กด์„ฑ (๋ชจ๋“ˆ์ด ํ•„์š”ํ•œ ๊ฒฝ์šฐ):

      ๋ณต์žกํ•œ ์˜์กด์„ฑ์€ ์ฃผ๋กœ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ํŠน์ง•์„ ๊ฐ–์Šต๋‹ˆ๋‹ค.

      • ์ธ์Šคํ„ด์Šค ์ƒ์„ฑ์— ํŠน๋ณ„ํ•œ ์กฐ๊ฑด์ด๋‚˜ ๋กœ์ง์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.
      • ์„ค์ • ๊ฐ’, ํ™˜๊ฒฝ ๊ฐ’, ํ”Œ๋ž˜๊ทธ ๋“ฑ์— ๋”ฐ๋ผ ๋‹ค๋ฅด๊ฒŒ ์ƒ์„ฑ๋˜์–ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.
      • ํŠน์ • ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌํ˜„ํ•˜๋Š” ์—ฌ๋Ÿฌ ๊ตฌํ˜„์ฒด ์ค‘์—์„œ ํ•˜๋‚˜๋ฅผ ์„ ํƒํ•ด์•ผ ํ•  ๋•Œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

      ์˜ˆ์ œ

      kotlinCopy code
      @Module
      @InstallIn(SingletonComponent::class)
      object NetworkModule {
          @Provides
          fun provideApiService(@Named("apiUrl") apiUrl: String): ApiService {
              return Retrofit.Builder()
                  .baseUrl(apiUrl)
                  .addConverterFactory(GsonConverterFactory.create())
                  .build()
                  .create(ApiService::class.java)
          }
      }
      

      ์œ„์˜ ์˜ˆ์ œ์—์„œ **ApiService**์˜ ์ƒ์„ฑ์€ Retrofit ์„ค์ •๊ณผ ํ•จ๊ป˜ ํŠน์ • URL์— ๊ธฐ๋ฐ˜ํ•˜์—ฌ ์ด๋ฃจ์–ด์ง€๊ธฐ ๋•Œ๋ฌธ์—, ๋‹จ์ˆœํ•œ ์ƒ์„ฑ์ž ์ฃผ์ž…๋งŒ์œผ๋กœ๋Š” ์ฒ˜๋ฆฌํ•˜๊ธฐ ์–ด๋ ต์Šต๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ @Provides ์–ด๋…ธํ…Œ์ด์…˜์ด ๋ถ™์€ ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ **ApiService**์˜ ์ธ์Šคํ„ด์Šค ์ƒ์„ฑ ๋ฐฉ๋ฒ•์„ ์ง€์ •ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

    • ๋‹จ์ˆœํ•œ ์˜์กด์„ฑ์€ Hilt๊ฐ€ ์ด๋ฏธ ์•Œ๊ณ  ์žˆ๋Š” ํƒ€์ž…๋“ค๋งŒ์„ ์ƒ์„ฑ์ž์˜ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ์‚ฌ์šฉํ•˜๋ฏ€๋กœ, ๊ทธ๋ƒฅ @Inject ์–ด๋…ธํ…Œ์ด์…˜์„ ๋ถ™์—ฌ์ฃผ๋ฉด ๋ฉ๋‹ˆ๋‹ค.

    • ๋ณต์žกํ•œ ์˜์กด์„ฑ์€ ํŠน์ •ํ•œ ๋กœ์ง์ด๋‚˜ ์„ค์ •์— ๋”ฐ๋ผ ๊ฐ์ฒด๊ฐ€ ์ƒ์„ฑ๋˜์–ด์•ผ ํ•  ๋•Œ ๋ฐœ์ƒํ•˜๋ฉฐ, ์ด๋Ÿฐ ๊ฒฝ์šฐ์—๋Š” ๋ชจ๋“ˆ ๋‚ด์˜ @Provides ๋ฉ”์„œ๋“œ๋ฅผ ํ†ตํ•ด ์ธ์Šคํ„ด์Šค ์ƒ์„ฑ ๋ฐฉ๋ฒ•์„ ์ง€์ •ํ•ด์ค˜์•ผ ํ•ฉ๋‹ˆ๋‹ค.

  • ์–ด๋–ค ๊ธฐ์ค€์œผ๋กœ ๋ชจ๋“ˆ ํด๋ž˜์Šค๋ฅผ ๋‚˜๋ˆ ์•ผํ•˜์ง€?
    1. ๊ธฐ๋Šฅ ๋ณ„: ๊ฐ ๊ธฐ๋Šฅ์ด๋‚˜ ํ™”๋ฉด(์˜ˆ: ๋กœ๊ทธ์ธ, ์‚ฌ์šฉ์ž ํ”„๋กœํ•„, ์ฃผ๋ฌธ ๋“ฑ)์— ๋Œ€ํ•ด ๋ณ„๋„์˜ ๋ชจ๋“ˆ๋กœ ๋ถ„๋ฆฌ
    2. ๊ณ„์ธต ๋ณ„: ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ์•„ํ‚คํ…์ฒ˜ ๊ณ„์ธต(์˜ˆ: ๋ฐ์ดํ„ฐ, ๋„๋ฉ”์ธ, ํ”„๋ ˆ์  ํ…Œ์ด์…˜)์— ๋”ฐ๋ผ ๋ชจ๋“ˆ์„ ๋ถ„๋ฆฌ
    3. ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๋ณ„: ์„œ๋“œํŒŒํ‹ฐ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๋˜๋Š” ํŠน์ • ํ”„๋ ˆ์ž„์›Œํฌ์™€ ๊ด€๋ จ๋œ ์˜์กด์„ฑ์„ ์ œ๊ณตํ•˜๋Š” ๋ชจ๋“ˆ์„ ๋งŒ๋“ญ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, Retrofit ๊ด€๋ จ ์˜์กด์„ฑ์„ ์ œ๊ณตํ•˜๋Š” **NetworkModule**์ด๋‚˜, Room ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ๊ด€๋ จ ์˜์กด์„ฑ์„ ์ œ๊ณตํ•˜๋Š” **DatabaseModule**์„ ์ƒ๊ฐํ•ด๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
    4. ์Šค์ฝ”ํ”„ ๋ณ„: ํŠน์ • ์Šค์ฝ”ํ”„(์˜ˆ: ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜, ์•กํ‹ฐ๋น„ํ‹ฐ, ํ”„๋ž˜๊ทธ๋จผํŠธ ๋“ฑ)์— ๋Œ€ํ•œ ์˜์กด์„ฑ๋งŒ์„ ์ œ๊ณตํ•˜๋Š” ๋ชจ๋“ˆ์„ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค. SingletonModule, ActivityModule, **FragmentModule**๊ณผ ๊ฐ™์€ ์ด๋ฆ„์œผ๋กœ ๋„ค์ด๋ฐ ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
    5. ํ™˜๊ฒฝ ๋ณ„: ๊ฐœ๋ฐœ, ์Šคํ…Œ์ด์ง•, ํ”„๋กœ๋•์…˜๊ณผ ๊ฐ™์€ ๋‹ค๋ฅธ ํ™˜๊ฒฝ์— ๋”ฐ๋ผ ๋‹ค๋ฅด๊ฒŒ ๋™์ž‘ํ•ด์•ผ ํ•˜๋Š” ์˜์กด์„ฑ์ด ์žˆ๋Š” ๊ฒฝ์šฐ, ๊ฐ ํ™˜๊ฒฝ์— ๋งž๋Š” ๋ชจ๋“ˆ์„ ๋งŒ๋“ญ๋‹ˆ๋‹ค.
    6. ํ…Œ์ŠคํŠธ์šฉ ๋ชจ๋“ˆ: ํ…Œ์ŠคํŠธ ์‹œ ์‚ฌ์šฉํ•˜๋Š” ์˜์กด์„ฑ์„ ์ œ๊ณตํ•˜๋Š” ๋ชจ๋“ˆ์„ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ์‹ค์ œ ์šด์˜ ํ™˜๊ฒฝ๊ณผ๋Š” ๋‹ค๋ฅธ ๋ชจ์˜(Mock) ๊ฐ์ฒด๋‚˜ ๊ฐ€์งœ(Fake) ๊ฐ์ฒด๋ฅผ ์ฃผ์ž…ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
@Module
@InstallIn(SingletonComponent::class)
object RepositoryModule {
    
    @Provides
    @Singleton
    fun provideCarExteriorImageRepository(): CarExteriorImageRepository {
        return CarExteriorImageRepository()
    }
    
    // ... ๊ธฐํƒ€ ์ œ๊ณต ๋ฉ”์„œ๋“œ ...
}

ViewModel์—์„œ ์˜์กด์„ฑ ์ฃผ์ž…ํ•˜๊ธฐ

class CarColorChoiceViewModel @Inject constructor(
    private val imageRepository: CarExteriorImageRepository
) : ViewModel() {
    // ... ๋‚˜๋จธ์ง€ ์ฝ”๋“œ๋Š” ๊ทธ๋Œ€๋กœ ์œ ์ง€ ...
}

Fragment์—์„œ ๋ทฐ ๋ชจ๋ธ ์ฃผ์ž…

import dagger.hilt.android.AndroidEntryPoint
import javax.inject.Inject

@AndroidEntryPoint
class CarColorChoiceFragment() : Fragment(), OnOtherColorItemClickListener {
    private var _binding: FragmentCarColorChoiceBinding? = null
    private val binding get() = _binding!!
    
    // ViewModel ์ฃผ์ž…
    private val carColorChoiceViewModel by viewModels<CarColorChoiceViewModel>()

    // ... ๋‚˜๋จธ์ง€ ์ฝ”๋“œ ...

}

Hilt ์–ด๋…ธํ…Œ์ด์…˜

  1. @Singleton:
    • ์ด ์ฃผ์„์€ ํ•ด๋‹น ์˜์กด์„ฑ์ด ์‹ฑ๊ธ€ํ„ด์œผ๋กœ ๋™์ž‘ํ•ด์•ผ ํ•จ์„ ๋‚˜ํƒ€๋ƒ…๋‹ˆ๋‹ค. ์ฆ‰, ํ•ด๋‹น ๊ฐ์ฒด๋Š” ์•ฑ์˜ ์ƒ๋ช…์ฃผ๊ธฐ ๋™์•ˆ ํ•˜๋‚˜๋งŒ ์ƒ์„ฑ๋˜๋ฉฐ ์—ฌ๋Ÿฌ ๋ฒˆ ์š”์ฒญ๋˜์–ด๋„ ๋™์ผํ•œ ์ธ์Šคํ„ด์Šค๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.
    • ์˜ˆ๋ฅผ ๋“ค์–ด, ์–ด๋–ค ์„œ๋น„์Šค๋‚˜ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์™€ ๊ฐ™์€ ๊ฐ์ฒด๊ฐ€ ์•ฑ ์ „์ฒด์—์„œ ํ•˜๋‚˜๋งŒ ์กด์žฌํ•ด์•ผ ํ•  ๋•Œ ์œ ์šฉํ•˜๊ฒŒ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.
  2. @Provides:
    • @Provides ์ฃผ์„์€ Hilt์—๊ฒŒ ์–ด๋–ป๊ฒŒ ํŠน์ • ํƒ€์ž…์˜ ์ธ์Šคํ„ด์Šค๋ฅผ ์ œ๊ณตํ•ด์•ผ ํ•˜๋Š”์ง€ ์•Œ๋ ค์ค๋‹ˆ๋‹ค. ์ด ์ฃผ์„์ด ๋‹ฌ๋ฆฐ ๋ฉ”์„œ๋“œ๋Š” ํ•ด๋‹น ํƒ€์ž…์˜ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.
    • @Module ๋‚ด๋ถ€์—์„œ ์‚ฌ์šฉ๋˜๋ฉฐ, ํ•„์š”ํ•  ๋•Œ๋งˆ๋‹ค Hilt์— ์˜ํ•ด ํ˜ธ์ถœ๋˜์–ด ํ•ด๋‹น ํƒ€์ž…์˜ ์ธ์Šคํ„ด์Šค๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.
  3. @Module:
    • @Module ์ฃผ์„์€ ํ•ด๋‹น ํด๋ž˜์Šค๊ฐ€ Hilt ๋ชจ๋“ˆ์ž„์„ ๋‚˜ํƒ€๋ƒ…๋‹ˆ๋‹ค. ๋ชจ๋“ˆ์€ ์˜์กด์„ฑ ์ฃผ์ž…์„ ์œ„ํ•ด ๊ฐ์ฒด๋ฅผ ์ œ๊ณตํ•˜๋Š” ๋ฉ”์„œ๋“œ๋“ค์˜ ์ง‘ํ•ฉ์ž…๋‹ˆ๋‹ค.
    • Hilt๋Š” ์ด ๋ชจ๋“ˆ์„ ์‚ฌ์šฉํ•˜์—ฌ ํ•„์š”ํ•œ ์˜์กด์„ฑ๋“ค์„ ์–ด๋–ป๊ฒŒ ์ƒ์„ฑํ•˜๊ณ  ์ œ๊ณตํ•ด์•ผ ํ•˜๋Š”์ง€ ์•Œ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.
  4. @InstallIn:
    • @InstallIn ์ฃผ์„์€ ๋ชจ๋“ˆ์ด ์–ด๋Š ์ปดํฌ๋„ŒํŠธ์— ์„ค์น˜๋˜์–ด์•ผ ํ•˜๋Š”์ง€ ์ง€์ •ํ•ฉ๋‹ˆ๋‹ค.
    • ์˜ˆ๋ฅผ ๋“ค์–ด, **@InstallIn(SingletonComponent::class)**์€ ํ•ด๋‹น ๋ชจ๋“ˆ์ด Singleton ์Šค์ฝ”ํ”„๋ฅผ ๊ฐ€์ง„ ์ปดํฌ๋„ŒํŠธ์— ์„ค์น˜๋˜์–ด์•ผ ํ•จ์„ ๋‚˜ํƒ€๋ƒ…๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ์ด ๋ชจ๋“ˆ์— ์žˆ๋Š” @Provides ๋ฉ”์„œ๋“œ๋“ค์ด ์ œ๊ณตํ•˜๋Š” ์˜์กด์„ฑ๋“ค์€ ์‹ฑ๊ธ€ํ„ด์œผ๋กœ ๋™์ž‘ํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค.
  5. @AndroidEntryPoint:
    • Hilt๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ Android ํด๋ž˜์Šค์— ์˜์กด์„ฑ์„ ์ฃผ์ž…ํ•˜๊ธฐ ์œ„ํ•œ ์ฃผ์„์ž…๋‹ˆ๋‹ค. ์ด ์ฃผ์„์„ Activity๋‚˜ Fragment์™€ ๊ฐ™์€ Android ์ปดํฌ๋„ŒํŠธ์— ๋ถ™์ด๋ฉด, Hilt๋Š” ๊ทธ ์ปดํฌ๋„ŒํŠธ์— ํ•„์š”ํ•œ ์˜์กด์„ฑ์„ ์ž๋™์œผ๋กœ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.
    • ์˜ˆ๋ฅผ ๋“ค๋ฉด, **@AndroidEntryPoint**๊ฐ€ ๋ถ™์€ Fragment์—์„œ๋Š” Hilt๊ฐ€ ํ•ด๋‹น Fragment์— ํ•„์š”ํ•œ ๊ฐ์ฒด๋“ค์„ ์•Œ์•„์„œ ์ฃผ์ž…ํ•ด์ค๋‹ˆ๋‹ค.

๐Ÿ“šRefernece

Hilt๋ฅผ ์‚ฌ์šฉํ•œ ์ข…์† ํ•ญ๋ชฉ ์‚ฝ์ž… ย |ย  Android ๊ฐœ๋ฐœ์ž ย |ย  Android Developers

Hilt๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์•ˆ๋“œ๋กœ์ด๋“œ MVVM ์•„ํ‚คํ…์ณ ๊ตฌํ˜„ํ•˜๊ธฐ

๐Ÿ’ป Projects

๐Ÿค Rules

โ˜€๏ธ Meetings

๐ŸŒต Reviews

1์ฃผ์ฐจ
2์ฃผ์ฐจ
3์ฃผ์ฐจ
4์ฃผ์ฐจ

๐ŸŒˆ Scrums

1์ฃผ์ฐจ
2์ฃผ์ฐจ
3์ฃผ์ฐจ
4์ฃผ์ฐจ

๐Ÿ›  Tech Posts & Mini seminar

๐Ÿ’ช๐Ÿผ [BE]

๐Ÿ›ค [FE]

๐Ÿ›ธ [AOS]


Clone this wiki locally