はじめに
システムは、常に正常に動作するとは限りません。入力値が不正な場合、通信に失敗した場合、データベースへ接続できない場合など、処理を予定どおりに完了できない状況は必ず起こり得ます。
このとき重要なのは、例外をどのようなコードで処理するかだけではありません。利用者へ何を伝え、処理を継続するのか中止するのか、どの情報を記録し、運用担当者へ通知するのかを、設計段階で決めておく必要があります。
エラー処理を実装者の判断へ任せると、画面や機能ごとに対応がばらつきます。この記事では、エラー処理を設計で決める理由と、設計時に整理すべき項目を解説します。
エラー処理はシステムの振る舞いを決める設計
例外処理という言葉から、try-catchやthrowなどのプログラミング機能を思い浮かべる人も多いでしょう。しかし、これらは設計したエラー処理を実現するための手段です。
設計で決めるのは、エラーが起きたときにシステムがどのように振る舞うかです。例えば、利用者へ表示する内容、処理の継続可否、再試行の有無、データ更新の取り消し、ログや通知の方法などが該当します。
同じ種類のエラーに対して画面や機能ごとに異なる振る舞いをすると、利用者や運用担当者はシステムの状態を判断できません。エラー処理は、プログラマー個人の書き方ではなく、システム全体で統一すべき設計です。
エラー処理を実装任せにすると対応がばらつく
設計で方針が決まっていなければ、実装者はエラーが発生するたびに対応を判断することになります。
ある処理では例外をログへ記録して中断し、別の処理ではメッセージだけを表示することがあります。例外を処理せず上位へ渡す実装や、問題を記録しないまま処理を続ける実装が混在することもあります。
個々の処理だけを見れば動作していても、システム全体では一貫性が失われます。その結果、同じような操作で異なるメッセージが表示されたり、障害調査に必要な情報が残っていなかったりして、保守や運用の負担が増えます。
実装者の自由度をなくすことが目的ではありません。共通の判断基準を設計で示し、機能固有の違いだけを実装時に判断できる状態にすることが重要です。
設計で決めるべきエラー処理の項目
エラー処理の設計では、主に次の項目を整理します。
| 項目 | 設計で決めること |
|---|---|
| 利用者への表示 | 何が起きたか、利用者が次に何をすればよいかをどのように伝えるか |
| 処理の継続・中止 | エラーが起きても処理を続けるのか、その時点で中止するのか |
| 再試行 | 一時的な失敗に対して再試行するか、どのような条件で中止するか |
| ロールバック | 更新途中のデータを取り消す必要があるか、どの範囲を元へ戻すか |
| ログ | どのエラーを、どの情報と重要度で記録するか |
| 運用通知 | 運用担当者へ通知するエラーと、通知方法をどうするか |
利用者向けのメッセージと、開発者や運用担当者が調査に使う情報は役割が異なります。内部の技術情報をそのまま利用者へ表示するのではなく、利用者には必要な行動が分かる内容を示し、詳しい原因はログへ記録します。
ログへ残す情報、ログレベル、保存や運用まで含めた考え方は、ログ設計はなぜ必要なのか|障害調査と運用効率を左右する設計の考え方で詳しく解説しています。
エラーの種類と影響に応じて対応を分ける
すべてのエラーや異常な状態を、同じ方法で処理する必要はありません。何が起きたかだけでなく、その原因とシステムへの影響を確認して対応を決めます。
| 状況 | 主な対応例 |
|---|---|
| 利用者の入力に誤りがある | 入力内容を修正できるようにメッセージを表示する |
| 検索結果が存在しない | エラーではなく、0件という正常な結果として表示する |
| 一時的な通信失敗が起きた | 条件を満たす場合は再試行し、回復しなければ処理を中止する |
| データ更新に失敗した | 処理を中止し、必要に応じて更新内容をロールバックする |
| システム障害が発生した | 処理を中止し、ログを記録して運用担当者へ通知する |
例えば、検索結果が0件であることと、データ取得処理そのものに失敗したことは異なります。両者を同じ結果として扱うと、利用者は「該当する情報がない」のか「システムが正常に動いていない」のか判断できません。
「エラーが発生したらメッセージを表示する」とだけ決めても、十分な設計にはなりません。エラーの種類、影響範囲、回復可能性を整理し、それぞれの対応を決める必要があります。
基本設計と詳細設計で決める内容を分ける
エラー処理は、一つの工程ですべてを決めるものではありません。外部から見た振る舞いと、内部での実現方法を段階的に具体化します。
基本設計では、利用者へ表示する内容、処理を継続できる条件、機能として保証する振る舞いなどを決めます。詳細設計では、エラーをどの処理で検知するか、例外をどこへ伝えるか、再試行やロールバックをどの範囲で行うか、どこでログや通知を実行するかを具体化します。
| 工程 | エラー処理で主に決めること |
|---|---|
| 基本設計 | 利用者や外部システムから見たエラー時の振る舞い |
| 詳細設計 | その振る舞いを実現する内部処理、分岐、例外の伝達、記録方法 |
| 実装 | 設計内容をコードや設定として実現する |
| テスト | 正常時だけでなく、異常時にも設計どおり動作するか確認する |
基本設計の役割は、基本設計とは?目的と決めることをわかりやすく解説で説明しています。内部の処理へ具体化する方法は、詳細設計とは?目的と決めることをわかりやすく解説を参照してください。
要件定義から実装・テストまでのつながりは、システム設計の工程とは?要件定義・基本設計・詳細設計の流れを解説で整理しています。
実装は設計したエラー処理を実現する工程
実装では、設計した方針に従って、例外クラス、エラーコード、try-catch、トランザクション制御などを使用します。
どの機能を使うかは、プログラミング言語やフレームワークによって異なります。しかし、「どの状況で処理を止めるか」「利用者へ何を伝えるか」「何を記録するか」という判断は、実装技術が変わっても必要です。
例外処理のコードが書かれているだけでは、エラー処理を設計したことにはなりません。設計した振る舞いと実装内容が対応し、レビューやテストで確認できる状態にすることが重要です。
まとめ
エラー処理は、例外を捕捉するためのプログラミング技術だけではありません。利用者への表示、処理の継続・中止、再試行、ロールバック、ログ、運用通知まで含めたシステムの振る舞いを決める設計です。
実装者ごとに判断すると、機能によって対応が異なり、利用者の混乱や障害調査の長期化につながります。設計段階で共通の方針と判断基準を決めておけば、担当者が変わっても一貫した品質を保ちやすくなります。
正常に動作するときだけでなく、失敗したときにシステムがどう振る舞うかまで決めることが、運用しやすく保守性の高いシステム設計につながります。