본문 바로가기
Study OR Book/Book

[이펙티브 코틀린] 아이템17: 이름 있는 아규먼트를 사용하라

by Baest 2025. 1. 8.

 

코드에서 아규먼트의 의미가 명확하지 않은 경우가 있다.

 

아래 코드에서 | 가 의미하는 바에 대하여 논란이 없을까?

val text = (1..10).joinToString("|")

만약 joinToString에 대하여 잘 알고 있다면, 구분자(seperator)를 의미한다는 것을 알 수 있겠지만

모른다면, 이를 접두사(prefix)나 그 외 다른 것으로 생각 할 수도 있다.

 

따라서 명확하지 않을 수 있는 문제가 있다.

이 문제를 해결하기 위해서는 아래은 방법으로 수정이 가능하다.

// 아규먼트를 사용하는 방법
val text = (1..10).joinToString(seperator = "|")

// 변수를 사용하여 의미를 명확하게 하는 방법 
val seperator = "|"
val text = (1..10).joinToString(seperator)

 

파라미터가 명확하지 않은 경우 이를 직접 지정해서 명확하게 만들어 줄 수 있다.

하지만 여전히 변수를 잘못 사용하는 등의 이슈가 있을 수 있으므로 아래와 같이 이름 있는 아규먼트를 사용하는게 좋다.

val seperator = "|"
val text = (1..10).joinToString(seperator = seperator)

 

 

이름 있는 아규먼트를 사용해야하는 경우

- 이름을 기반으로 값이 무엇을 나타내는지 알 수 있다.

- 파라미터 입력 순서와 상관 없으므로 안전하다.

 

추가적으로 이름 있는 아규먼트의 사용을 더욱 더 추천하는 경우

- 디폴트 아규먼트의 경우

- 같은 타입의 파라미터가 많은 경우

- 함수 타입의 파라미터가 있는 경우(마지막 제외)

 

디폴트 아규먼트

함수 이름은 필수 파라미터들과 관련되어 있기 때문에 디폴트 값을 갖는 옵션 파라미터 설명이 명확하지 않다.

따라서 이름을 붙여서 사용하는 것이 좋다.

 

같은 타입의 파라미터가 많은 경우

파라미터가 모두 다른 타입인 경우 위치가 잘못 입력되었을 때 오류가 발생해서 쉽게 확인이 가능하다.

하지만 같은 타입이라면, 잘못 입력된 경우 문제를 파악하기 어려울 수 있다.

 

fun sendEmail(to: String, message: String) { /*...*/ }

// 위와 같은 경우 아래처럼 이름 있는 아규먼트를 사용하는 것이 좋다.

sendEmail(
  to = "test@email.com",
  message = "샘플 메세지"
)

 

FYI: 위치 기반 아규먼트 (파라미터가 모두 다른 타입인 경우 위치가 잘못 입력되었을 때의 예시)

fun greet(name: String, age: Int) {
	println("Hi, my name is $name and I am $age years old.")
}

fun main() {
	// 위치 기반 아규먼트 사용
    greet("Alice", 25) // name = "Alice", age = 25
    
    // 순서 바뀌면 타입 불일치 오류
    greet(25, "Alice")
}

 

추가: 위치 기반과 이름 있는 아규먼트 혼합 사용

* 위치 기반 아규먼트와 이름 있는 아규먼트를 혼합 사용할 때는 위치 기반 아규먼트가 먼저 와야한다.

fun greet(name: String, age: Int, country: String) {
    println("Hello, my name is $name, I am $age years old, and I am from $country.")
}

fun main() {
    // 위치 기반 + 이름 있는 아규먼트 혼합
    greet("Alice", age = 25, country = "USA") // 올바른 예시
}


// 잘못된 예시
fun main() {
    // 이름 있는 아규먼트가 위치 기반 아규먼트 앞에 올 경우 오류 발생
    greet(age = 25, "Alice", country = "USA") // 오류: 위치 기반 아규먼트는 항상 앞에 와야 함
}

 

함수 타입 파라미터

함수 타입 파라미터는 마지막 위치에 배치하는 것이 좋다. 때로는 함수 이름이 함수 타입 아규먼트를 설명해 주기도 한다.

예를 들어 repeat 이라는 함수 이름으로 정의되어 있을 경우 해당 함수의 역할이 반복을 시킨다는 것을 예상할 수 있다.

 

그 밖의 모든 함수 타입 아규먼트는 이름이 있는 아규먼트를 사용하는 것이 이해하기 좋다.

일부 예시로 아래와 같은 여러 함수 타입의 옵션 파라미터가 있는 경우 더 헷갈릴 수 있다.

fun call(before: () -> Unit = {}, after: () -> Unit = {}) {
    before()
    println("Middle")
    after()
}

call({ print("CALL") }) // CALLMiddle
call({ print("CALL") }) // MiddleCALL

// 위와 같이 사용하는 것 보다 아래와 같이 이름을 붙여 사용하면, 이해하기 쉽다.

call(before = { print("CALL") } ) // CALLMiddle
call(after = { print("CALL") } ) // MiddleCALL

 

 

정리

- 이름 있는 아규먼트를 사용하면 가독성이 높아진다.

- 코드의 안정성도 향상 시킬 수 있다.

- 함수에 같은 타입의 파라미터가 여러개 있을 때, 함수 타입의 파라미터가 있을 때, 옵션 파라미터가 있을 때 '이름 있는 아규먼트'를 사용하는게 좋다.