例外処理の書き方について気になったので書いてみる。
##事例から
Javaを例に挙げると、
public class hogeAction {
public String main() {
try {
・・・
ビジネスロジック
・・・
} catch (Throwable e) {
return null;
}
return foo;
}
}
このようになんでもCatchしちゃう包容力の高いコードをたまに見る。
こういうコードを見つけると、「臭うぞ!!」と思うのは自分だけだろうか?
まあ直接的すぎるのもあれなので、
「ちょっと例外処理広すぎやしませんか?
例外処理は必要最低限の範囲で意図したものだけCatchしましょうよ」
くらいにレビューフィードバックしたりする。
言語やチームに限らず、ここまで激しくなくても、必要以上に大きくTry Catchで囲って必要以上にCatchする書き方をするエンジニアを数多く見てきた。
##なぜこういうコードが生まれるのか
あまりにも多いので、こういう書き方が昔は流行してたのかなーとも思い、Twitterなどで問いかけてみたけどどうやらそうでもなさそう。
ってことでせっかくなので理由を聞いてみたところ多かった回答は、
「あまり意識して書いてなかった」
「もし漏れていたら処理(表示)に影響するので・・・」
といった回答だった。
##つっこんでみる
前者は置いておいて、
「もし漏れていたら処理(表示)に影響するので・・・」
につっこんでみる。
意図したコードをかけていないのでは?
意図して書けている自信がないコードをプロダクトコードにのせていることが果たしてよいのだろうか?
ビジネスロジックだろうと予約メソッドだろうと、InputとOutputのパターンを理解できているのであれば、そのパターンごとに意図した適切な処理を書けばいい。
それでも漏れるかもしれないから念のため?
もちろん人間だからバグを生む可能性があることは前提にすべきである。
だけどもしそうであればなおさら、ビジネスロジックでわざわざそう書かないと漏れたときに処理(表示)に影響しちゃう設計を疑うべきではないだろうか?
- Try Catchで囲うのを忘れてしまった場合
- このFunctionよりも大きいところで例外が発生した場合
に結局漏れちゃうのではないだろうか?
##どうするのがいいのか考えてみる
自分が考えてみた答えは、
- セーフティーネットとしての例外処理
- 意思を持った例外処理
をわけることである。
セーフティーネットとしての例外処理とは
「それでも漏れるかもしれないから念のため」を拾うための例外処理がセーフティーネットとしての例外処理だ。
人間がバグを生む可能性が以上、それをそのままユーザーにさらすのはよろしくないので、セーフティーネットは必要であろう。
ただし、先ほど述べた通り、これをビジネスロジックで意識して書かないとセーフティーネットにならないのはリスクである。
フレームワークレベルなどビジネスロジックの範囲を包括する深い層で例外処理を行い、ビジネスロジックで意識しなくてもよい状態にするのが好ましい。
意思を持った例外処理とは
ほとんどの場合の例外処理と言われるものがこちらのことである。
ビジネスロジックで書く例外処理はこちらのことだ。
セーフティーネットとしての例外処理がされている前提であれば、意思を持ってコーディングを行い、意図した部分だけで意図した例外のみをCatchして適切な例外処理を行えばいい。
バグは見つけて直す!!
例外処理もコードであり、意図していない場所で例外が発生した場合はもはやバグと呼んでいい。
つまるところ、セーフティーネットとしての例外処理にひかかったものが見つかった場合、基本的には適切な処理になるようにコードを直すべきである。
バグは変に握りつぶしてしまうよりも、バグらしくバグとして見つかる状態にしてとっとと直す方が健全である。
まとめると・・・
- セーフティーネットとしての例外処理と意思を持った例外処理をわけて考える
- セーフティーネットとしての例外処理は、ビジネスロジックで意図しなくてもいい層で行う
- 意思を持った例外処理は、意図した部分で意図した例外のみを処理する
- セーフティーネットとしての例外処理にひかかったことがわかった場合はバグなのでとっとと直す
が私の考えです。
皆さんがは例外処理についてどう考えますか?
また、この考えは誰かから教えてもらったものなのか、なにかの本で読んだのかまったく記憶にありません。
よい本や文献などあればぜひご紹介ください。