エラーハンドリング
例外・Result型・エラー境界を用いた堅牢なエラー処理設計と、エラーの分類・伝播・復旧戦略
エラーハンドリングはシステムの堅牢性を左右するにもかかわらず、設計の後回しにされがちな領域だ。エラーは大きく「予期可能なエラー」と「バグ」に分類できる。前者はバリデーション失敗・リソース不存在・外部APIの一時的な失敗など、ビジネスロジックの一部として扱うべきケースだ。後者はNullPointerExceptionや存在しないプロパティへのアクセスなど、プログラムの誤りに起因し、握りつぶさず表面化させるべきものだ。
例外(Exception)は制御フローを非局所的に変化させるため、呼び出し元が明示的にcatchしなければエラーが見えない。Result型(成功値と失敗値をUnion型で返す)はエラーを型として明示し、呼び出し元がエラー処理を強制される。TypeScriptではネイティブなResult型はないが、Effectライブラリや自前実装で実現できる。どちらが適切かはエラーの性質と伝播距離による判断が必要だ。
エラーバウンダリはエラーの影響範囲を限定するための構造だ。ReactのError Boundaryはコンポーネントツリーのクラッシュを局所化し、他の部分の表示を維持する。バックエンドではミドルウェアやグローバルExceptionHandlerがこの役割を担う。エラーの情報量も重要で、スタックトレース・操作ID・コンテキスト情報を含めたログを残すことで、本番環境でのデバッグが可能になる。ユーザー向けのエラーメッセージは、内部のエラー詳細を漏らさず・かつ次のアクションが分かるものにすべきだ。
コードレビューで着目するポイント
- エラーを握りつぶしていないか(catch節が空・console.logだけで終わる)
- 予期可能なエラーと予期できないバグが同じcatch節で処理されていないか
- エラーの型情報が失われていないか(Error型を
anyでキャッチ・再スロー時の情報消失) - エラーメッセージにスタックトレースや操作IDなどのデバッグ情報が含まれているか
- ユーザー向けメッセージに内部エラーの詳細が露出していないか(セキュリティ)
- Resultやエラー型の伝播先でエラーケースが処理されているか(TypeScriptのnever型等で網羅性チェック)
- 非同期処理においてPromiseのrejectが適切にハンドリングされているか
典型的なアンチパターン
空のcatch: try { ... } catch (e) {} によってエラーが完全に隠蔽される。実行時に何かが失敗しても誰も気づかず、データの不整合が蓄積してから後でサービス障害として表面化する。
エラーメッセージの情報過多(情報漏洩): Stackトレースやデータベーススキーマの詳細をAPIレスポンスに含める。攻撃者に内部構造を開示し、セキュリティインシデントの糸口になる。
try-catchを制御フローとして使う: 例外を予期される状態遷移のトリガーとして使う(例:ユーザー未存在を例外で判定)。例外は高コストで意図が読みにくく、if文またはResult型で表現すべきだ。
参考リソース
- Joe Armstrong「Let It Crash」哲学(Erlangの設計思想)
- Effect-TS https://effect.website — 型安全なエラー処理チャンネル付きランタイム
- neverthrow https://github.com/supermacro/neverthrow — TypeScriptのResult型ライブラリ
- OWASP「Error Handling」チートシート https://cheatsheetseries.owasp.org
- Sentry https://sentry.io — エラートラッキングとコンテキスト情報の収集
- 1. 📄アーキテクチャスタイル
- 2. 📄ドメインモデリング
- 3. 📄モジュール分割と依存管理
- 4. 📄データモデリング
- 5. 📄API設計
- 6. 📄整合性とトランザクション
- 7. 📄非同期処理(Queue/Event)
- 8. 📄キャッシング
- 9. 📄ユーザーリサーチ
- 10. 📄情報アーキテクチャ
- 11. 📄インタラクションデザイン
- 12. 📄UX原則とヒューリスティクス
- 13. 📄アクセシビリティ(UX観点)
- 14. 📄UXメトリクス
- 15. 📄スケーラビリティ
- 16. 📄可用性とレジリエンス
- 17. 📄オブザーバビリティ
- 18. 📄環境・インフラ設計
- 19. 📄データマイグレーション
- 20. 📄セキュリティ設計原則
- 21. 📄データ保護とマルチテナント
- 22. 📄LLMセキュリティ
- 23. 📄ビジュアルデザイン原則
- 24. 📄デザインシステム
- 25. 📄コンポーネント設計
- 26. 📄スタイリング
- 27. 📄設計原則
- 28. 📄デザインパターン(GoF)
- 29. 📄エンタープライズパターン
- 30. 📄クリーンコード
- 31. 📄リファクタリング
- 32. 📄型設計とコントラクト
- 33. 📄関数型プログラミング概念
- 34. 📄エラーハンドリング
- 35. 📄テスト戦略と哲学
- 36. 📄テスト種別(機能テスト)
- 37. 📄テスト種別(UI・ビジュアル)
- 38. 📄テスト種別(契約・境界)
- 39. 📄並行処理・マルチスレッド
- 40. 📄パフォーマンス最適化
- 41. 📄ドキュメント管理
- 42. 📄バージョン管理と開発プロセス
- 43. 📄脅威モデリング
- 44. 📄通信保護(TLS)
- 45. 📄暗号化・機密情報管理
- 46. 📄認証・セッション管理
- 47. 📄認可・アクセス制御
- 48. 📄入力バリデーション
- 49. 📄インジェクション攻撃
- 50. 📄正規化(データベース正規化)