Less is more.

学んだことなどについて書きます。

「A Philosophy of Software Design」を読んだ

A Philosophy of Software Designを読んだので感想を書きます。

 

日本のAmazonでは売ってなくて電子書籍もなかったのでAmazon.comから購入する必要があって大変面倒でした… Kindleだと辞書を引くのも簡単なので英語の本は電子書籍で読みたいですね。

どんな本か?

ソフトウェアの複雑さを減らすためにどのような設計を行えば良いかについて書かれた本です。

特にモジュール設計でインターフェースが最小限で機能の多いDeep Module(深いモジュール?)になるようにモジュールを設計するという内容が参考になりました。 

クラスを小さくするプラクティスが行きすぎると小さなクラスが増えすぎて全体としての複雑性が上がることがあるという記述もあり、クラスを闇雲に分割して小さくするのではなくDeep Moduleになるのかどうかを考えた上で分割するようにする必要があるというのは今後意識していきたいと思います。

全般的に今後設計する際にこの本の各省の内容に立ち返ってどう設計すべきか考えていきたいと思える内容で読んでよかったです。

読書メモ

Chapter2: The Nature of Complexity

  • 複雑さとはシステムの理解や修正を難しくするソフトウェアシステムの構造
  • 複雑さの症状
    • 修正の連鎖
      • 一つの修正が複数箇所に連鎖する
    • 認知負荷
      • コード量の多いアプローチの方が認知不可が低くなるためシンプルになることがある
    • 未知の未知
      • 3つの症状の中で最悪
      • バグが出るまで修正が必要であることに気づくすべがない
  • 複雑さの原因
    • 依存
      • ソフトウェア設計のゴールは依存の数を減らしできるだけシンプルで明瞭にすること
    • 不明瞭さ
      • 変数名やドキュメント
      • あまりに多くのドキュメントが必要になるのはシステムの設計が正しくない兆候
  • 複雑さは蓄積される
    • 複雑さが蓄積されると一つの依存や不明瞭さを解消するのとは異なり修正が困難になる

Chapter3: Working Code Is'nt Enough

  • 良い設計のためには戦術的ではなく戦略的にプログラミングする必要がある
  • 戦術的プログラミング
    • できるだけ早く機能改修やバグ修正を行うことを目指す
    • 複雑さが蓄積され彼機能改修に時間がかかるようになる
  • 戦略的プログラミング
    • 動くだけのプログラムを目標とせずシステムの設計を改善するために時間を投資する
    • 10-20%の時間を投資する
      • 最初は遅くなるが時間が経つにつれてその時間は取り返せる

Chapter4: Modules Should Be Deep

  • モジュール設計
    • 開発者が全体の複雑さの必要な一部分のみに対すれば良いように複雑さを管理する
    • モジュール間の依存を最小限にすることが目標
  • モジュールをインターフェイス/実装の二つに分けて考える
    • 深いモジュール
      • インターフェースが最小限で機能が多い
      • 良いモジュール
    • 浅いモジュール
      • 提供する機能に対してインタフェースが複雑
  • 「クラスは小さくすべき」という考えが行き過ぎると個々のクラスはシンプルだが全体のインタフェースとして複雑になる

Chapter5: Information Hiding (and Leakage)

  • 情報隠蔽
    • 深いモジュールを達成するための一番重要なテクニック
    • 必要最小限の機能を外部に公開する
  • 情報漏れ
    • 設計修正の影響が複数のモジュールにおよぶ
    • 設計の危険信号
    • 時間分割
      • システムの構造が実行順序に対応する
      • モジュール設計ではタスクの実行順ではなく各タスクを実行するのに必要な知識に集中する

Chapter6: General-Purpose Modules are Deeper

  • 汎用/専用のどちらで実装するか
  • 少し汎用にするのが良い
    • 実装は現在の要求を満たす専用の実装でインターフェースは汎用にする
  • 汎用のアプローチは良い情報隠蔽につながる
  • 汎用/専用の正しいバランスを見つけるための問い
    • 現在の要求を満たす最もシンプルなインタフェースは?
    • このメソッドはどのくらいの数の状況で使われる?
    • 現在の要求のためにこのAPIを使うのは簡単か?

Chapter7: DIfferent Layer, Different Abstraction

  • よく設計されたシステムではソフトウェアの各レイヤーは異なる抽象化を提供する
  • パススルーメソッド
    • ほぼ同じシグネチャーのメソッドを呼び出すメソッド
    • クラス間の責務が綺麗に分離されていない
  • 同じシグネチャーが常に悪いわけではない
    • 有用で明確な機能を提供するかどうかが重要
  • デコレーターパターン
    • レイヤー間でAPIが重複する
    • 濫用するとJava I/Oクラスのように浅いクラスが多くできる
  • インターフェースと実装
    • 異なる抽象化となる
    • 同じ抽象化がされている場合はそのクラスは深くない
  • パススルー変数
    • 変数をメソッドチェインで引き渡す
    • 間のメソッドでその変数を意識しなければいけないため複雑度が増す

Chapter8: Pull Complexity Downwards

  • シンプルな実装よりもシンプルなインターフェースが重要
    • 設定パラメーターを採用するのは公開するのはできるだけ避ける
  • 複雑さを引き下げる際に注意する点
    • その複雑さはクラスの機能に関連しているか?
    • アプリケーションのシンプル化に寄与するか?
    • クラスのインターフェースをシンプルにするか?

Chapter9: Better Together or Better Apart

  • 二つの機能を同じ場所で実装するか分離するか
    • 目標は全体としての複雑さを下げてモジュール度を上げること
  • 関連する機能はまとめた方が良い
    • 情報を共有している
    • 一緒に使われる
    • 概念的に重なっている
  • 上のレイヤーの方が専用で下のレイヤーの方が汎用のコードになる傾向がある
    • 汎用/専用が混在する場合は専用のロジックを分離して上のレイヤーにする
  • メソッドの分離と併合
    • 各メソッドが「一つのこと」を「完了させる」ようにすべき
    • 各メソッドが単独で理解できるようにする

Chapter10: Define Errors Out Of Existence

  • 例外は複雑さにつながる
  • 不必要な例外を定義すると例外処理の問題が悪化する
  • 例外の多いクラスは複雑なインターフェースを持ち例外の少ないクラスよりも浅くなる
  • 例外処理を行う場所を減らす
    • 例外をなくす
      • 同じ理由で特別な条件をなくすことも有用
    • 例外マスク
      • システムの下のレイヤーで例外処理を行い、上のレイヤーに例外を伝えない
    • 例外の集約
    • クラッシュさせる

Chapter11: Design it Twice

  • 複数の設計を考えることで良い結果が得られる
    • 一つのアプローチが適していると思っていても2番目の設計を考えてみる

Chapter12: Why Write Comments? The Four Excuses

  • 正しいコメントは設計を改善する
  • コメントを書かない言い訳
    • 良いコードはそれ自体がドキュメントだ
      • ユーザーがコードを読む必要のあるメソッドは抽象化が無い
    • 書く時間がない
      • 10%程度しか時間はかからないしかけたコストはすぐに回収できる
  • コードに表現されていない設計者の考えを捉えることがコメントの考え方

Chapter13: Comments Should Describe Things that Aren't Obvious from the Code

  • コメントはコードで明確になっていないことを書くべき
  • コメント規約を決める
  • コードと同じ内容を繰り返さない
  • 低レベルのコメントは正確さを加え、高レベルのコメントは直感を強化する
  • 良い抽象化を表すコードが欲しければ、その抽象化をコメンドに記述する必要がある
    • インターフェースのコメントと実装のコメントを分離する
    • インターフェースのコメントに実装の内容を混在させない
    • 実装のコメントにはhowではなくwhat/whyを書く

Chapter14: Choosing Names

  • 良い名前はドキュメントの一種
  • 正確で直感的で長すぎない名前をつける
    • 命名が難しい場合はそのオブジェクトの設計がクリアになっていない恐れがある
  • 名前に一貫性を持つ

Chapter15: Write The Comments First

  • 設計プロセスの一部にする
  • コメントを最初に書く
    • 良いコメントになる
    • コメントを書くことで設計が良くなる
    • コメントを書くのが楽しくなる

Chapter16: Modifying Existing Code

  • 修正が完了した際にその修正が最初から存在していた場合と同じ設計になることが理想
  • コメントをメンテナンスする
    • 記述対象のコードの近くにコメントを書く
  • プログラム外にドキュメント済みの情報はリファレンスのみを書く

Chapter17: Consistency

  • 一貫性は複雑さを減らし、振る舞いをより明確にする
  • 一貫性を保つ
    • ドキュメント
    • ツールでチェック
    • 郷にいれば郷に従え
      • 周りのソースに合わせる
    • 既存の規約を変更しない

Chapter18: Code Should be Obvious

  • 良い名前をつける
  • 一貫性
  • スペースを適切にいれてみやすくする
  • コメント
  • コードを不明確にするもの
    • イベントドリブンプログラミング
    • 汎用コンテナ
    • 期待に反する挙動をするコード

Chapter19: Software Trends

Chapter20: Designing for Performance

  • 重い処理を理解し、軽い処理を選択するようにする
    • ネットワーク
    • 二次記憶装置へのI/O
    • 動的メモリ確保
    • キャッシュミス
  • 修正する前に測定する
    • 原因を探る
    • 修正後の基準性能を得る
  • クリティカルパスの周辺のコードを設計する
    • 特別な状況のコードを除いてシンプルにする