9
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

はじめに

Goのエラー処理はシンプルですが、実務では次の理由で事故りやすいです。

  • 返すだけで情報が足りず、ログを見ても原因が分からない
  • 文字列比較に寄って、呼び出し元が分岐できない
  • ラップのしすぎで、結局どこで失敗したのか追えない

この記事は構文の説明よりも「どう設計して運用で回すか」に寄せます。

先に結論 まず固定する方針

  • 呼び出し元が分岐したいものは sentinel か typed error にする
  • それ以外は fmt.Errorf で文脈を足してラップする
  • 比較は errors.Is、取り出しは errors.As を使う
  • ログに出す情報とエラーに含める情報を分ける

いつ sentinel error を使うか

sentinel error は「呼び出し元が明確に分岐したい」場合に使います。

    • NotFound
    • PermissionDenied
    • Conflict
    • RateLimit

安易に増やすと、分岐が増えて保守がつらくなります。

いつ typed error を使うか

typed error は「追加情報が必要で、呼び出し元が取り出したい」場合に向きます。

    • フィールド名、バリデーション種別
    • 下流サービス名、HTTPステータス
    • リトライ可能かどうか

実装テンプレ

sentinel error

package app

import "errors"

var ErrNotFound = errors.New("not found")

呼び出し側

if errors.Is(err, app.ErrNotFound) {
    // 404
}

typed error

package app

import "fmt"

type ValidationError struct {
    Field string
    Code  string
}

func (e *ValidationError) Error() string {
    return fmt.Sprintf("validation failed: field=%s code=%s", e.Field, e.Code)
}

呼び出し側

var ve *app.ValidationError
if errors.As(err, &ve) {
    // ve.Field, ve.Code を使ってレスポンスを組み立てる
}

ラップ(文脈を足す)

if err != nil {
    return fmt.Errorf("get user: id=%s: %w", id, err)
}

文脈を足すと調査が速くなります。
ただし、秘密情報を入れないように注意します。

ログ設計との分担

エラー文字列に全部を入れると、冗長になりすぎます。

  • エラー
    • 文脈(どの処理で失敗したか)
    • 呼び出し元が分岐できる種類
  • ログ
    • requestId、traceId
    • 引数の一部(個人情報はマスク)
    • 下流のレスポンス要約

よくある落とし穴

  • errors.Is を使わずに == で比較する
    • ラップすると一致しない
  • typed error の値型とポインタ型を混ぜて As が通らない
    • どちらで返すか方針を固定する
  • エラー文に個人情報やトークンを入れる
    • ログ共有で事故る

レビュー用チェックリスト

  • 文字列比較で分岐していない
  • 失敗時に文脈が追加されている
  • 呼び出し元が分岐したい種類が明確(sentinel または typed)
  • 個人情報や秘密情報がエラー文に含まれない
  • errors.Is / errors.As の使い分けができている
9
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?