Menu
Coddy logo textTech

에러 래핑 (fmt.Errorf)

Coddy GO 여정의 객체 지향 프로그래밍 섹션에 포함된 레슨. 107개 중 54번째.

오류가 애플리케이션의 여러 계층을 통과할 때는 오류가 어디서 발생했는지 아는 것이 매우 중요합니다. Go의 fmt.Errorf 함수에서 %w 동사를 사용하면 오류를 래핑하여 원래 오류를 보존하면서 컨텍스트를 추가할 수 있습니다.

Error 래핑은 오류의 체인을 생성합니다. 각 계층은 오류가 발생했을 때 수행하려고 했던 작업에 대한 정보를 추가할 수 있습니다.

func ReadConfig(filename string) error {
    data, err := os.ReadFile(filename)
    if err != nil {
        return fmt.Errorf("reading config file: %w", err)
    }
    // 데이터 처리...
    return nil
}

%w 동사는 특별합니다. 원래 오류를 새로운 오류 안에 감쌉니다. 이는 오류를 문자열로 변환하기만 하고 원래 오류의 정체성을 잃게 하는 %v와 다릅니다.

func LoadSettings() error {
    err := ReadConfig("settings.json")
    if err != nil {
        return fmt.Errorf("loading settings: %w", err)
    }
    return nil
}

LoadSettings가 실패하면 오류 메시지에 전체 chain이 표시됩니다: "loading settings: reading config file: open settings.json: no such file or directory". 각 계층이 context를 추가하므로 디버깅이 훨씬 쉬워집니다.

래핑된 오류에는 여전히 원래 오류가 포함되어 있습니다. 다음 레슨에서는 errors.Is()errors.As()를 사용하여 이러한 오류를 언래핑하고 내부에 무엇이 있는지 확인하는 방법을 배우게 됩니다.

challenge icon

챌린지

쉬움

여러 계층에 걸친 오류 래핑을 보여 주는 주문 처리 시스템을 만들어 보겠습니다. 각 계층이 오류에 컨텍스트를 추가하는 함수 체인을 만들어 문제가 정확히 어디에서 발생했는지 쉽게 추적할 수 있도록 합니다.

코드를 두 파일로 구성합니다.

  • orders.go: 오류가 상위 계층으로 전파될 때 오류를 래핑하는 여러 계층의 주문 처리 로직을 작성합니다.

    처리 체인을 구성하는 세 가지 함수를 구현합니다.

    • ValidateItem(itemID string) error - itemID가 "INVALID"이면 메시지가 "item not found"인 오류를 반환하고, 그렇지 않으면 nil을 반환합니다.
    • ProcessOrder(orderID, itemID string) error - ValidateItem을 호출합니다. 오류가 반환되면 해당 오류를 "processing order [orderID]: %w" 컨텍스트로 래핑합니다. 그렇지 않으면 nil을 반환합니다.
    • SubmitOrder(customerName, orderID, itemID string) error - ProcessOrder를 호출합니다. 오류가 반환되면 해당 오류를 "submitting order for [customerName]: %w" 컨텍스트로 래핑합니다. 그렇지 않으면 nil을 반환합니다.

    각 계층은 %w 동사와 함께 fmt.Errorf를 사용하여 아래 계층의 오류를 래핑하고 컨텍스트 체인을 구성해야 합니다.

  • main.go: 입력에서 주문 세부 정보를 읽고, SubmitOrder를 호출한 다음 결과를 표시합니다. 오류가 발생하면 전체 오류 체인을 출력합니다. 성공하면 확인 메시지를 출력합니다.

다음 입력이 제공됩니다.

  • 1번째 줄: 고객 이름
  • 2번째 줄: 주문 ID
  • 3번째 줄: 항목 ID

결과를 출력합니다.

  • 오류가 발생한 경우: Error: [full error chain]
  • 성공한 경우: Order [orderID] submitted successfully for [customerName]

예를 들어 Alice, ORD-123, INVALID가 주어지면 출력은 다음과 같아야 합니다.

Error: submitting order for Alice: processing order ORD-123: item not found

오류 메시지에 전체 체인이 어떻게 표시되는지 확인하세요. 최상위 제출 시도부터 주문 처리 과정을 거쳐 실제 유효성 검사 실패에 이르기까지 문제를 추적할 수 있습니다. 각 계층은 %w를 사용하여 자체 컨텍스트를 추가했습니다.

그리고 Bob, ORD-456, ITEM-001이 주어지면 출력은 다음과 같아야 합니다.

Order ORD-456 submitted successfully for Bob

직접 해보기

package main

import (
	"bufio"
	"fmt"
	"os"
)

func main() {
	scanner := bufio.NewScanner(os.Stdin)
	
	// 고객 이름 읽기
	scanner.Scan()
	customerName := scanner.Text()
	
	// 주문 ID 읽기
	scanner.Scan()
	orderID := scanner.Text()
	
	// 아이템 ID 읽기
	scanner.Scan()
	itemID := scanner.Text()
	
	// TODO: 입력 값으로 SubmitOrder 호출
	// TODO: 오류가 발생하면 출력: Error: [full error chain]
	// TODO: If successful, print: Order [orderID] submitted successfully for [customerName]
	
	_ = customerName
	_ = orderID
	_ = itemID
}
quiz icon실력 점검

이 레슨에는 짧은 퀴즈가 포함되어 있습니다. 레슨을 시작해 문제를 풀고 진행 상황을 기록하세요.

객체 지향 프로그래밍의 모든 레슨

직접 연습해 보세요: 온라인 Go 컴파일러