- エラー処理は実装ではなく「仕様」の中心に置く
- なぜエラー仕様が必要なのか
- よくある誤解
- エラーの分類
- 仕様として書くべき内容
- テストとしてのエラー仕様
- API設計との関係
- 注意点 ― 例外を握りつぶさない
- まとめ ― 安定するシステムは失敗時に決まる
エラー処理は実装ではなく「仕様」の中心に置く
SDD(仕様駆動開発)で最も軽視されやすく、そして最も重要な領域があります。
エラーハンドリングです。
多くの開発では、エラー処理は実装の後半に書かれます。
- とりあえず例外を投げる
- 失敗したらメッセージを出す
- ログを残す
しかしSDDの観点では、これは順序が逆です。
エラーハンドリングは付属処理ではありません。
システムが何を保証するかを定義する仕様です。
成功時の挙動だけを仕様にしても、ソフトウェアの振る舞いは決まりません。
現実のシステムは、むしろ失敗時にこそ振る舞いが問われます。
なぜエラー仕様が必要なのか
次の問いに答えられるでしょうか。
「処理が途中で失敗したとき、システムはどの状態になるか」
これが未定義のままでも、プログラムは動きます。
しかし、安定はしません。
例えば注文処理。
- 決済成功
- 在庫更新失敗
このとき、
- 注文は成立するのか
- 返金するのか
- 再試行するのか
これは実装判断ではありません。
仕様です。
エラー仕様がない状態とは、
「障害時の挙動を開発者が都度決めるシステム」
を意味します。
よくある誤解
「エラーは想定外だから、仕様化できない」
逆です。
想定外のものは仕様にできません。
しかし、ほとんどのエラーは想定内です。
例:
- 入力不正
- 権限不足
- 外部API障害
- タイムアウト
- 同時更新
これらは発生確率が高い現象です。
仕様化しない方が不自然です。
エラーの分類
まずエラーを分けます。
SDDではここが重要です。
1. 業務エラー(Business Error)**
- 在庫不足
- 上限超過
- 重複登録
これは失敗ではなく、許可されない操作です。
例外ではありません。
2. システムエラー(System Error)**
- DB接続失敗
- APIタイムアウト
- 内部例外
これは処理失敗です。
この2つを区別しないと、UI・API・ログが破綻します。
仕様として書くべき内容
最低限、次を定義します。
- 失敗時の状態
- 再試行の可否
- 利用者への通知
- ロールバック範囲
例:支払い処理
| 状況 | システム状態 | 利用者表示 |
| カード拒否 | 未注文 | 再入力 |
| 決済成功・在庫失敗 | 未確定 | 処理中表示 |
| 通信断 | 不明 | 保留表示 |
ここまで書いて初めて、振る舞いが決まります。
テストとしてのエラー仕様
SDDでは、これをテストにします。
- 在庫不足なら注文生成されない
- タイムアウトなら確定しない
- 再試行で成功する
成功ケースより先に、失敗ケースのテストを書きます。
これにより、例外処理が設計になります。
API設計との関係
エラー仕様が曖昧だと、APIが壊れます。
悪い例:
- 200と500しかない
- メッセージ文字列だけ
良い例:
- 409:業務競合
- 422:入力不正
- 503:外部依存失敗
コードと状態を対応させます。
クライアントはこれで挙動を決定できます。
注意点 ― 例外を握りつぶさない
ありがちな実装があります。
「とりあえず成功扱いにする」
これは短期的には安定します。
長期的にはデータ不整合になります。
仕様で決めるべきは、
失敗を隠すかではなく、
失敗をどう扱うかです。
まとめ ― 安定するシステムは失敗時に決まる
多くの仕様書は、成功時の流れを中心に書かれます。
しかし利用者が困るのは失敗時です。
エラーハンドリング仕様を書くと、次が明確になります。
- どこまでが成功か
- いつ再操作できるか
- 誰が復旧するか
結果として、問い合わせが減ります。
そして開発者も迷わなくなります。
成功フローだけの仕様は、完成図です。
エラーまで含めた仕様が、設計図です。
SDDでは、例外処理は最後に付け足すものではありません。
最初に定義することで、システムの振る舞いが初めて安定します。