例外設計
例外の分類
table:例外とエラー
Expected and Accepted Expected but Unaccepted Unexpected
Ruby (正常系) 例外 (StandardError) 例外 (Exception)
Java (正常系) 例外(Exception) エラー (Error)
Go (正常系) error panic
Python (正常系) 例外 (XxxError) 例外(その他)
JIS X0014 (正常系) 障害(fault) 故障(failure)
各言語によって違いはあるが、ここでは、Expected but Unacceptedを「予期する例外」Unexpectedを「予期しない例外」と呼ぶ。ここで「予期する」かどうかはプログラム上で明示的に具象型の例外をキャッチしハンドリングするかどうかを指し、人間が予想しうるかどうかではない。
予期する失敗
予期する失敗は、以下のようなものである。
業務上発生しうるが、プロセスを継続できないもの。
不正な入力値
同時更新における排他
自責ではどうもできない。(High AvailabilityなSLAがある場合は、予期しない例外とするケースもある。AWSのマネージドサービスの障害など)
外部サービスのAPI呼び出しのサーバ側のエラー
長くかかる処理のタイムアウト
予期しない失敗
予期しない失敗は以下のようなものである。
あるはずのファイル/ディレクトリが無い
設定ファイルのデプロイミス
リリース作業時のディレクトリ作成忘れ
データベースのマイグレーション漏れ
リソースの不足
Out of Memory
Disk full
ネットワーク断
まとめ
table:比較
予期する失敗 予期しない失敗
実装 例外またはResult Type 例外を持つ言語であれば通常例外で実装するか?
テスト かならず1ケース以上はやる 端折っても良い※1
※1 発生したらシステムに重大なダメージ与える可能性があるならばやっておく。
ハンドリング
予期する失敗は、それが発生するレイヤーまたは、1つ上位のレイヤで必ずキャッチし、可能であればリカバリする。
予期しない失敗は、それが発生するレイヤーではキャッチせず上位レイヤにあげる。各レイヤでリカバリ処理としてやれることがなければ、最上位レイヤまで伝播させてクライアントに通知する必要があれば、そこでキャッチする。