はじめに、この文書の目的
- 流れとしては、catch(Exception e) {} の撲滅 と、これに続くポエムを書いてます。
- Exceptionで書いてますが、エラーとは何なのか?どう扱うべきか?を考察
- プログラマへ「Exception を黙殺 しないほうがメリットあるよ」を伝えたい
- 設計者へ「超レアな Exception の扱いを決める設計をすべきだ」と伝えたい
あるプログラマの行動
- 「あぁ、例外ね。それ発生しないから、よくわからないから、黙殺しておけばいいや。catch(Exception e) {} でOK」
- これ最悪です。
立場を変えて考えてみます。
- throw Exception している側は、(非常にレアであったとしても)異常事態が発生しているから throw してるんです。
例外を黙殺するとどうなるか?
- Exceptionが発生しても、何事もなかったかのようにあたかも正常に動き続ける。
- 怖いですね「子供が頭痛い!」と言ってるのに親は無視し続けるんですね。
- 後々取り返しのつかないことになりませんか?後悔しませんか?
なぜ、プログラマ(使う側)はExceptionを黙殺してしまうのか?
- 設計で扱いが決まっているExceptionはちゃんと処理しますよね。(通信エラーのリトライとか)
- 問題は、設計で扱いが決まっていない例外の扱い方です。そこでプログラマが「扱いが決まっていない→黙殺でいいや」という選択をしてしまうんですね。
では、扱いが決まっていない例外はどうすればいいのか?
- 「扱いが決まっていない例外 → catchしてそのままthrow」しましょう。
- これが正解です。
「え?よくわからない例外をthrowしていいの?」と思った人へ
- そもそも、設計で扱いが決まっていない例外とは、超レアな例外のことです。(発生することが、実質あり得ないから、設計が無いんですね)
- だから、発生することはほぼ絶対にありません。だから、黙殺しようがthrowしようが、実際にはそのコードが実行されることはないので、そういう意味ではどちらを選択しても同じなんです。
- でもあえてどちらか選択するなら、*仮に発生したとき*のことを考えるなら、黙殺するよりはthrowの方がましですね。(ところが、本当に発生したときは最強の味方になってくれます)
「超レアな例外で、ほぼ絶対発生しないなら、やっぱり黙殺してもいいじゃん」と思った人へ
- 今は「ほぼ絶対発生しない」と思っていますが、運用フェーズに入ると、突然発生したりするんです。
- 人間の想定できる範囲(設計力)には限界があります。現実はそれを軽く超えてきます。
- 黙殺してると、現実が超えてきたとき、手も足も出ないんです。開発フェーズなら打てる手はたくさんありますが、運用フェーズだと死にます。
「いやいや、お前は例外をthrowするという意味を分かってるのか?システム止まるんだぞ?そんな怖いこと書く勇気はないぞ」と思った人へ
- 気持ちはわかります。ごめんなさい。本当のことを書きます。
- 実は、この問題、設計が悪いんです。なぜか?
- 「超レアな例外をどう扱うか?」設計していないからです。だから設計しましょう。
「いやいや、超レアな例外をどう設計するんだ?」と思った人へ
- 例えば「超レアな例外は、最上位のクラスでcatchし、ERRORとしてログ出力してシステムは継続する」とするのはどうでしょうか。
- ほら、もう安心して、超レアな例外をthrowできますね。
「いやいや、超レアな例外発生しているのに、ログ吐いてシステム継続なんていう、そんないい加減な設計では困るんだ」と思った人へ
- ごめんなさい。(正体不明な原因で発生した)超レアな例外をちゃんと復旧する方法なんてわかりません。
- そもそも、超レアケースなのでログ出力だけで我慢してください。
「いやいや、超レアな例外でも、発生原因が分かるものはあるでしょう?そういうのは、ちゃんと設計してもらわないと困るんだ」と思った人へ
- 超レアなんですよ?普通発生しないですよ?本当に設計しますか?
- 設計だけで終わりませんよ?実装も試験も運用も工数増えますよ?
- 費用対効果は悪いですよ?負担する覚悟はありますか?
- で、本当にやりますか?