A Philosophy of Software Design ch5. Information Hiding (and Leakage)

APoSDソフトウェア設計勉強メモ

出典: 


Information Hiding (and Leakage)

  • ch4.で述べたこと: モジュールは深くあるべき
  • 本章: どう作るの

Information hiding

  • 知識の隠蔽

    • 深いモジュールを作る上で最重要テクニック
    • in 1972 David Parnas
  • 実装のhowが隠蔽される

    • データ構造やアルゴリズム

      • B木にデータを格納する方法、効率的なアクセス方法
      • ファイルの論理ブロックとディスクの物理ブロックとの対応づけ
      • TCPの実装
      • マルチコアプロセッサのスケジューリング
      • JSONドキュメントのパース
    • 情報の水準はさまざま

      • 低水準

        • 例: ページサイズ
      • 高水準

        • 例: 「ほとんどのファイルのサイズが小さい」という仮定
  • 2つの点で複雑性を減らす

    • インタフェースが単純になる

      • 重要でない詳細が削ぎ落とされ、開発者の「認知の負荷」が下がる

        • 例: B木

          • 木の平衡の保ち方などを知る必要がない
    • システムの拡張が容易になる

      • 隠蔽された知識は他のモジュールとの依存関係をもたない
      • ので、独立して変更を加えることができる

        • 例: TCP

          • 例えば輻輳制御の知識はTCPに閉じている
          • L4のTCPの輻輳制御の実装が変更されても、L5以上のプロトコルは影響を受けない
  • モジュールを設計する際は、なんの知識を閉じ込めるかよく考えよ

    • 隠蔽すればするほど、インタフェースは単純になる
    • つまり、モジュールは「深く」なる
    • 【補】利用者にとって重要な知識は隠蔽してはいけない(ch.6)
  • 知識の隠蔽はゼロ百ではない、部分的でも価値がある

    • クラスの知識が全クライアントコードに暴露されているよりは、一部のクラスにのみ公開されているほうがマシ

      • 知識を必要とするクラス向けのメソッドを用意する

        • 【補】Repository向けのsetterとかはこれ?

Information leakage

  • 隠蔽できてないやつ
  • 設計(how)の変更があちこちに跳ねる

    • ある知識が複数のモジュールに反映されている

      • 重複
      • ひとかたまりであるべきものが分散している(Back-door leakage)

        • 例: データフォーマットのread/writeが別々のモジュールに分かれている
        • ひと目でわからないので厄介
    • 知識がインタフェースに漏れている
  • 知識の漏出はソフトウェア設計上、最重要危険信号

    • 知識の漏出に敏感であることは最重要スキル
  • 知識の漏出に出くわしたら自問自答せよ:

    • 「これらのクラスを再構成して、この知識が1つのクラスにしか影響を与えないようにするには?」
    • クラス群が小さく、漏出した知識と密に紐付いているなら、1つのクラスにまとめることを検討する
    • あるいは、知識を別クラスに切り出して委譲する

      • 切り出した新しいクラスのインタフェースに知識が漏出していたら意味がないことに注意する

        • Back-door leakageがインタフェース越しの(普通の)漏出になったたけ

Temporal decomposition

  • ソフトウェア構造がタスク発生順に対応している
  • 時間分割してしまっている例

    • クラス群

      1. HogeReader
      2. HogeModifier
      3. HogeWriter
    • Hogeフォーマットについての知識がReaderとWriterに散らかっている

      • Back-door leakage
    • まとめよう
  • タスクの発生順ではなく、各タスクが必要とする知識に着目する

    • 【補】この場合、Hogeフォーマットの読み書き

Example: HTTP server

  • HTTPとはなんぞや(略)
  • Request/Responseの話

Example: Too many classes

  • やりがちなミス: 時間分割

    1. HTTPリクエストを読み、文字列を返すクラス

      • 【補】Receiverとする
    2. 文字列をパースするクラス

      • 【補】Parserとする
  • パースの知識のBack-door leakage

    • ReceiverとParser両クラスで文字列パースの知識が必要になる

      • HTTPリクエストというものは、ある程度パースしないと読めないもの
      • 例えば、Content-Lengthヘッダを読まないと、リクエストボディの長さがわからない
    • 呼び出しコードに複雑性を強いる

      • Receiver, Parserのメソッドを特定の順番で呼ばせる

        • 【補】認知の負荷
  • 知識の隠蔽は、クラスを少し大きくすることで改善することが多い

    • 関連機能がまとまる
    • インタフェース単純化

      • 【補】クラス減る、メソッド減る
      • 深いモジュールにつながる
  • かといってアプリケーション全体を1クラスにしていいわけもない
  • いつクラスを分割すべきかについてはch9にて論ずる

Example: HTTP parameter handling

  • クエリパラメータをパースする部分は誰もがカプセル化するところ

    • &=区切りで連想配列にパース
    • +を半角スペースに
  • やりがち: こんな浅いメソッドを生やして、内部表現を暴露してしまう
public Map<String, String> getParams() {
    return this.params;
}
  • こうあるべき
public String getParameter(String name) {...}
public int getIntParameter(String name) {...}
  • 「内部表現がMap<String, String>である」という知識を隠蔽した
  • getIntParameterはさらに下記メカニズムを隠蔽

    • 文字列から整数への変換
    • 変換失敗時の例外送出

Example: defaults in HTTP responses

  • やりがちな間違い: デフォルト値を設定すべきものに設定しない

      • HTTPレスポンスのHTTPバージョン

        • リクエストのものと一致するべき
      • DATEヘッダ
    • モジュール利用者が設定するのは、知識の漏出にあたる
  • 「デフォルト値」は、知識の部分的な隠蔽の例

    • 普遍的なケースが可能な限り単純になるように設計する、という原則にしたがっている
    • 利用者は、普遍的なケースにおいて、デフォルトが設定された項目の存在について知らない
    • レアケースでは

      • デフォルト値をオーバライドする
      • デフォルトのふるまいを変えるための特別なメソッドを起動する

        • 【補】UnixのファイルIOのlseek()的なやつ
  • クラスはよしなに「正しいことをする」べき

    • デフォルト値はこの一種
    • JavaのファイルI/Oの姿勢はこれに反する

      • ファイルI/Oにおけるバッファリングは誰もが欲する機能
      • わざわざ指定しなくても有効になってほしい
      • 利用者は存在すら知らないのが望ましい

Red Flag: Overexposure

  • 普遍的な機能を利用するために、めったに利用されない機能についても学ばなければならない
  • 認知の負荷の増大

Information hiding within a class

  • 知識の隠蔽は、なにもシステムに対するクラスだけの話ではない

    • クラスの中に知識をカプセル化し、システムの残りの部分から隠蔽する
  • クラスに対するメソッド

    • privateメソッドの中に知識をカプセル化し、クラスの残りの部分から隠蔽する
  • インスタンス変数の利用箇所を減らせ

    • 依存を排除し、複雑性を減らす

Taking it too far

  • 隠蔽していいのは、「モジュール外で必要とされない知識」
  • モジュール外で必要とされる知識は隠蔽してはいけない
  • 例: モジュールのパフォーマンスチューニング用コンフィグ

    • ユースケースごとに異なる設定が必要
  • モジュール外で必要な情報は最小化せよ

    • 設定値を自動調整できるなら、そのほうが設定項目を公開するよりも良い
    • どの知識がモジュール外で必要か認識し、それを確実に公開することが重要

Conclusion

  • 知識の隠蔽と深いモジュールとは深く関連している
  • 知識を隠蔽するほど…

    • モジュールが提供する機能は増える
    • インタフェースは小さくなる
    • つまり、モジュールは深くなる
  • 逆もまた然り

英語

  • pernicious

    • 有害な、悪質な