コンテンツにスキップ

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. アルゴリズムとデータ構造入門 へ進もう。