Errorを3つに分類する
ビジネスロジックの一部である
明示的に処理する
想定できる状態の一部なので型で明示すべき
ビジネスロジックの外である
想定内である
技術的エラーとしてログ、監視、再試行などする
場合により型で明示しても良いが、多くは例外扱い
想定外である
アラートし、修正対象である
例外として扱う
関連
彼は次のような「Result乱用パターン」を戒めていますgpt-5.icon
1. 診断情報が欲しいときは使うな
Result では stack trace や error location が失われる。
例外を無理やり Result に詰め直すのは本末転倒。
2. 例外の再発明をするな
あらゆるエラーを Result で返すのは間違い。
結局どこかで例外は発生するので、適切に try-catch を使え。
3. 「即終了」したいなら Result ではなく例外を投げろ
4. 内部制御フローでしか使わないなら無理に Result を使うな
内部処理だけで閉じる複雑な制御は、ローカル例外の方が読みやすい
Resultは外部に対して意味のある失敗を明示するための型であって、内部のロジック制御のために使うものではない
もしその「失敗」が外に伝わらず、関数内で完結しているならResult を経由するのは冗長
code:bad.ts
function traverseTree(node: Node): Result<Value, Error> {
if (node.isInvalid()) return err('invalid node'); // 失敗としてResult返す
for (const child of node.children) {
const result = traverseTree(child);
if (result.isErr()) return result; // 伝播させる
}
return ok(node.value);
}
このようにResultで「失敗したら早期終了」するロジックを書くと、内部での値伝搬やbind処理が煩雑になりやすい
対案:ローカル例外で処理した方が簡潔
code:ts
class EarlyExit extends Error {}
function traverseTree(node: Node): Value {
if (node.isInvalid()) throw new EarlyExit();
for (const child of node.children) traverseTree(child);
return node.value;
}
try {
traverseTree(root);
} catch (e) {
if (e instanceof EarlyExit) console.log("invalid tree");
}
5. 誰もエラー理由を気にしないなら Result を返すな
消費側が「失敗したこと」しか気にしないなら Option で十分。
6. I/O すべてを Result でモデル化しようとするな
ファイルやネットワークには無限に失敗要因がある。
ドメインで意味を持つ最小限だけを Result 化し、他は例外でよい。
7. パフォーマンス重視箇所では注意
小さい構造体でもオーバーヘッドになる場合がある。
8. 異言語連携(interop)には不向き
OO 言語の呼び出し元に Result を押し付けるのは親切でない。
結論として
Result はドメインモデリングのための道具であり、ドメインで意味を持たない失敗には使うべきでない