๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
๐Ÿค2024 ์•ˆ๋“œ๋กœ์ด๋“œ/๐Ÿฟ ์˜ํ™” ํ”„๋กœ์ ํŠธ ๊ฐœ๋ฐœ ์ผ์ง€

[์„œ๋ฒ„ ํ˜ธ์ถœ ์„ฑ๊ณต ์‹คํŒจ ์ฒ˜๋ฆฌ ] ๋ชจ์กฐ๋ฆฌ ์ˆ˜์ •ํ•˜๊ธฐ !!!!

by hyeonha 2024. 11. 29.

๋ชฉ์ฐจ

    ๋ฐฐ๊ฒฝ

    ํ”„๋กœ์ ํŠธ๊ฐ€ ์ ์  ๋งˆ๋ฌด๋ฆฌ๋˜๋Š” ์ตœ๊ทผ... 

    ์„œ๋ฒ„ ์ˆ˜์ •์„ ๊ธฐ๋‹ค๋ฆฌ๋ฉด์„œ ๊ธฐ์กด ๋กœ์ง์— ๋Œ€ํ•ด ์˜๋ฌธ์„ ๊ฐ€์ง€๊ณ  ์žˆ๋˜ ๋ถ€๋ถ„์— ๋Œ€ํ•ด ์ด์ „์— ํ•จ๊ป˜ ํ–ˆ๋˜ ๊ฐœ๋ฐœ์ž๋ถ„๊ป˜ ์งˆ๋ฌธ์„ ๋“œ๋ ธ๋‹ค!!!

     

    ๊ทธ๋Ÿฐ๋ฐ ๊ฒฐ๊ณผ์ ์œผ๋กœ ๋‚˜๋Š” ์„œ๋ฒ„ ์‹คํŒจ, ์„ฑ๊ณต ์ฒ˜๋ฆฌ์— ๋Œ€ํ•œ ์ดํ•ด๊ฐ€ ์ •~~๋ง ๋ถ€์กฑํ•œ ์ƒํƒœ์˜€๋‹ค. ๋”ฐ๋ผ์„œ ๊ทธ๋Ÿฐ ์ƒํƒœ๋กœ ์ง  ์ฝ”๋“œ๊ฐ€ ๋ชจ๋‘ ์ž˜๋ชป๋˜์—‡๋‹ค๋Š” ํ”ผ๋“œ๋ฐฑ์„ ๋ฐ›๊ฒŒ ๋˜์—ˆ๋‹ค.

    ์ด๋ ‡๊ฒŒ ํฌ๊ฒŒ ์ž˜๋ชป๋œ ์ ์„ ์•Œ ์ˆ˜ ์žˆ๋‹ค๋‹ˆ ใ… ใ…   ์งˆ๋ฌธ์„ ๋“œ๋ ค์„œ ์ •๋ง ๋‹คํ–‰์ด๊ณ  ๋‹ต๋ณ€ ์ฃผ์‹  ๊ฒƒ์— ์ •๋ง ๊ฐ์‚ฌํ•˜๋‹ค ๐Ÿ™


    ์ž˜๋ชป๋œ ์ฝ”๋“œ

    ์ž˜๋ชป๋œ ์ฝ”๋“œ๋ฅผ ๋ณด๊ณ  ๋ฌธ์ œ์ ๊ณผ ๋ถ€์กฑํ•จ ์ ์„ ์ฑ„์›Œ๋ณด์ž

    class GetReportListUseCase
        @Inject
        constructor(
            private val reportRepository: ReportRepository,
        ) {
            operator fun invoke(lastReportId: String?) =
                flow {
                    // todo : ๊ทธ๋ƒฅ "" ๋กœ ๋„ฃ์–ด์ค˜๋„ ๋จ ์ˆ˜์ •ํ•  ๊ฒƒ
                    val result = reportRepository.searchReport(SearchReportRequest(lastReportId = lastReportId))
                    result.onFailure {
                        throw it
                    }
                    emit(result.getOrNull())
                }.catch {
                    Timber.e(it.localizedMessage)
                }
        }

     

    ์ฝ”๋“œ์˜ ๋ฌธ์ œ์  

    1. result.onFailure { throw it }  

    ์‹คํŒจ ์‹œ ์˜ˆ์™ธ๋ฅผ throw ํ•˜๊ณ  ์ž‡๋‹ค. 

    ๊ทธ๋ฆฌ๊ณ  .catch { Timber.d("failed to search user Report list" ) ์—์„œ๋Š” ๋‹ค์‹œ ํ•œ๋ฒˆ ์˜ˆ์™ธ๋ฅผ ์žก์œผ๋ ค๊ณ  ํ•˜๊ณ  ์žˆ๋‹ค..

     

    ์šฐ์„  onSuccess์™€ onFailure๋Š” ๋ฌด์—‡์„ ํ•˜๋Š” ์•„์ด๋“ค ์ธ์ง€๋ถ€ํ„ฐ ์ดํ•ดํ•˜์ž.

    onSuccess

    result.onSuccess { value ->
     // ์—ฐ์‚ฐ์ด ์„ฑ๊ณตํ–ˆ์„ ๋•Œ ์‹คํ–‰๋˜๋Š” ๋ธ”๋ก
     // value : ์„ฑ๊ณต์ ์œผ๋กœ ์–ป๋Š” ๊ฒฐ๊ณผ๊ฐ’

     

    - ์—ฐ์‚ฐ์ด ์„ฑ๊ณต์ ์œผ๋กœ ์™„๋ฃŒ๋˜์—ˆ์„ ๋•Œ ํ˜ธ์ถœ๋œ๋‹ค.

    - ์„ฑ๊ณตํ•œ ๊ฒฐ๊ณผ๊ฐ’์€ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ๋ฐ›์•„ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค(value)

    - ์—ฐ์‚ฐ ๊ฒฐ๊ณผ๋ฅผ ์ถ”๊ฐ€๋กœ ๊ฐ€๊ณตํ•˜๊ฑฐ๋‚˜ ์‚ฌ์šฉํ•  ๋•Œ ํ™œ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

    onFailure 

    result.onFailure { exception -> 
    // ์—ฐ์‚ฐ ์ค‘ ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ–ˆ์„ ๋•Œ ์‹คํ–‰๋˜๋Š” ๋ธ”๋ก
    // exception : ๋ฐœ์ƒํ•œ ์˜ˆ์™ธ ๊ฐ์ฒด

     

     

    - ์—ฐ์‚ฐ ์ค‘ ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ–ˆ์„ ๋•Œ ํ˜ธ์ถœ๋œ๋‹ค

    - ์˜ˆ์™ธ ๊ฐ์ฒด๋ฅผ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ๋ฐ›์•„ ์˜ˆ์™ธ ์ฒ˜๋ฆฌ๋ฅผ ํ•  ์ˆ˜ ์žˆ๋‹ค(exception)

    - ๋กœ๊น…, ์—๋Ÿฌ ๋ฉ”์‹œ์ง€ ํ‘œ์‹œ, ๋Œ€์ฒด ๋™์ž‘ ๋“ฑ์„ ์ •์˜ํ•  ๋•Œ ์‚ฌ์šฉํ•œ๋‹ค.

    throw ํ•˜๋ฉด ์–ด๋–ค ์ผ์ด ์ผ์–ด๋‚ ๊นŒ?

    1. ์˜ˆ์™ธ ์ƒ์„ฑ

     - ํ˜„์žฌ ์Šค์ฝ”ํ”„์—์„œ ๋ฐœ์ƒํ•œ ์˜ˆ์™ธ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•œ๋‹ค.

    - ์˜ˆ์™ธ์˜ ๋ชจ๋“  ์ •๋ณด๋ฅผ ๋ณด์กดํ•œ๋‹ค.

     

    2. ํ˜ธ์ถœ ์Šคํƒ ์ „ํŒŒ

    - ์˜ˆ์™ธ๋Š” ํ˜„์žฌ ๋ฉ”์„œ๋“œ์—์„œ ํ˜ธ์ถœํ•œ ๋ถ€๋ชจ ๋ฉ”์„œ๋“œ๋กœ ์ „ํŒŒ๋œ๋‹ค.

    - ๊ฐ ํ˜ธ์ถœ ์Šคํƒ ๋ ˆ๋ฒจ์„ ๊ฑฐ์Šฌ๋Ÿฌ ์˜ฌ๋ผ๊ฐ„๋‹ค.

     

    3. ์˜ˆ์™ธ ์ฒ˜๋ฆฌ ๋Œ€๊ธฐ 

    - ์ ์ ˆํ•œ ์˜ˆ์™ธ ์ฒ˜๋ฆฌ๊ธฐ(try, catch)๋ฅผ ์ฐพ์„ ๋•Œ๊นŒ์ง€ ๊ณ„์† ์ „ํŒŒ๋œ๋‹ค.

    - ๋งŒ์•ฝ ์–ด๋””์—์„œ๋„ ์ฒ˜๋ฆฌ๋˜์ง€ ์•Š์œผ๋ฉด ํ”„๋กœ๊ทธ๋žจ์ด ์ค‘๋‹จ๋  ์ˆ˜ ์žˆ๋‹ค.

    - ๊ฐœ๋ฐœ์ž๊ฐ€ ์˜๋„์ ์œผ๋กœ ์—๋Ÿฌ๋ฅผ ์ƒ์œ„ ๋ ˆ์ด์–ด๋กœ ์ „ํŒŒํ•  ๋•Œ ์‚ฌ์šฉํ•œ๋‹ค

     

    // ์˜ˆ์™ธ๋ฅผ ๋ช…์‹œ์ ์œผ๋กœ ๋ฐœ์ƒ์‹œํ‚ค๊ณ  ์ „ํŒŒํ•  ๋•Œ throw ๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.
    fun getList() {
    // ์˜ˆ์™ธ ๋ฐœ์ƒ ๊ฐ€๋Šฅ์„ฑ ์žˆ๋Š” ์ฝ”๋“œ
    	throw RuntimeException("wrong")
    }
    
    fun callGetList() {
    	try {
        	getList() 
        } catch(e : Exception) {
        	// ์˜ˆ์™ธ ์ฒ˜๋ฆฌ
        	println(e.message)
        }
      }

     

    ๊ฐœ์„ ํ•œ ์ฝ”๋“œ

    ์•„๋ž˜๋Š” ๊ฐœ์„ ํ•ด๋ณธ ์ฝ”๋“œ์ด๋‹ค! 

    class GetReportListUseCase
        @Inject
        constructor(
            private val reportRepository: ReportRepository,
        ) {
            operator fun invoke(lastReportId: String?): Flow<SearchReportResponse?> =
                flow {
                    // 1. ๋ ˆํฌ์ง€ํ† ๋ฆฌ ํ˜ธ์ถœ ์‹œ ์˜ˆ์™ธ ๋ฐœ์ƒ
                    try {
                        val result = reportRepository.searchReport(SearchReportRequest(lastReportId = lastReportId))
                        result
                            .onSuccess { searchResult ->
                                emit(searchResult)
                            }.onFailure { exception ->
                                when (exception) {
                                    // todo : ์ดํ›„ UiState๋ฅผ ํ†ตํ•ด HttpError ๋ฐœ์ƒ ์‹œ ์—๋Ÿฌ ๋ฉ”์‹œ์ง€ ๋ณด์ด๊ธฐ
                                    is HttpException -> Timber.e("Network error: ${exception.message}")
                                    else -> Timber.e("Unknown error: ${exception.message}")
                                }
                                // ์˜ˆ์™ธ ๋ฐœ์ƒ ์‹œ  ๊ธฐ๋ณธ๊ฐ’  ๋ฐ˜ํ™˜
                                emit(SearchReportResponse())
                            }
                    } catch (e: Exception) {
                        // result.onFailure์—์„œ ์ฒ˜๋ฆฌ๋˜์ง€ ์•Š์€ ๋ชจ๋“  ์˜ˆ์™ธ๋ฅผ ์ตœ์ข…์ ์œผ๋กœ ์žก์•„๋‚ธ๋‹ค.
                        // ์˜ˆ์ƒ์น˜ ๋ชปํ•œ ์˜ˆ์™ธ ๋ฐœ์ƒ ๊ฐ€๋Šฅ์„ฑ
                        // 1. JSON ํŒŒ์‹ฑ ์˜ค๋ฅ˜
                        // 2. ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๋‚ด๋ถ€ ๋ฒ„๊ทธ๋กœ ์ธํ•œ ์˜ˆ์™ธ
                        Timber.e(e, "Unexpected error in GetReportListUseCase")
                        // ์˜ˆ์™ธ ๋ฐœ์ƒ ์‹œ  ๊ธฐ๋ณธ๊ฐ’  ๋ฐ˜ํ™˜
                        emit(SearchReportResponse())
                    }
                }
        }

     

     

    throw

    ์˜ˆ์™ธ throw ๊ณผ์ •
    ํ”„๋กœ๊ทธ๋žจ ์‹คํ–‰ ํ๋ฆ„ :
    1. ํ•จ์ˆ˜ ์‹œ์ž‘
    2. ์˜ˆ์™ธ ๋ฐœ์ƒ !
    3. ํ”„๋กœ๊ทธ๋žจ ์‹คํ–‰ ์ค‘๋‹จ
    4. ์˜ˆ์™ธ ์ •๋ณด ์ „ํŒŒ

     

    throw๋Š”  ํŠน์ • ์ƒํ™ฉ์—์„œ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋Š” ์˜ˆ์™ธ๋ฅผ ์ฒ˜๋ฆฌํ•ด์ฃผ๊ธฐ ์œ„ํ•ด catch๋ฌธ์—์„œ ์žก์„ ์ˆ˜ ์žˆ๋„๋ก ํ•ด๋‹น ์˜ˆ์™ธ๋ฅผ ๋˜์ง€๋Š”(throw) ์ฒ˜๋ฆฌ ๊ณผ์ •์ด๋‹ค.

    class CustomNetworkException(message: String) : Exception(message)
    
    
    fun performNetworkCall() {
        val random = Random.nextInt(0, 3)
    
        when (random) {
            0 -> throw CustomNetworkException("์—ฐ๊ฒฐ ์˜ค๋ฅ˜")
            1 -> throw IllegalArgumentException("์ž˜๋ชป๋œ ์ธ์ž")
            2 -> throw RuntimeException("์•Œ ์ˆ˜ ์—†๋Š” ์˜ค๋ฅ˜")
        }
    }

     

    ์ด๋ ‡๊ฒŒ random ์ˆ˜์— ๋”ฐ๋ผ์„œ throw๋ฅผ ํ†ตํ•ด ์˜ˆ์™ธ๋ฅผ ๋˜์ ธ์ฃผ์—ˆ๋‹ค.

    ๊ฐœ๋ฐœ ์ค‘์—์„œ๋Š” ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋Š” ์ƒํ™ฉ์—์„œ throw๋ฅผ ํ†ตํ•ด ์˜ˆ์™ธ๋ฅผ ๋˜์ ธ์ฃผ๋ฉด ๋œ๋‹ค!!

    catch

    ์˜ˆ์™ธ catch ๊ณผ์ •
    ํ”„๋กœ๊ทธ๋žจ ์‹คํ–‰ ํ๋ฆ„ :
    1. try ๋ธ”๋ก ์‹œ์ž‘
    2. ์˜ˆ์™ธ ๋ฐœ์ƒ!
    3. catch ๋ธ”๋ก์œผ๋กœ ์ด๋™
    4. ์˜ˆ์™ธ ๋ฉ”์‹œ์ง€ ์ถœ๋ ฅ
    5. finally ๋ธ”๋ก ์‹คํ–‰
    6. ํ”„๋กœ๊ทธ๋žจ ์ •์ƒ ๊ณ„์† ์‹คํ–‰

     

    ์œ„์—์„œ ๋˜์ง„ ์˜ˆ์™ธ๋“ค์„ ์—ฌ๊ธฐ์„œ catch๋ฅผ ํ•˜๊ณ  ๋ฐœ์ƒํ•˜๋Š” ์˜ˆ์™ธ์— ๋”ฐ๋ผ์„œ ์ฒ˜๋ฆฌ๋ฅผ ํ•ด์ฃผ์—ˆ๋‹ค.

    ์ด์ฒ˜๋Ÿผ catch๋ฌธ์„ ํ†ตํ•ด ์ฒ˜๋ฆฌํ•˜๊ณ  ์‹ถ์€ ์˜ˆ์™ธ๋ฅผ ์žก์•„์„œ ์›ํ•˜๋Š” ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค.

    fun main() {
        try {
            performNetworkCall()
        } catch (e: CustomNetworkException) {
            // ํŠน์ • ์˜ˆ์™ธ ์ฒ˜๋ฆฌ
            println("๋„คํŠธ์›Œํฌ ์˜ค๋ฅ˜ ์ฒ˜๋ฆฌ: ${e.message}")
        } catch (e: IllegalArgumentException) {
            // ๋‹ค๋ฅธ ์œ ํ˜•์˜ ์˜ˆ์™ธ ์ฒ˜๋ฆฌ
            println("์ธ์ž ์˜ค๋ฅ˜ ์ฒ˜๋ฆฌ: ${e.message}")
        } catch (e: Exception) {
            // ๋ชจ๋“  ๋‚˜๋จธ์ง€ ์˜ˆ์™ธ ์ฒ˜๋ฆฌ
            println("์ผ๋ฐ˜ ์˜ˆ์™ธ ์ฒ˜๋ฆฌ: ${e.message}")
        } finally {
            // ํ•ญ์ƒ ์‹คํ–‰๋˜๋Š” ๋ธ”๋ก
            println("์ •๋ฆฌ ๋ฐ ์ž์› ํ•ด์ œ")
        }
    }

     

     

    ์˜ˆ์™ธ throw ํ›„ ์‹คํ–‰ ํ๋ฆ„

    ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•˜๋ฉด ํ๋ฆ„์€ ์ฆ‰์‹œ ์ค‘๋‹จ๋˜๊ณ  ๋‹ค์Œ ์ค„์— ์œ„์น˜ํ•œ ์ฝ”๋“œ๋Š” ์‹คํ–‰๋˜์ง€ ์•Š๋Š”๋‹ค.

    fun exampleThrowError() {
        println("์ด ์ฝ”๋“œ๋Š” ์‹คํ–‰ ๋จ")
        throw RuntimeException("Something went wrong!")
        // ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•˜๋ฉด ํ”„๋กœ๊ทธ๋žจ ํ๋ฆ„์ด ์ฆ‰์‹œ ์ค‘๋‹จ๋œ๋‹ค.
        println("์ด ์ฝ”๋“œ๋Š” ์‹คํ–‰๋˜์ง€ ์•Š์Œ")
    
    }
    

     

    catch ์‹œ ์‹คํ–‰ ํ๋ฆ„

    catch ๋ธ”๋ก ์ดํ›„์˜ ํ”„๋กœ๊ทธ๋žจ์€ ๊ณ„์† ์‹คํ–‰๋˜๊ณ , finally ๋ธ”๋Ÿญ์œผ๋กœ ์ž‘์„ฑ๋œ ์ฝ”๋“œ๋Š” ์˜ˆ์™ธ์™€ ์ƒ๊ด€์—†์ด ์ •์ƒ ์‹คํ–‰๋œ๋‹ค

    fun exampleCatchError(){
        try {
            // ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋Š” ์ฝ”๋“œ ๋ธ”๋Ÿญ
            val result = 10/0 // ์ด ์ค„์—์„œ ArithmeticException ๋ฐœ์ƒ
            println("์ด ์ฝ”๋“œ๋Š” ์‹คํ–‰๋˜์ง€ ์•Š์Œ")
        } catch (e : ArithmeticException) {
            // ํŠน์ • ์—๋Ÿฌ๋ฅผ ์žก์•„์„œ ์ฒ˜๋ฆฌ
            println("0์œผ๋กœ ๋‚˜๋ˆŒ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค :${e.message}")
        } finally {
            // ์˜ˆ์™ธ ๋ฐœ์ƒ ์—ฌ๋ถ€์™€ ์ƒ๊ด€์—†์ด ์ •์ƒ ์‹คํ–‰
            println("์ •๋ฆฌ ์ž‘์—… ์ˆ˜ํ–‰")
        }
    
        // catch ๋ธ”๋ก ์ดํ›„ ํ”„๋กœ๊ทธ๋žจ ๊ณ„์† ์‹คํ–‰
        println("ํ”„๋กœ๊ทธ๋žจ ๊ณ„์† ์ง„ํ–‰")
    
    }

     

    ์‹ค์ œ ํ”„๋กœ์ ํŠธ์— ์ ์šฉํ•œ ๋ฐฉ์‹

    ํ˜„์žฌ๋Š” ์•„๋ž˜์™€ ๊ฐ™์ด ์‚ฌ์šฉํ•ด์ฃผ๊ณ  ์žˆ๋‹ค.

    ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•œ ๊ฒฝ์šฐ์—๋Š” null์„ ๋ฐ˜ํ™˜ํ•ด์ฃผ๊ณ , ์„ฑ๊ณตํ•œ ๊ฒฝ์šฐ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐฉ์ถœํ•˜๋„๋ก ํ•ด์ฃผ์—ˆ๋‹ค.

    ์ด ๋ถ€๋ถ„์€ ์ถ”ํ›„ ์‚ฌ์šฉ์ž์™€์˜ ์ƒํ˜ธ์ž‘์šฉ์„ ๋ณด๋ฉด์„œ ๋‚˜ํƒ€๋‚˜๋Š” ์ƒํ™ฉ์— ๋งž์ถ”์–ด ์ˆ˜์ •ํ•ด์ค„ ์˜ˆ์ •์ด๋‹ค! 

     flow {
                    val result = reportRepository.getReport(reportId)
                    result.onFailure {
                        when (it) {
                            is HttpException -> Timber.e("Network error: ${it.message}")
                            else -> Timber.e("Unknown error: ${it.message}")
                        }
                        emit(null)
                    }
                    result.onSuccess {
                        emit(it)
                    }
                }
    728x90