なになれ

IT系のことを記録していきます

A Philosophy of Software Designの7章要約

本内容は「A Philosophy of Software Design」の7章を要約する記事です。

過去記事

6章の紹介

他担当の方が要約した6章の内容を引用します。

  • 6章 汎用モジュールはより深く
  • 筆者の経験では特化することは複雑性を増加させる
  • 新しいクラスを設計においては汎用クラスの方が特殊クラスの代替品よりも優れていることがわかった
    • あまりに汎用的なものを実装すると、現在抱えている特定の問題を解決するのにいい仕事ができないかもという懸念も存在する
    • 今日のニーズに焦点を当て、必要なものだけを構築し、今日の使用目的に合わせて特化させる方が良いという意見もあります
    • 筆者の講義で得れた経験では、汎用インターフェースの方が特殊なものよりもシンプルで奥が深く、結果的に実装のコード量が少なくて済む
    • クラスを特殊な方法で使う場合でも、汎用的な方法で構築した方が手間がかからないということがわかった
  • 筆者の経験では、新しいモジュールをある程度汎用的に実装することがスイートスポットとなる
    • この「ある程度汎用的」というのは、モジュールの機能は現在のニーズを反映すべきであるが、インターフェースはそうであってはならないという意味
  • 筆者の授業の生徒の実装の中でわかったことは、クラス設計の目標のひとつは、それぞれのクラスが独立して開発できるようにすることですが、特化したアプローチにより、ユーザーインターフェースとテキストクラスが結びつく結果となった
  • 設計にあたって汎用的なAPIの設計ができているかの問い
    • 私の現在のニーズをすべてカバーする最もシンプルなインターフェースは何か?
      • もし、APIの全体的な機能を減らすことなくメソッドの数を減らすのであれば、おそらくより汎用的なメソッドを作っているのでしょう
      • メソッドの数を減らすために多くの追加引数を導入しなければならないのであれば、それは物事を本当に単純化しているとは言えないかもしれません
    • このメソッドはどのような場面で使われるのでしょうか?
      • メソッドがある特定の用途のために設計されている場合、たとえばバックスペース・メソッドなどは、特殊すぎるという赤信号です
      • いくつかの特殊なメソッドを一つの汎用的なメソッドに置き換えることができるかどうか確認してください
    • このAPIは、私の現在のニーズに対して使いやすいか?
      • この質問は、APIをシンプルで汎用的なものにするのが行き過ぎた場合に、それを判断するのに役立つ
      • もし、現在の目的でクラスを使うために多くの追加コードを書かなければならないなら、それはそのインターフェースが適切な機能を提供していないという赤信号です
  • 筆者は多くのソフトウェアシステムが、必然的に特殊化されたコードを持たざるを得ないことも認めている(特殊化を完全に排除することは通常不可能)
    • 例えば、高度に専門化された特定の機能を提供するアプリケーションの存在
  • ただ、その場合も特殊化したコードは、汎用コードからきれいに分離する必要がある
    • 特殊化されたコードをソフトウェアスタックの上または下に押し出すことで実現する
      • アプリケーションのトップレベルクラスにて特化した機能を、その機能を実装するために使用される低レベルのクラスに浸透させる必要はない
  • 特殊化のもう一つの形態は、メソッド本体のコードでの特殊なケースという形で発生する
    • if文だらけのコードになり、コードを理解しづらく、バグが発生しやすい
    • このため特殊なケースは可能な限り排除する必要がある
  • 対応として、エッジケースを余分なコードなしに自動的に処理する方法で、ノーマルケースを設計するのが一番良い(詳細は10章で解説する)

7章要約

  • 7章 異なるレイヤー、異なる抽象化
  • 概要
    • ソフトウェアのレイヤーについて、各レイヤーは異なる抽象化を提供するべき
      • レイヤーは上位に向かうほどに複雑さを軽減するものになっている必要がある
    • 似たような抽象化が異なるレイヤーで存在する場合の問題や解決策を示す
  • パススルー・メソッド
    • 呼び出すメソッドとインタフェースが類似しているか同一である別のメソッドを呼び出す以外は、ほとんど何もしないメソッド
    • クラス間の責任の重複を生み出す。複雑さが増すだけ
    • 解決策
      • 直接公開する
      • 機能を再配分する
      • クラスを結合する
  • インタフェースの重複が許されるケース
    • 同じインタフェースを複数のメソッド間で持つディスパッチャは例外的に有効なケース
    • 複数のメソッドの実行を新しいインタフェースを学ぶことなく選択してくれるため、複雑性を軽減する
  • デコレーター(ラッパークラス)
    • 浅いクラスになりがち、多くのパススルー・メソッドを持つ
    • 解決策
      • 基底クラスに直接新しい機能を追加する
      • 複数の浅いラッパークラスを作るのではなく、1つの深いクラスを作る
  • パススルー変数
    • 長いメソッドチェーンを通じて渡される変数のこと
    • 解決策
      • ベストな解決策ではないが、コンテキストオブジェクトがベターな方法
      • 共有オブジェクト
      • グローバル変数
      • コンテキストオブジェクト
        • グローバル変数に近い
        • コンテキスト内の変数を不変にすることで問題を回避する

感想

  • ラッパークラスをよく作りがちなので反省する
  • パススルー変数問題はフロントエンド界隈でソリューションが生まれていっているかもしれない