영어 데일리

내 시간을 아껴줬던 6가지의 코틀린 실수 피하기

현욱 정리장 2025. 5. 22. 10:56

https://medium.com/@nameisjayant/avoid-these-6-kotlin-mistakes-that-cost-me-hours-ec570446d95f

 

여기 더 깔끔하고, 안전하며 관용적인 코드를 작성하는데 나에게 도움되었던 피땀 어린 6가지 교휸이 있습니다. 

 

코틀린은 깔끔하고 비싼 언어입니다. 그리고 바로 그 점때문에 교묘하게 까다롭습니다. 

내가 코틀린을 풀타임으로 개발할때 나는 마치 날아가는 기분이였습니다. 코드가 깔끔하고, 널에 대해 안전하며, 코루틴. 등등. 뭐가 잘못되겠어?

 

무수한 시간을 디버깅과 리팩토링 그리고 어려운 방법에 대해 배우고 나서 나에게 크게 시간을 쓰게만든 6가지 일반적인 코틀린 실수에 대해 정리해봤습니다.

이제 막 시작한 분이거나, 심지어 스스로 경험자라고 생각하더라도 이것은 꼭 피해야 할 함정들입니다. 

너의 시간을 아끼고 작은 두통을 지켜봅시다

 

1. 코틀린에서 자바로 작성하기 

오래된 습관들을 버리는건 힘듭니다. 한동안 저는 사실상 코틀린 문법으로 자바를 쓰고 있었어요. 

예제 

fun isActive(userProfile: UserProfile?): Boolean {
    if (userProfile != null) {
        return userProfile.isActive
    } else {
        return false
    }
}



수정: 코틀린의 표현력을 믿으세요.

fun isActive(userProfile: UserProfile?) = userProfile?.isActive == true


깔끔하고 간결한 코틀린입니다

 

2. 확장 함수를 활용하지 않기 

코틀린의 슈퍼파워 기능중에 하나는 확장함수입니다. 하지만 나는 몇달 동안 손도 대지않았습니다.

문제

나는 반복해서 같은 널체크 로직을 사용하고, 여러 장소에 보일러플레이트 코드를 작성했습니다.

 

수정

재사용 가능한 로직을 확장함수에서 추출했습니다.

 

fun String?.orDefault(default: String = ""): String {
    return this ?: default
}


대신에 지금은 

 

val name = user.name ?: ""


나는 이제 이렇게작성합니다

val name = user.name.orDefault()


이제 우리는 ?: ""와 같은 널체크 로직을 코드에 매번 사용하지말고, 대신에 orDefault() 와 같은 확장함수를 사용합시다.

더 읽기 쉽고, 더 재사용가능하며 더 코틀린 스럽습니다.

 

3. 코루틴으로 지나치게 복잡하게만들기

코루틴은 매우 환상적입니다. 너가 잘못쓰기 전까지요. 그러다보면 결국 엉망진창의 동시성 코드가 되어버립니다.

실수: 구조체 없이 매번 코루틴을 실행하는 것 

GlobalScope.launch {
    fetchData()
}


이 방식은 잘 작동했어요. 뭔가를 취소하거나, 예외를 처리해야할 때까지는요. 

 

수정: 동시성 구조체를 사용하세요. 코루틴 생명주기를 coroutinescope에 연결하세요. 예를들면 viewModelScope나 lifecycleScope요.

viewModelScope.launch {
    try {
        val data = repository.getData()
        _state.value = data
    } catch (e: Exception) {
        _error.value = e.message
    }
}


보너스: CoroutineExceptionHandler와 try/catch는 적절한 예외처리입니다. 

 

4. 오버로딩 함수에서 기반 인자를 처리하지 않는 실수 

코틀린은 기본 인자를 지원하므로, 오버로딩 함수가 필요 없어집니다.

 

실수: 자바처럼 오버로딩 함수를 작성하는 것 

fun greet(name: String) {
    greet(name, false)
}

fun greet(name: String, isFormal: Boolean) {
    if (isFormal) println("Hello, $name") else println("Hey, $name")
}


수정: 대신 기본인자를 사용하세요. 

fun greet(name: String, isFormal: Boolean = false) {
    if (isFormal) println("Hello, $name") else println("Hey, $name")
}



더 깔끔해지고, 유지보수하기 쉬워집니다. 

 

5. 타입 엘리어스를 무시하는것 

때때로 나는 람다나 함수 타입을 사용할때, 타입이 깊게 중첩되거나, 반복적인 경우가 있었습니다. 

 

실수

val callback: (Int, String, Boolean) -> Unit

 

수정:  typeAlias 를 사용해 간단하고 읽기쉽게 하기

typealias ResultCallback = (Int, String, Boolean) -> Unit

val callback: ResultCallback


이것은 너가 APIs, 리스너, 또는 고차 함수와 함께 작업할때는 판도를 바꾸는 요소가 됩니다. 

 

6. for 루프 대신에 functional 연산자 사용하기

 

자바에서는 나는 for loops를 항상 사용했어요.

val result = mutableListOf<Int>()
for (num in numbers) {
    if (num % 2 == 0) {
        result.add(num * 2)
    }
}


수정: 코툴린 펑셔널 접근방식을 받아들이세요.

val result = numbers.filter { it % 2 == 0 }.map { it * 2 }


더 효율적이고, 컴포저블하며, 읽기쉽습니다. (한번만 사용해보면 압니다.)

 

보너스: runBlocking을 사용해서 메인쓰레드 블로킹

이건 테스트 할때랑, 코루틴을 처음써볼때 진짜 크게 당했던 부분이에요.

fun getUser() {
    runBlocking {
        val user = api.fetchUser()
        println(user)
    }
}


이슈: runBlocking은 현재 스레드를 막아버립니다. 메인스레드에서 그러면 큰일나요.

 

수정: runBlocking을 테스트 환경에서 사용하거나, 상위 함수에서 꼭 필요할때만 사용하세요.

그 외에는 suspend 함수나 coroutinescope 를 사용하는 구조적 코루틴을 쓰는 것이 좋습니다.

suspend fun getUser() {
    val user = api.fetchUser()
    println(user)
}

 

 

마지막 

여기 나열된 모든 실수는 하나하나 전투의 흔적입니다. 그리고 나는 다음 프로젝트에 계속 가져갈 교훈입니다.

코틀린은 많은 것을 제공하지만, 그 진가는 겉핥기 이상의 이해를 가진 사람들에게만 보답합니다.

희망합니다. 이 글이 깔끔하고 안전하고 더 관용적인 코틀린 작성에 도움되기를요. 나처럼 어려운길을 경험하지 않고요.

 

오늘은 여기까지 입니다. 여러분, 이 글을 재밌게 읽으셨고, 새로운것을 배웠기를바랍니다. 

이글이 유익했다고 느끼셨다면 자유롭게 박수를 보내주ㄱ시고, 이런 글들을 더 보고싶으시다면 팔로우해주세요.
 

 

 

 

 

 

기타

idiomatic 관용적인 

elegant 깔끔하고 효율적인

deceptively tricky 겉보기엔 쉬워보여도 실제론 까다로운 

leveraging 활용하다

extract 추출하다 

eliminates 제거하다 

deeply nested 깊게 중첩되다. 

embrace 받아들이다. 

when appropriate 진짜 꼭 필요한 상황에서만