エラーハンドリングについて考える。


書きながら考えたものなので、メモみたいな感じ。

エラーハンドリングの知識を体系的に纏めた本とかないだろうか。
本屋に行ってみても、

  • プログラミング言語の棚を漁ると、エラーの中で致命的なものを例外として扱って、その言語における例外処理の文法について基本的だったりidiomだったりを紹介してくれる
  • 設計関連の棚を漁ると、上流行程っぽい感じ?ここらへんはよくわかってない。設計、分析技法の紹介と、テストを書くことをお勧めしててバグに強いソフトウェアを!という感じ

こんな本が見つかって、エラーハンドリング、エラーハンドリング設計について体系的に纏めてる本を見つけられなかったのだけど、そういうのは有るんだろうか。

エラーハンドリング設計として、

  • ソフトウェア(アプリケーション、ライブラリ。あるいは両方を合わせて)の設計
  • 例外処理、例外安全性
  • Logging

をこれらをカバーした視点でどのようにするべきかが解説してあればとても読んでみたいんだけど。ただ、言語とさらにソフトウェアの性質に非常に左右される部分ではあると思う。C++GUIアプリケーションで知りたい。


例外について、C++だと標準ライブラリで送出された例外から、スタックトレースなどが取れないので、ある程度まとまった単位で例外処理を組み込んでも、送出された例外を、デバッグに役立てることが出来なくはないだろうか。

「例外は例外なのだから、それをデバッグに役立てるとか、それつまりバグじゃん」って言われたらそうだけど、すべてのバグをつぶすことなんて出来なくて、残ってたバグが例外として実行時に現れることも有るんじゃないだろうか。

そしてそれを突き詰めると、例外を投げうる標準関数、標準クラスのメンバ関数を呼ぶ関数すべてでtry catchして例外が起きた状況を付加(例えばスタックトレースやなど)できるような例外に変換・・・それは言い過ぎにしても、結構細かい粒度で例外を待ち構えてなくちゃいけないんじゃないだろうか・・・

と思ったけど、標準関数から投げられる例外ってのは、vector::atとかfstreamとかじゃ無い限り、かなり限定的で致命的なものなのかも。それにatは例外投げないように事前に対応できるし、fstreamも例外フラグたてないことが出来るし、例えば「eofになったよ!」とかを例外で扱った方が楽になりうる場合に例外で扱えば良いだけとして。ふむ。

そうすると、基本的に例外を待ち構えるべき状況は限定されて、自分が送出するときも、自分のアプリケーションで使いやすい形式の例外を投げるようにする。例外の投げと受けはこれで問題ないだろうか。

例外安全性についてはC++ならExceptional C++がかなり勉強になりました。

なので第2項の「例外処理、例外安全性の設計」はC++でやるならこんな感じで。


そして、例外からさらに広げてエラーハンドリング全般についてなのだけど、簡単なCUIアプリケーションなら、どんなに深くの関数まで潜っても、何らかのメッセージになる文字列を標準(エラー)出力まで魔法のように出せてしまうけど(そんな設計はよくないのかも)、大きなGUIアプリケーションとかになると、そういう、例外じゃないんだけど、ユーザーに知らせておきたいメッセージや情報ってのはどういう風に扱ったら良いのかしら。

例えば、何らかの保存ファイルを開いたとして、
「読み取り中になにかよくないものが有ったけど、そんなことは弊社屈指の天才プログラマである私が予期できるエラーちゃんだったのでデフォルト値でよしなにやっておきましょう☆キャピ」なんてことをしてしまおうとした自称天才プログラマーがいたとして、まあ、たしかによくないなにかが有った訳で、それを即異常として読み込めないよりは、なんらかよしなにして読めた方が良いのかもしれないけど、ものによってはユーザーがそれを知れるべきじゃないかという要望を考えてみたり。

いまの例をさらに具体的に、例えば画像編集ソフトで、なんかの保存したファイルを開こうとした時、とあるレイヤーの前後関係のインデックスが重複してたとか(だれだ勝手に書き換えたやつは!)。どのように処理するにしても(重複したレイヤーの最初以外を飛ばす。順次、次にinsertする。など。)、ユーザーには、何かをどうにかしましたよと伝えてあげるのが親切な気がする(MessageBoxという魔法の関数をここで使うと、多くの場合において効果的にユーザーのストレスを増加させることができる。)

ただ、あるアプリケーションのファイル読み込みなんてそれだけで、アプリケーション本体からちょっと離れて、ライブラリ化してしまうことも考えられる訳で(たとえそのアプリケーションでしか使われないとしても)、そのときに「ライブラリが何かよしなにしたよ」というのを、アプリケーションが有効に便利に扱うにはどうしたら良いのか。

あるいはユーザーには知らせない場合も、そうであるなら最低限Loggingは出来た方が良いと思うけど、ライブラリ側にログを取る処理を入れてしまうのはライブラリの汎用性を著しく下げてしまうと思うので、やっぱりアプリケーション側でそういったライブラリ側のメッセージとか情報をもらってごにょごにょできるのが良いと思う。


つまり、

ライブラリ側の、"例外以外のエラーハンドリング"をアプリケーション側でどう扱うか

という問題か・・・?

ライブラリ側はどういう風に例外ほど重大でない(そして処理がそのまま継続されるような)エラーをアプリケーション側に通知できるだろうか。

さらに言えば、ライブラリ側で、とあるエラーが有ったときに、ユーザーに、この処理を継続するしない、どういう対策をするしないと、選んでもらうこともあるかと考えたけど、ユーザーとライブラリが近いことは良くなさそうに思えたし(どうしてかちゃんと説明できない)*1、これはアプリケーション側がうまく間に入ってなんとかするような問題かも。


さっきのようにCUIアプリケーションなら、常に標準出入力がユーザーの矢面に立っていろいろやってくれそうに思えたけど、いくらCUIで標準出入力を自由に使えてもライブラリがユーザーと近いのはよくないか・・・

むう。


エラー処理設計:対処方法をシステム全体で定める
ここは参考になると思う。具体的な方策は見えないのだけど、エラーをきちんと体系化したら光が見えるだろうか。


例外をインターセプトすべきか
これはどう考えたら良いんだろう。
コメントで2番目でログっていうのがついてるけど、個人的には3番目でログとってreturn false;なんじゃないかと思う。ただ、これがなんかのライブラリだと、ログっていうのにちょっと抵抗が・・・


よくわからない・・・><;

*1:<追記>ライブラリはあくまでライブラリなので、ユーザーと近いとアプリケーションの自由度を大幅に下げてしまうことになりそう。