최데브는 오늘도 프로그래밍을 한다.

[이펙티브 코틀린] 7. 결과 부족이 발생할 경우 null과 Failure를 사용하라 본문

Effective Kotiln

[이펙티브 코틀린] 7. 결과 부족이 발생할 경우 null과 Failure를 사용하라

최데브 2023. 3. 1. 13:36

우리는 함수를 작성하다보면 결과를 만들어 낼 수 없을 때가(예외) 있다.
대표적으로 아래와 같은 상황이 생길 수 있다.

  • 서버로부터 데이터를 받을때 인터넷 문제로 받아오지 못한 경우
  • 조건에 맞는 요소들중 첫번쨰 요소를 가져오려고 했는데 조건에 맞는 요소가
    하나도 없는 경우 ex) index 에러
  • json 파싱을 하려고 했는데 형식이 맞지 않아서 발생하는 오류

이런 상황을 처리할때 두 가지 매커니즘을 활용 할 수 있다.

  •  제목처럼 null이나 Failure(라는 이름의 sealed 클래스)를 사용해서 처리
  • 예외를 throw

두가지에는 중요한 차이가 있다.

 

예외를 throw 하는거부터 보자.

  • 일단 예외는 정보를 전달하는 방법으로 사용해서는
    안된다. 예외는 잘못된 특별한 상황을 나타낼때 사용해야한다.
    그 이유는 많은 개발자가 예외가 전파되는 과정을 제대로 추적하기 쉽지않다.
  • 예외는 예외적인 상황을 처리하기 위해 만들어졌으므로 명시적인 테스트만큼 빠르게 동작하지 않는다.
  • try - catch 블록 내부에 코드를 배치하면, 컴파일러가 할 수 있는 최적화가 제한된다.

제목처럼 null이나 Failure(라는 이름의 sealed 클래스)를 사용해서 처리

  • null 과 Failure 는 예상이 되는 오류를 표현할때 좋다,명시적이고 효율적이며 간단하게 처리할 수있다.예측하기 어려운 것에만 예외를 throw 해서 처리하는것이 좋다.

아래에 예시를 보자.

inline fun <reified T> String.readObjectOrNull(): T? {
    // ...
    if (incorrectSign) {
        return null
    }
    // ...
    return result
}

inline fun <reified T> String.readObject(): Result<T> {
    // ...
    if (incorrectSign) {
        return Failure(JsonParsingException())
    }
    // ...
    return Success(result)
}

sealed class Result<out T>
class Success<out T>(val result: T): Result<T>()
class Failure(val throwable: Throwable): Result<Nothing>()

class JsonParsingException: Exception()

이렇게하면 개발중에 에러를 놓치는 일이 확 줄어들 것이다. null 을 반환해서 처리할 일이 생겼다면 코틀린의 null-safety 기능을 이용해서 처리해보자.

 

아래는 처리하는 예시다.

val age = userText.readObjectOrNull<Person>()?.age ?: -1
val person = userText.readObjectOrNull<Person>()
val age = when(person) {
    is Success -> person.age
    is Failure -> -1
}

sealed 클래스로 만든 Result 처럼 만들어서 처리하는 경우는 에러에 대한 추가적인 정보를 반환해야할때 유용하고

추가적인 정보를 전달하지 않아도 되는 경우는 null 을 이용해서 처리하는게 좋다.

 

반응형
Comments