例外原理主義

れいがい!」、「REIGAI REIGAIせよ!」、「そろそろれいがいさんへの思いを適当にまとめる」も参照のこと。

  • assert/エラー/例外の区別。
    • 意味論上、本質的な違いはない。現状の実装などの都合で使い分けるもの。
    • 問題の通知に使用される場合の signal やモナド*1等も意味論上、本質的な違いはない。
    • 本来これらは同じような構文で記述できるべき。
  • assert/エラー/例外の使い分け。
    • なにか問題が起きた場合は基本的に例外を投げる。
      • リリース版ではそもそも発生することがあってはならない類の問題については assert を使用する。
        • パフォーマンスが問題にならない場合は assert とともに例外やエラーを併用することを推奨。
      • 問題が起きても無視してよいものあるいは例外ではパフォーマンスや呼び出し側の実装の都合が悪い場合にはエラーする。
  • assert/エラー/例外の役割。
    • 問題が起きたことの通知。
      • 通知先は呼び出し元。
      • 末端の呼び出し元はユーザー/管理者/プログラマを問わず、人。
        • 形式:UI上のメッセージあるいはログ
        • 内容:呼び出し履歴(引数を含む)+末端でどんな問題が起きたのか。
      • 代替手段がある場合にそちらを利用。
      • 安全な終了。
        • ここでいう安全とはデータを破損・損失しないという意味での安全。
  • どんな情報を例外として送出するべきか?
    • 「なにをやった時」に「なにが起きた」のか。
      • 多くの状況下で、呼び出し側は「なにをやった時」かは分かるが、例外を送出する関数が呼び出された際の仮引数に含まれる情報は呼び出された側が含めるべき。そうしなければより親のレイヤーに情報を返す為にその関数を呼び出す全ての箇所で実引数に含まれる情報を埋め込むコードをばらまかなければならなくなる。
      • エンドユーザーに見せる場合はこれに「なにをすれば問題を解決できるのか」を付与すること。
        • 適切に情報を提示できればプログラマでないエンドユーザーでも問題の把握と対処が可能になる。
          • そしてその情報はなによりもまずその製品を開発中の開発者自身を助ける。
    • 中途半端にコミットしてしまっている動作があるのならばその情報。
      • 前提としては例外に限らず問題が起きた場合は可能な限りロールバックを行う。
  • 自動伝播について
    • 自動伝播については一長一短があるが、自動伝播しなければ「問題が発生したことにすら気づかない」という事態を招いてしまう点を重要視し、自動伝播であることを善しとする。
      • 見えるべき情報が見えなくなるというのはそれだけで避けるべき理由に足る。
      • まずファイルの保存やサーバーへのデータのポストなどと言ったコミット(書き込み)系操作に失敗していることは絶対に検知されなければならない。この問題は検知できれば単にリトライするなり別の場所に待避させるなりして致命的な状況を回避できるが、検知できなければそれも叶わない。
      • 次にデータの読み込み操作に失敗していた場合、これについても絶対に検知されなければならない。この問題は検知できれば単にリトライするなり読み込み可能な状態にするなりすれば済む話だが、データの一部を読み込みに失敗していることに気づかずにデータを上書きをしてしまい致命的な状況を招いてしまう。
      • データの演算操作についても読み書きと同様の理由で問題を検知する必要があり、要は結局のところ全ての問題はまず検知されなければならない。
    • 自動伝播はいまの形ではなく、関数(やスコープ)を抜ける度に自動でネストされるべき。
      • ネストされる際、引数あるいはそれに相当する情報を含めるべき。
        • これらの情報がないと対応が困難になる。    
    • 上位で中断するかどうかを判断することについては機能の切り分けの問題でもあると思う。また、実際に上位に中断するかどうかを問い合わせる実装については trickerr.h で実現しているので参照されたし。(といっても利用例が欠けているのあまり参考にはならないかも。)
    • 例外の型については関数と1対の関係になるべきものなのかも。
      • その上で例外情報を木構造でネストする。
      • 関数自体もクラス扱いすれば、そのまま例外情報として送出可能になるし、処理内容によってベースとなるクラスを継承していれば catch の利便性もよい。
    • 捕捉された例外はネストはしても原則として加工するべきではない。
  • Icon 言語のゴール指向について*2
    • 例外原理主義の立場からすると恐らく Icon 言語のゴール指向のままではナンセンス極まりないと言える。
      • が、皮肉なことに例外原理主義な思想に染まってる現在思案中の俺俺言語での挙動に非常に近いモノでもある。
  • エラー忘却型コンピューティング/フェイルソフトについて
    • 本質的にこれらの目的はダウンタイムの最小化であり、この意味でも例外を使いすべての問題を検出することは重要。
      • 問題を検出したからと言って全ての処理を止める必要はない。
      • 問題の検知というか早期発見を怠るとより大きなダウンタイムを招くことになりかねない。
  • フェイルセーフについて
    • 例外そのものがフェイルセーフな性質を持っている。
      • ただし、(当然ではあるが)ただ例外を使えばフェイルセーフになるというものではないので注意。
  • 今現在例外に統一されてないことについて
    • 今現在例外に統一されてないだけで例外(の発展系)で統一されるべき。
    • 昔は言語使用的にそもそも例外が存在しておらずその間にエラーやassertが蔓延ってしまっただけで例外(の発展系)で統一されるべき。
    • インターフェイス上、モジュール間での例外処理は難があるが例外システムの共通化を図り、例外(の発展系)で統一されるべき。
    • 例外(の発展系)で統一されるべき。
      • ・・・ぶっちゃけいまの例外システムのままではダメだと思う。ひょっとしたら例外システムがダメなんじゃなくてそのまわりの処理体系のほうに手を入れるべきなのかも知れないけど。少なくとも正常系の戻り値と同列で例外を処理できるようにし、且つ木構造例外に対応する必要がある。

*1:モナドについてはよく理解していないので推量ですが。

*2:Wikipediaの情報を見ただけなので私の理解が足りないことも否めないのであしからず。