[go] Error Wrapping 패턴

Go 언어는 오류 처리를 위해 내장된 에러 타입을 제공하고, 이러한 에러를 반환하는 함수들은 다른 언어와는 다소 다른 패턴을 가지고 있습니다. 하지만 때때로, 더 많은 컨텍스트를 제공하기 위해 에러를 wrapping 하는 것이 좋은 선택일 수 있습니다.

에러 wrapping 패턴을 사용하면 에러에 대한 추가적인 정보를 제공하고, 디버깅 및 추적을 용이하게 할 수 있습니다. Go 언어에서 이 패턴을 구현하는 방법을 알아보겠습니다.

기본 에러 처리

첫 번째로, 기본적인 에러 처리 방식을 살펴보겠습니다. 아래는 간단한 함수에서 발생한 에러를 처리하는 예제 코드입니다.

func divide(a, b int) (int, error) {
    if b == 0 {
        return 0, errors.New("cannot divide by zero")
    }
    return a / b, nil
}

func main() {
    res, err := divide(10, 0)
    if err != nil {
        fmt.Println("Error:", err)
        return
    }
    fmt.Println("Result:", res)
}

위 예제에서 errors.New() 함수를 사용하여 에러를 생성하고, 호출하는 측에서 이를 확인하여 처리합니다.

에러 wrapping

에러 wrapping은 에러를 래핑하여 컨텍스트를 추가하는 것을 의미합니다. errors 패키지에서 제공하는 Wrap 함수를 사용하여 에러를 wrapping할 수 있습니다.

func divide(a, b int) (int, error) {
    if b == 0 {
        return 0, errors.Wrap(errors.New("cannot divide by zero"), "divide")
    }
    return a / b, nil
}

위 코드에서 errors.Wrap() 함수를 사용하여 기본 에러에 “divide”라는 컨텍스트를 추가했습니다. 이렇게 함으로써 디버깅 시 에러의 원인을 추적하는 데 도움이 됩니다.

래핑된 에러 처리

래핑된 에러를 처리하는 방법은 간단합니다. errors 패키지의 Cause 함수를 사용하여 원본 에러를 추출하고, 래핑된 컨텍스트 정보도 함께 확인할 수 있습니다.

func main() {
    res, err := divide(10, 0)
    if err != nil {
        fmt.Println("Error:", err)
        fmt.Println("Original error:", errors.Cause(err))
        return
    }
    fmt.Println("Result:", res)
}

위 예제에서 errors.Cause() 함수를 사용하여 래핑된 에러의 원본을 확인하고, 원본 에러의 정보도 함께 출력하였습니다.

에러 wrapping 패턴을 사용하면 코드의 유지보수성을 향상시키고, 디버깅을 용이하게 할 수 있습니다. 따라서 적절한 상황에서 이를 활용하여 좀 더 유연하고 가독성 있는 코드를 작성하는 것이 좋습니다.

참고 자료