chofutaroメモ

ソフトウェアエンジニアによるソフトウェアエンジニアのためのメモ書き

例外について考えてみました

例外について考えてみました。例外を文法として持つ言語を使って開発する場合、例外をどのように取り扱うかがいつも議論になっているように感じるため、自分の考えを改めて整理しておいた方が良いと感じました。

最初に

私が師匠と思っている人に”Javaを復習するにはどんな本がよいか”という観点で「Java: The Good Parts」という本を薦めていただきました。まだ読み始めなのですが私のニーズにぴったりです。

Java: The Good Parts

Java: The Good Parts

この本の著者はチェック例外について言及していますが、私は、Java言語のチェック例外機構そのものに問題はないと感じています*1
話が発散しているかもしれませんが、例外を考える上で重要なのは例外に対する設計思想だと思います。システム設計の中で例外(的な事象*2)をどう取り扱うのかしっかり方針を立て、その方針に基づき大勢のプログラマの意思統一をどう図るのか、というのが大切なんだと思います。

結論

理由は後で記す*3として、まず結論を列挙しておきます。

  • 検査例外は必要(使う)。そして設計によって例外クラス全体の継承構造を管理する*4
  • 検査例外の最上位クラスがExceptionクラスにならないよう、これに替わる例外クラス(ここではControlledExceptionと仮定します)を、開発に携わる人全員に共通したクラスとして定義する。
  • ソフトウェアの要求機能・性能として、エラー*5の回復を義務づけられているケースでは、ControlledExceptionを使う。それ以外は、RuntimeException及びその派生クラスを使う。
  • エラーが発生したパッケージ内でエラーの処置ができない場合、パッケージの公開インタフェースとしてControlledExceptionを使い、当該パッケージ内部では、必ずしもControlledExceptionを使わなくとも良い。

結論に至る根拠

検査例外は不要だという人たちの根拠

トレンドとして、どちらかと言うと”検査例外は不要”という話が多いように見受けられます。そこで、その説を支持している人たちの根拠を整理してみました。

  • 検査例外を使うと、Versioningの問題が顕著になる : 部品クラスにおいて、従来無かった検査例外を新たにスローするようコードを変更した場合、呼び出し側のクラスにおいてもコードの変更が必要になる。
  • 検査例外を使うと、Scalablityの問題あるいは例外連鎖が顕著になる : 検査例外を使用すると、例外をメソッドはそのメソッドの抽象化レベルにあわせて投げる必要があり、メソッドの実装方法の詳細に合わせた例外を使えない。仮に使うことを許してしまうと、Versioningの問題が顕在化し、メソッドの内部仕様を公開 し、抽象化のレベルに応じて例外クラスの数が増える、ことになる。
  • 検査例外を使うと、RuntimeExceptionの飲み込みが顕著になる : 例外を受け取る側では、詳細な例外が何であれ、例外的な事象に対する処置はひとつであることが多です。このことから例外的な事象に対して処置する側は、Exceptionでキャッチ(Exception派生例外を一網打尽にできる)したくなる(これは心情として避けられないという仮定)。こうなると、ExceptionクラスはRuntimeExceptionクラスの親でもあるので、バグ(RuntimeException例外)もキャッチしてしまう。
  • 検査例外を使うと、例外対処のコードを局所化ができない : 検査例外を使用すると、例外をスローしたメソッドから、例外を処理できるメソッドに至る途中のメソッド全てにおいて、例外に対して何もできないにもかかわらず、例外をキャッチして(何もせず)リスローする無駄なコードを書かなければなければならない。
検査例外は必要だという人たちの根拠
  • 検査例外は、例外仕様の文書化を強制する : コンパイル時に例外の仕様を検出することができるため、文書化されていない例外を見逃すことがない。クラスの使用法として、どのメソッドでどういう例外がスローされるのか判らなければ、どうエラー処理して良いのか判らない、あるいは必要ないエラー処理を書くことになる。
両者の意見を参考にして

検査例外を不要だという人たちの根拠は、設計によって軽減されるか無くすことができるように感じます。設計によって検査例外を管理すれば、挙げられている問題はかなり軽減すると考えられます。

優秀な開発者ばかりが集まった開発では設計によって検査例外を管理できそうですが、大規模な開発になればなるほど、優秀とは言えない人が増えていくわけですから、検査例外の管理ができなくなる虞があります。おそらく、検査例外は不要と主張されている方々は『いくら設計で管理していても、コーディング時には、それを無視して誤った使い方をする者が出てくる*6』と考えていらっしゃるのではないでしょうか*7

これらの説を集めている際、同様の指摘をされているウェブページがありました。参考までに挙げておきます。

developerWorks Japan Javaの理論と実践: 例外をめぐる議論

私の意見としては適切に例外を使うのは確かに難しく、また間違った使い方をされる例は多いものの、彼に同意する人たちは間違った理由から同意していると思います。ちょうど政治家が、誰でもチョコレートがもらえるような補助を主張すると10歳の子供から絶大な支持を受けるのと似た話のように思います。

開発者としては「面倒なこと(検査例外を使用する開発)は避けたい」と思ってしまうのですが、それは怠慢のような気がしています。管理者として「しっかり設計・コーディングして検査例外を管理しよう」と言いたくなりましたし、それを目指したいものです。

最後に

先述した本の3章では例外が触れられていますが、著者が、

Javaの例外ほど、みんなから悪口を言われて誤解されている機能はないだろう

と言われています。その通り、今でもJavaの検査例外に関する議論は止むことがないようです。

今回私は、Javaを使った開発において例外をどのように取り扱うべきか再考してみたのですが、その中で感じたことがあります。それは、検査例外だけでなく、エラー処理をどうするかというのは、開発において重要なポイントだということです。これは、止むことが無くて当然です。どのような設計方針とすべきか、いつも答えが違うし、いつも議論しているような気がします。

ただ今回、それで良いんだと感じました。

*1:メリットを活かせるなら使った方が良い。存在が悪ではない、という考えは間違っていないと思います。

*2:バグに起因する障害を含む

*3:長くなるため。

*4:Exceptionクラスを使わせない

*5:呼び出し元には例外のスローによって知らされた事象

*6:つまりコーディング以降管理不能に陥る

*7:個人的にはよく判ります