コンテンツにスキップ

4-3. 例外処理・ログの考え方

  • エラーと例外をどう捉えるか
  • try / catch / finally の役割
  • エラーを無視せず、状況を残すことの重要性
  • ログがデバッグや運用でどう役立つか

どれだけ丁寧にコードを書いても、現実のシステムでは次のようなことが起こる。

  • 入力値が想定外だった
  • ファイルや API が取得できなかった
  • JSON や数値への変換に失敗した
  • 必要なデータが不足していた

つまりプログラムは、常に成功するとは限らない。

そこで必要になるのが、異常系をどう扱うかという考え方である。
その中心にあるのが例外処理である。

正常系
入力 → 処理 → 出力
例外発生時
入力 → 処理 → エラー発生
↓
どう扱うか決める

例外処理の目的は、「エラーを完全になくすこと」ではなく、起きたときに壊れ方を制御することである。


2. エラーにはいくつか種類がある

Section titled “2. エラーにはいくつか種類がある”

初学者は、すべてのエラーを同じものとして捉えがちである。
しかし実際には、性質の違うエラーがある。

種類例何が問題か
構文エラー括弧の閉じ忘れコードの形そのものが不正
実行時エラー / 例外不正な値で処理した実行中に問題が起きた
業務ルール違反残高不足、必須項目不足入力はあるがルールを満たさない

この章では特に、実行中に起きた問題をどう扱うかを中心に学ぶ。

業務ルール違反は概念上は「入力はあるがルールを満たしていない状態」として分けて考えられる。
ただし実際のプログラムでは、その問題を上位へ伝えるために throw を使って Error を投げ、例外として扱うことも多い。

throw は、「ここでは正常に処理を続けられない」と判断したときに、問題を呼び出し元へ伝えるための構文である。

if (amount > balance) {
throw new Error("insufficient balance");
}

このように書くと、その場で問題を明示し、上位の try / catch 側で受け取って扱える。
つまり throw は、問題を隠すのではなく見える形で伝えるための手段である。


JavaScript では、例外処理の基本として try / catch / finally を使う。

const text = '{"name":"Sato"}';
try {
const data = JSON.parse(text);
console.log(data.name);
} catch (error) {
console.error("Failed to parse JSON:", error.message);
} finally {
console.log("finished");
}

たとえば text の末尾の } を消した壊れた JSON に変えると、JSON.parse() が失敗して catch に入る。

部分役割
tryまず実行してみる処理を書く
catch例外が起きたときの処理を書く
finally成功・失敗にかかわらず最後に行う処理を書く
try を実行
↓
例外なし ─────→ finally
↓
例外あり
↓
catch を実行
↓
finally

finally は、後片付けや終了ログなど「最後に必ず行いたい処理」を置くのに向いている。


4. 例外処理でやってはいけないこと

Section titled “4. 例外処理でやってはいけないこと”

例外処理は便利だが、使い方を誤ると問題を隠してしまう。

たとえば次のコードはよくない。

try {
riskyOperation();
} catch (error) {
}

catch の中が空だと、問題が起きても「何が起きたのか」が分からなくなる。
これは**サイレントフェイル(黙って失敗する状態)**につながりやすい。

  • 例外を握りつぶさない
  • 回復できるなら回復する
  • 回復できないなら、少なくとも状況を記録する
  • 必要なら上位へエラーを伝える

つまり catch は「とりあえず無視する場所」ではなく、そのエラーにどう向き合うか決める場所である。


ログとは、プログラムの中で何が起きたかを記録するメッセージである。

プログラム実行中
↓
[INFO] start order process
[WARN] input is missing optional field
[ERROR] failed to save order

ログが重要なのは、エラーが起きた瞬間に人が見ていないことが多いからである。
後から調査するとき、ログは「何が起きたか」を知る大事な手掛かりになる。

レベル使いどころ
INFO正常な進行や開始・終了の記録
WARNすぐ停止はしないが、注意したい状態
ERROR処理失敗や例外など、明確な問題

良いログには、次の要素がある。

  • 何をしていたか
  • どの入力や ID を扱っていたか
  • 成功したのか失敗したのか
  • エラーならメッセージは何か

たとえば、単に failed とだけ出すより、[ERROR] withdraw failed: insufficient balance のほうが原因を追いやすい。


6. ログに書いてよいこと、避けるべきこと

Section titled “6. ログに書いてよいこと、避けるべきこと”

ログは多ければよいわけではない。
何でも出すと、重要な情報が埋もれたり、機密情報を漏らしたりする危険がある。

  • 処理名
  • 対象 ID
  • 入力値の要約
  • エラーメッセージ
  • 処理の成否

そのまま出さないほうがよいもの

Section titled “そのまま出さないほうがよいもの”
  • パスワード
  • アクセストークン
  • 個人情報の全文
  • 不要に大量の内部データ

ログは「調査しやすさ」と「安全性」の両方を意識する必要がある。


7. 例外処理とログはどう組み合わさるか

Section titled “7. 例外処理とログはどう組み合わさるか”

例外処理とログは別のものだが、実務ではよく一緒に使う。

処理開始
↓
問題発生
↓
catch で状況を受け止める
↓
ログへ記録する
↓
必要なら安全なメッセージを返す

ここで重要なのは、「ユーザーへ見せる内容」と「開発者が調査に使う内容」を分けることだ。
ユーザーには分かりやすい説明、開発者には原因を追える情報が必要になる。


catch したら問題解決、ではない

Section titled “catch したら問題解決、ではない”

catch は、エラーを受け取っただけである。
そこから「回復する」「ログを残す」「処理を止める」などを決める必要がある。

ログはデバッグ用の独り言ではない

Section titled “ログはデバッグ用の独り言ではない”

ログは、あとで他の人が読んでも意味が分かる必要がある。
そのため、文脈のない短いメッセージより、状況が分かる文のほうがよい。

すべてを巨大な try / catch で囲むと、どこで何が失敗したのか見えにくくなる。
必要な範囲で扱うことが大切である。


キーワード説明
例外実行中に起きた問題を表すもの
throw問題を上位へ伝えるために例外を投げる構文
tryまず実行してみる処理を書く場所
catch例外が起きたときの処理を書く場所
finally最後に必ず実行したい処理を書く場所
サイレントフェイルエラーを黙って握りつぶしてしまう状態
ログ何が起きたかを記録するメッセージ
INFO / WARN / ERRORログの重要度を表す目安

演習問題 に取り組んで理解を確認しよう。

理解できたら 4-4. アルゴリズムとデータ構造入門 へ進もう。