つの重要なポイント
### 1. 複雑さはソフトウェア設計の課題の根源である
> 複雑さは依存関係と不明瞭さの蓄積から生じる。
**複雑さは徐々に蓄積する。** ソフトウェアシステムが成長するにつれて、コンポーネント間の依存関係や不明瞭なコードセクションの蓄積により、複雑さが増していく。この複雑さは主に以下の三つの形で現れる:
- 変更の増幅:小さな変更が多くの場所での修正を必要とする
- 認知負荷:開発者が変更を行うために大量の情報を理解する必要がある
- 未知の未知:どのコードを修正する必要があるか、どの情報が関連しているかが不明確である
**シンプルさが解毒剤である。** 複雑さに対抗するために、ソフトウェア設計者は依存関係と不明瞭さを最小限に抑えたシンプルで明確な設計に焦点を当てるべきである。これには以下が含まれる:
- モジュラー設計:システムを独立したモジュールに分割する
- 情報隠蔽:実装の詳細をモジュール内にカプセル化する
- 明確な抽象化:基礎的な複雑さを隠すシンプルなインターフェースを提供する
### 2. 戦略的プログラミングは戦術的アプローチに勝る
> 最良のアプローチは、継続的に小さな投資を行うことである。
**長期的な思考がより良い結果をもたらす。** 戦略的プログラミングは、単にコードを動作させるのではなく、優れた設計を作成することに焦点を当てる。このアプローチには以下が含まれる:
- 設計に時間を投資する
- 継続的に小さな改善を行う
- クリーンな設計を維持するためにリファクタリングを行う
**戦術的プログラミングは技術的負債を生む。** 戦術的アプローチは短期的には速く見えるかもしれないが、しばしば以下の結果をもたらす:
- クイックフィックスやハックの蓄積
- 時間が経つにつれて変更が難しくなる
- 長期的な開発コストの増加
戦略的なマインドセットを採用することで、開発者は保守しやすく進化しやすいシステムを作成し、最終的には時間と労力を節約することができる。
### 3. モジュールは浅くなく深くあるべきである
> 最良のモジュールは強力な機能を提供しながらもシンプルなインターフェースを持つものである。
**深さが抽象化を生む。** 深いモジュールは、シンプルなインターフェースの背後に大きな実装の複雑さを隠す。このアプローチは以下を促進する:
- モジュールのユーザーの認知負荷を減らす
- 実装の変更を容易にする
- 情報隠蔽とカプセル化を促進する
**浅いモジュールは複雑さを増す。** 機能に対して複雑なインターフェースを持つモジュールは浅いと見なされる。これらのモジュールは以下を引き起こす:
- システム全体の複雑さを増加させる
- 不要な実装の詳細を露出させる
- システムの理解と変更を難しくする
深いモジュールを作成するためには、基礎的な複雑さを抽象化するシンプルで直感的なインターフェースの設計に焦点を当てるべきである。機能とインターフェースの複雑さの比率を最大化することを目指す。
### 4. 良いインターフェースは複雑さを管理する鍵である
> モジュールのインターフェースには形式的な情報と非形式的な情報の二種類が含まれる。
**よく設計されたインターフェースはシステムを簡素化する。** 良いインターフェースは、不要な詳細を露出させずにモジュールの機能を明確に抽象化するべきである。これには以下が含まれる:
- シンプルで直感的に使用できる
- 実装の複雑さを隠す
- 形式的な情報(例:メソッドシグネチャ)と非形式的な情報(例:高レベルの動作説明)を提供する
**インターフェースは慎重に進化させるべきである。** 既存のコードを変更する際には:
- モジュールのインターフェースへの影響を考慮する
- 実装の詳細を露出させない
- インターフェースが提供する抽象化を維持または改善することを目指す
良いインターフェースの作成と維持に焦点を当てることで、開発者は複雑さを管理し、システムをよりモジュール化し理解しやすくすることができる。
### 5. コメントは抽象化を作成するために重要である
> コメントは抽象化を完全に捉える唯一の方法であり、良い抽象化は良いシステム設計の基礎である。
**コメントは抽象化を完成させる。** コードは実装の詳細を表現できるが、コメントは以下を捉えるために不可欠である:
- 高レベルの設計決定
- 選択の背後にある理由
- 期待と制約
- コードだけでは明らかでない抽象化
**まずコメントを書く。** コードを実装する前にコメントを書くことで:
- 設計についての考えを明確にする
- 早期に抽象化を評価し洗練する
- ドキュメントが常に最新であることを保証する
**何を、なぜを重視し、どうやってを避ける。** 良いコメントは以下を行うべきである:
- コードから明らかでないことを説明する
- コードの目的と高レベルの動作を説明する
- 単にコードが何をするかを繰り返さない
明確で情報豊富なコメントを優先することで、開発者はより良い抽象化を作成し、システム全体の設計を改善することができる。
### 6. 一貫した命名とフォーマットは可読性を向上させる
> 良い名前はドキュメントの一形態であり、コードを理解しやすくする。
**一貫性は認知負荷を減らす。** 命名とフォーマットの規約を確立し、それに従うことで、開発者は以下を行うことができる:
- コードをより予測可能で読みやすくする
- コードを理解するための精神的な努力を減らす
- バグや設計上の問題を示す不一致を強調する
**名前を慎重に選ぶ。** 良い名前は以下の特性を持つべきである:
- 正確で曖昧でない
- 名前が示す対象の明確なイメージを作り出す
- コードベース全体で一貫して使用される
**フォーマットも重要である。** 一貫したフォーマットは以下を助ける:
- コードの構造をより明確にする
- 関連する要素を視覚的にグループ化する
- 重要な情報を強調する
命名とフォーマットに注意を払うことで、開発者はコードの可読性と保守性を大幅に向上させることができる。
### 7. 継続的な改良はクリーンな設計を維持するために不可欠である
> 長期的に効率的に作業できるクリーンなソフトウェア構造を望むなら、最初にその構造を作成するために少し余分な時間をかける必要がある。
**設計は継続的なプロセスである。** クリーンなソフトウェア設計には以下が必要である:
- 既存のコードを改善するための定期的なリファクタリング
- 設計決定の継続的な評価
- システムが進化するにつれて変更を行う意欲
**改善に投資する。** クリーンな設計を維持するためには:
- クリーンアップとリファクタリングのための時間を割り当てる
- 設計上の問題を早期に対処し、複雑化する前に解決する
- 各コード変更を全体の設計を改善する機会と見なす
**完璧と進捗のバランスを取る。** クリーンな設計を目指す際には:
- いくつかの妥協が必要であることを認識する
- 漸進的な改善に焦点を当てる
- 最も重要な利益をもたらす変更を優先する
設計を継続的な改良のプロセスとして扱うことで、開発者はシステムが成長し進化する中でクリーンで管理しやすい状態を維持することができる。
### 8. エラーハンドリングは簡素化すべきであり、増やすべきではない
> 例外処理の複雑さを排除する最良の方法は、例外を処理する必要がないようにAPIを定義することである:エラーを存在しないものとして定義する。
**例外ケースを減らす。** エラーハンドリングを簡素化するためには:
- 例外的な条件を最小限に抑えるようにAPIを設計する
- 一般的なエッジケースを処理するデフォルトの動作を使用する
- 例外が本当に必要かどうかを検討する
**エラーハンドリングを集約する。** 例外が避けられない場合には:
- 可能な限り一箇所で複数の例外を処理する
- 関連するエラーの処理を簡素化するために例外階層を使用する
- 意味のある処理ができない例外をキャッチしない
**通常のケースを簡単にする。** エラーのない一般的なパスをできるだけシンプルで明確にすることに焦点を当てる。このアプローチは以下を促進する:
- 開発者の認知負荷を減らす
- バグの導入の可能性を最小限に抑える
- コードの理解と保守を容易にする
エラーハンドリングを簡素化することで、開発者はより堅牢で理解しやすいシステムを作成することができる。
### 9. 汎用コードは特定用途のソリューションよりも優れていることが多い
> クラスを特定の用途で使用する場合でも、汎用的な方法で構築する方が労力が少ない。
**汎用性は再利用性を促進する。** 汎用コードは:
- より広範な問題に適用できる
- よりシンプルで抽象的であることが多い
- クリーンなインターフェースを持つ傾向がある
**早期の特化を避ける。** 新しい機能を設計する際には:
- ある程度汎用的なアプローチから始める
- 早期に特定のユースケースに最適化する衝動に抵抗する
- 実際の使用パターンに基づいて設計を進化させる
**汎用性とシンプルさのバランスを取る。** 汎用的なソリューションを目指す際には:
- 過剰なエンジニアリングや不要な複雑さを避ける
- 汎用設計が一般的なケースでも使いやすいことを確認する
- 本当に必要な場合には特化したソリューションを作成する意欲を持つ
汎用的な設計を優先することで、開発者は将来の要件に対応しやすい、より柔軟で保守しやすいシステムを作成することができる。
### 10. コードは書きやすさではなく読みやすさを重視して書く
> ソフトウェアは書きやすさではなく、読みやすさを重視して設計されるべきである。
**長期的な保守性を優先する。** コードを書く際には:
- 将来の読者が理解しやすいようにすることに焦点を当てる
- コードの目的を曖昧にするショートカットや巧妙なトリックを避ける
- 明確な抽象化とドキュメントの作成に時間を投資する
**コードを明確にする。** 以下を目指してコードを書く:
- 最小限の精神的努力で迅速に理解できる
- 明確で一貫した命名規則を使用する
- 論理的でわかりやすい構造を持つ
**明確さのためにリファクタリングする。** 既存のコードを定期的にレビューし改善する:
- 複雑なセクションを簡素化する機会を探す
- 長いメソッドをより小さく焦点を絞った部分に分割する
- 重複や不一致を排除する
読みやすさを重視することで、開発者は保守、デバッグ、拡張が容易なシステムを作成することができる。このアプローチは最初はより多くの努力を必要とするかもしれないが、長期的な複雑さの軽減とチームの生産性の向上に繋がる。
Last updated:
レビュー
本書『A Philosophy of Software Design, 2nd Edition』は賛否両論を受けている。多くの読者は、複雑さの管理や深いモジュールの設計に関する洞察を称賛しているが、一部の読者はコメントの重要性に対する強調や特定の分野での深みの欠如を批判している。特に新しい開発者にとって、明確な文章と実践的なアドバイスが評価されている。しかし、経験豊富なプログラマーの中には、内容が基本的すぎると感じたり、特定の推奨事項に同意しない人もいる。本書のオブジェクト指向プログラミングと学術的な視点に焦点を当てている点が指摘されており、より多様な言語の例や実世界の応用を望む声もある。