1. 設計原則入門 MOC
- 設計原則とは何か
- 設計原則の分類 (概観)
- 設計原則と他の概念との関係
[[設計原則とデザインパターンの関係]](パターンは原則を具現化する手段)[[設計原則とアーキテクチャパターンの関係]][[設計原則とプログラミングパラダイムの関係]]
- 設計原則の適用における心構え
2. SOLID原則 MOC
- S: 単一責任の原則 (SRP - Single Responsibility Principle) MOC
- SRP: 定義 (クラスやモジュールが変更される理由は一つだけであるべき / アクターに対する単一の責任)
- SRP: “責任” と “変更理由”、“アクター” の解釈
- SRP: 目的 (凝集度の向上、結合度の低下、変更時の影響範囲の限定)
- SRP違反の兆候と具体例
[[SRP違反: 多機能クラス (God Classの兆候)]][[SRP違反: 異なる関心事が混在するメソッド]][[SRP違反: 複数のアクターが同じクラスの変更を要求する]]
- SRPを遵守した設計例
[[関心事に基づくクラス分割・メソッド分割]][[FacadeパターンやMediatorパターンによる責任の調整]][[データ永続化ロジックの分離 (例: Repositoryパターン)]][[UIロジックとビジネスロジックの分離]]
- SRP: 利点 (可読性向上、保守性向上、テスト容易性向上、再利用性向上、コンフリクト軽減)
- SRP: 適用時の課題 (適切な「責任」の粒度の判断、クラス数の増加の可能性)
- SRPと他の原則との関連 (OCP, LSP)
- SRPのためのリファクタリングテクニック
[[SRP: Javaにおける実践例]][[SRP: Pythonにおける実践例]][[SRP: C#における実践例|における実践例]]
- O: オープン/クローズドの原則 (OCP - Open/Closed Principle) MOC
- OCP: 定義 (ソフトウェアのエンティティは拡張に対して開いており、修正に対して閉じているべき) (Bertrand Meyer)
- OCP: 目的 (既存コードへの影響を最小限にしつつ機能追加を可能にする)
- OCP違反の兆候と具体例
[[OCP違反: 機能追加のたびに既存クラスのコード変更が必要になる]][[OCP違反: 型や条件に基づく多数のif/elseやswitch文]]
- OCPを遵守した設計例
[[抽象化 (インターフェース、抽象クラス) の利用]][[ポリモーフィズムの活用]][[Strategyパターンによるアルゴリズムの切り替え]][[Decoratorパターンによる機能追加]][[Template Methodパターンによるアルゴリズム骨格の固定と一部カスタマイズ]][[プラグインアーキテクチャ]]
- OCP: 利点 (拡張性向上、保守性向上、影響範囲の限定、再利用性向上)
- OCP: 適用時の課題 (適切な抽象化の予測、過度な抽象化による複雑化)
- OCPと他の原則との関連 (SRP, LSP, DIP)
[[OCP: Javaにおける実践例]][[OCP: Pythonにおける実践例]][[OCP: C#における実践例|における実践例]]
- L: Liskovの置換原則 (LSP - Liskov Substitution Principle) MOC
- LSP: 定義 (派生型はその基底型と置換可能でなければならない) (Barbara Liskov)
- LSP: 目的 (継承関係の正しさの保証、ポリモーフィズムの信頼性確保)
- LSP違反の兆候と具体例
[[LSP違反: サブクラスでスーパークラスのメソッドの事前条件を強化する]][[LSP違反: サブクラスでスーパークラスのメソッドの事後条件を弱化する]][[LSP違反: スーパークラスの不変条件をサブクラスが破壊する]][[LSP違反: サブクラスでオーバーライドしたメソッドが何もしない、または例外を投げる(期待と異なる場合)]][[LSP違反: instanceof や型キャストによる分岐処理]][[正方形は長方形か? (LSPの古典的議論)]]
- LSPを遵守した設計例
[[契約による設計 (Design by Contract) の概念の適用]][[継承よりもコンポジションやインターフェースの利用を検討]][[「IS-A」関係の慎重な検討]]
- LSP: 利点 (コードの信頼性向上、ポリモーフィズムの適切な機能、階層の整合性)
- LSP: 適用時の課題 (厳密な遵守の難しさ、設計初期段階での見極め)
- LSPと他の原則との関連 (OCP, DIP)
[[LSP: Javaにおける実践例]][[LSP: Pythonにおける実践例]][[LSP: C#における実践例|における実践例]]
- I: インターフェース分離の原則 (ISP - Interface Segregation Principle) MOC
- ISP: 定義 (クライアントに、クライアントが利用しないメソッドへの依存を強制すべきではない / 巨大なインターフェースよりも小さく具体的なインターフェース)
- ISP: 目的 (クライアントの関心に合わせたインターフェース提供、不必要な再コンパイル・再デプロイの回避)
- ISP違反の兆候と具体例
[[ISP違反: "Fat Interface" (多機能すぎるインターフェース)]][[ISP違反: クライアントがインターフェースの一部のメソッドしか利用しない]][[ISP違反: メソッドが空実装されたり、例外をスローしたりするクラス]]
- ISPを遵守した設計例
[[ロールインターフェース (Role Interface) への分割]][[Adapterパターンによるインターフェース変換]]
- ISP: 利点 (凝集度の向上、結合度の低下、再利用性の向上、保守性の向上)
- ISP: 適用時の課題 (インターフェース数の増加、適切な分割単位の判断)
- ISPと他の原則との関連 (SRP, LSP)
[[ISP: Javaにおける実践例]][[ISP: Pythonにおける実践例 (ダックタイピングとの関連)]][[ISP: C#における実践例|における実践例]][[ISPとGo言語のインターフェース]]
- D: 依存性逆転の原則 (DIP - Dependency Inversion Principle) MOC
- DIP: 定義 (上位モジュールは下位モジュールに依存すべきではない。両者とも抽象に依存すべき。抽象は詳細に依存すべきではない。詳細が抽象に依存すべき)
- DIP: 目的 (モジュール間の疎結合化、柔軟性と再利用性の向上)
- DIP違反の兆候と具体例
[[DIP違反: 上位クラスが具象的な下位クラスを直接インスタンス化・利用する]][[DIP違反: ビジネスロジックが具体的なデータベースアクセス技術に依存する]]
- DIPを遵守した設計例
[[抽象インターフェースまたは抽象クラスの導入]]- 依存性注入 (DI - Dependency Injection) (コンストラクタ注入, セッター注入, インターフェース注入)
[[Service Locatorパターン]](DIの代替だが注意が必要)[[Inversion of Control (IoC) コンテナ / DIフレームワークの利用]](Spring, Guice, .NET Core DIなど)[[FactoryパターンやAbstract Factoryパターンによるインスタンス生成の抽象化]]
- DIP: 利点 (柔軟性向上、拡張性向上、テスト容易性向上、モジュールの交換可能性)
- DIP: 適用時の課題 (抽象レイヤーの追加による複雑性の増加、適切な抽象の設計)
- DIPと他の原則との関連 (OCP, LSP)
[[DIP: Javaにおける実践例]][[DIP: Pythonにおける実践例]][[DIP: C#における実践例|における実践例]]
3. その他の重要な設計原則 MOC
- DRY原則 (Don’t Repeat Yourself) MOC
- DRY: 定義 (システム内のあらゆる知識は、単一かつ明確な、信頼できる表現を持たなければならない)
- DRY: “知識”の範囲 (コード、データ、ドキュメントなど)
- DRY: 目的 (重複排除による保守性、一貫性、信頼性の向上)
[[DRY違反 (WET - Write Everything Twice / We Enjoy Typing / Waste Everyone's Time) の例]]- メソッド化、クラス化、設定ファイル、コード生成など)
- DRYの利点と適用時の注意点 (時期尚早な抽象化、誤った共通化)
- Keep It Short and Simple) MOC
- KISS: 定義 (設計は可能な限りシンプルであるべき)
- KISS: 目的 (理解しやすさ、保守しやすさ、バグの低減)
[[KISS違反の例 (過度な機能、不必要な複雑性)]]- KISSと他の原則 (YAGNI) との関連
- シンプルさの多様な側面 (コード、アーキテクチャ、UI)
- YAGNI原則 (You Ain’t Gonna Need It) MOC
- YAGNI: 定義 (実際に必要になるまで機能を追加しない)
- YAGNI: 目的 (無駄な開発コストの削減、システムのシンプルさ維持)
[[YAGNI違反の例 (将来のための過剰な汎用化、未使用機能の実装)]]- YAGNIとアジャイル開発、MVP (Minimum Viable Product)
- 最小知識の原則 (Principle of Least Knowledge) MOC
- LoD: 定義 (オブジェクトは、密接に関連するオブジェクトとだけ通信すべき) (“友達の友達とは話すな”)
- LoD: 目的 (オブジェクト間の結合度の低減、カプセル化の強化)
[[LoD違反の例 (メソッドチェーンの奥深くまでアクセスする: obj.getA().getB().getC().doSomething())]]- LoDを遵守した設計 (メソッド呼び出しの対象範囲)
- LoDの利点と適用時の注意点 (ラッパークラスの増加の可能性)
- 「継承よりコンポジション (Composition over Inheritance)」の原則 MOC
- [[この原則が推奨される理由 (柔軟性、カプセル化の維持、“IS-A” vs “HAS-A”)] ]
- 継承の問題点 (密結合、脆弱な基底クラス問題)
- コンポジションと委譲による柔軟な機能拡張
- カプセル化 (Encapsulation) の原則 (再掲・原則としての重要性)
- Principles) MOC (Craig Larman)
- パターン (概要)
[[情報エキスパート (Information Expert)]][[生成者 (Creator)]][[コントローラ (Controller)]][[低結合 (Low Coupling)]](再掲)[[高凝集 (High Cohesion)]](再掲)[[ポリモーフィズム (Polymorphism)]](原則としての活用)[[純粋人工物 (Pure Fabrication)]][[間接化 (Indirection)]][[保護された変更 (Protected Variations)]]
- パターン (概要)
4. 設計原則の適用と実践 MOC
- 原則をいつ、どのように適用するか
- 原則間のトレードオフとバランス
- 設計原則の学習と継続的な改善