Java言語のチェック例外は本当にGood Partなのか?

デブサミ2011会場のオライリーのブースで目に入ったため、以下の本を購入しました。

Java: The Good Parts

Java: The Good Parts

180ページほどの薄い本ですし、各章は独立して気軽に読むことができます。早速、気になるいくつかの章から読んでみました。ただし、監訳者のid:t_yano氏も前書きで

本書が、みなさんにとってJava以外の言語についても考えるようになり、みなさんのプログラミングの世界がさらに豊かになることを望みます。

と書かれているように、この本から直接Javaのプログラミングのテクニックや知識を得るというよりも、ベテランの上級者がJavaについて考え直すきっかけ作りとして読むのが良いのではないかと感じました。*1むしろ、Javaプログラミングの初中級者が、Java言語の正しいプログラミングテクニックを学ぶのであれば、

Effective Java 第2版 (The Java Series)

Effective Java 第2版 (The Java Series)

の方が良いと思います。
Javaといっても、言語だけでなくプラットフォームやライブラリーなどを含めると膨大な範囲があり、その中で、どこがGood Partsなのかという点は(この本の著者も最初に書いているように)プログラマーの主観や経験によって異なるのが当然であり、絶対的に正しい答えというのが書かれていることを期待して読んでも失望するだけですね。個人的には、SI業界でJava EEを使った開発をやってきていることもあり、

などをJavaJava言語ではない!)のGood Partsに加えてほしかったなという思いもあります。(JVM言語まで対象にするとさすがにスコープが広すぎるかもしれませんが。)
それで、実際にこの本の3章を読んで、「Java言語のチェック例外は本当にGood Partなのか?」ということを再び考えるきっかけとなりました。(考えるきっかけという意味でこの本は実際に良書ということで。)そして、実際に検索したら、既にいくつかの議論がなされているページを見つけました。
Javaの理論と実践: 例外をめぐる議論
「検査例外はアジャイルやオブジェクト指向の考えに反するという事実」について一部誤解あり - じゅんいち☆かとうの技術日誌
非検査例外に萌えるわけ - じゅんいち☆かとうの技術日誌
Throwableについて本気出して考えてみた 2nd Season - 都元ダイスケ IT-PRESS
例外について色々と考えてみた - ぐるぐる~
RE: 検査例外イケテナイところ - SiroKuro Page
探せば、他にもいろいろ見つかるかもしれません。私の知っている範囲の主要な言語でチェック例外というアイデアがあるのはJavaだけなので、この機能がJavaのGood Partなのかどうかは、Javaプログラマーとしては実際非常に興味深いところです。
Java: The Good Partsの著者はもともとSunで黎明期からJavaにかかわっているということもあるのだと思いますが、チェック例外については、かなり教条的な立場*2をとっています。実際、3章では

悪に対抗しよう。新しいRuntimeExceptionを宣言してはならない。

とまで言っています。直後に

私はちょっとしたException絶対主義者だった時期があり、(中略)私は今でもRuntimeExeptionクラスを使うのは間違いだと信じているが、人には現場での現実に従うべきときもあるのだ。

とフォローしていますが、実用主義者の感覚とはかなりずれている気がします。*3
それで、一般的にはチェック例外が善か悪かという議論になるのですが、私自身は今のところ以下のように考えています。まず、Javaが対象としているようなプログラムは業務システムを含めて大規模なプログラムになることが普通です。この場合、どうしても必然的にアーキテクチャ的にレイヤー構造をとる設計となります。そうすると、下位レイヤーにとっての外部仕様であったものが、上位レイヤーにとっては実装の詳細であり意識する必要がないというケースが出てきます。典型的な例はjava.ioやjava.sqlAPIを提供するクラスです。実際、IOExceptionやSQLExceptionといった例外はこうしたAPIの提供者にとっては、インターフェースを記述する手段としてチェック例外を使用することが適切なように思われます。しかし、ドメイン層やアプリケーション層のプログラマーにとって、こうしたレイヤーの例外が発生しても一般的には正しく対処することが困難であり、仮に対処しようとしても(AOPを使わない限り)、DRYに反していたるところに同じような例外処理を書かなくてはならなくなってしまい、まったく実用的とはいえません。そもそも、上位層のクラスがインフラ層の例外を意識しなくてはならないのは関心事の分離という考え方からも不適切です。
このような事実を考えると、一般的にフレームワークやライブラリーなど、どのようなアプリケーションで再利用されるかのコンテキストが明確でないクラスでは、チェック例外を使用することは適切でないのではないかと考えます。実際、Spring FrameworkではSQLExceptionなどシステム系の例外はすべて実行時例外に変換することで、アプリケーション層のプログラマーが意識しなくてもよいように工夫されています。
それでは、チェック例外はまったく不要なものなのであり、使うべきでないということなのでしょうか?実際、一部にはそのような意見もあるようですが、ドメイン層やサービス層など上位レベルのクラスにおいて、不変条件や事後条件が満たせなくなるようなケースを記述するための仕組みとして、チェック例外の使いどころはあると信じています。よくある例ですが、Account(口座)クラスで残高がマイナスになったら、InsuffisientBalanceExceptionなどを投げるといった場合に使えるはずです。
しかしながら、実際のSIの開発で以上のようにオブジェクト指向で、かつ、ドメインドリブンな設計でやっているところは非常に限られるという現実があります。クラス名ですら適切な名前をつけることがないのに、例外といったものにまで適切な名前をつけて表現する*4といったある意味高尚な設計がされる機会は本当に少ないのではないでしょうか?そして、多くの場合Actionのexecute()メソッドにロジックを記述するといったTransaction Script的な設計をする世界であれば、チェック例外というのは多くの場合、無用の長物でしかなく、半端に使用しても無駄なtry-catchでコードが複雑になるだけだと思います。
まとめると、

というのが私の考え方です。したがって、DDD的な理想のオブジェクト指向設計をする手段として、Javaのチェック例外というのは本当は優れた機構だと思うのですが、なかなか現実世界では使いどころがないということになるかと思います。

*1:enum変数名やパッケージ名にキャメルケースを使っていたり、Javaプログラマーの一般常識とは反するところもある。

*2:この本で、他に教条的と思われるところはBatter、Catcherといったドメインの用語をインターフェース名に使い、実装クラスにImplという接尾辞を与えているところです。インターフェース中心主義だとその通りなのですが、通常はクラスに単純な名前を使い、インターフェースにIという接頭辞をつけたりableやerなどの接尾辞をつけるなど補助的な名前を与えることが実用的で普通です。実装パターンでも単純なクラス名を推奨していたと思います。

*3:原著者のチェック例外びいきやインターフェース中心主義は、9章で書かれているようにRMIへのかかわりを考えると良く分かる気がします。ただし、普通、RemoteExceptionがチェック例外なのは厄介なだけで、あの設計方針は今から考えると失敗だったと思うのですが。それから、ファサードインターフェースとDTOを利用せずに、ドメインインターフェースを直接リモート呼び出しにする発想も実用的でなく、現在では否定されています。この設計が今でも良いと信じているのであれば、率直な感想として、アメリカにおける老害さんですかとちょっとつっこみたくなる気持ちもしますw。

*4:一般的に例外クラスは長い英語名となる。