Upgrade to Pro — share decks privately, control downloads, hide ads and more …

2025-05-28 社内勉強会 SOLID原則ではじめるよりよい設計の第一歩 / The F...

2025-05-28 社内勉強会 SOLID原則ではじめるよりよい設計の第一歩 / The First Step to Better Software Design with SOLID Principles

Avatar for Kentaro Abe

Kentaro Abe

May 28, 2025
Tweet

More Decks by Kentaro Abe

Other Decks in Programming

Transcript

  1. 6 • 機能の修正が簡単 • 機能の追加が簡単 • 修正範囲が明確 • 影響範囲が明確 •

    テストがしやすい • リリーススピードが早い • バグの原因追求がしやすい よい設計の指標(一例) 「よい設計」は状況によって異なる 例えば保守しない案件では、 コードの読みやすさや バグの原因追求のしやすさは 優先度が低いかもしれない
  2. 7 • 機能の修正が簡単 • 機能の追加が簡単 • 修正範囲が明確 • 影響範囲が明確 •

    テストがしやすい • リリーススピードが早い • バグの原因追求がしやすい 今回考える「よい設計」の指標
  3. 12 SOLID原則 略称 英語名称 日本語名称 SRP Single Responsibility Principle 単一責任の原則

    OCP Open-Closed Principle 開放閉鎖の原則 LSP Liskov Substitution Principle リスコフの置換原則 ISP Interface Segregation Principle インターフェース分離の原則 DIP Dependency Inversion Principle 依存性逆転の原則
  4. 13 • クラスや関数は、ただひとつの機能について責任を持つ • どこまでをひとつの機能とするべきかは状況による ◦ 例)ファイルの読み書きを分けるか? 単一責任の原則 • Single

    Responsibility Principle • Open-Closed Principle • Liskov Substitution Principle • Interface Segregation Principle • Dependency Inversion Principle 変更するための理由が、一つのクラスに対して一つ以上あってはならない いい言葉!
  5. 14 • 拡張(機能追加)するときに既存コードを修正するべきでない • すごくざっくり言うと、ポリモーフィズムを駆使して if文を減らそうって話 開放閉鎖の原則 • Single Responsibility

    Principle • Open-Closed Principle • Liskov Substitution Principle • Interface Segregation Principle • Dependency Inversion Principle ソフトウェアの実体(クラス、モジュール、関数など)は、 拡張に対して開かれているべきであり、修正に対して閉じていなければならない
  6. 15 • サブクラスは親クラスの代わりとして使えるべき • 主に継承に適用される原則 • かなり理論的な原則で、もう少し細かい定義がある • 今日はあまり扱いません リスコフの置換原則

    • Single Responsibility Principle • Open-Closed Principle • Liskov Substitution Principle • Interface Segregation Principle • Dependency Inversion Principle ある基底クラスへのポインタないし参照を扱っている関数群は、その派生クラスの オブジェクトの詳細を知らなくても扱えるようにしなければならない リスコフさん→
  7. 16 • インターフェースはこの機能を保証します、という「約束」 • 保証できない機能の実装を強制してはならない • 小さいインターフェースを組み合わせる インターフェース分離の原則 • Single

    Responsibility Principle • Open-Closed Principle • Liskov Substitution Principle • Interface Segregation Principle • Dependency Inversion Principle 汎用なインターフェースが一つあるよりも、 各クライアントに特化したインターフェースがたくさんあった方がよい
  8. 17 • 依存とは「使うこと」 ◦ 使う側が使われる側に依存する • より安定したものに依存しましょう ◦ 安定=変更が少ない ◦

    下位より上位が安定 ◦ 具象より抽象が安定 依存性逆転の原則 • Single Responsibility Principle • Open-Closed Principle • Liskov Substitution Principle • Interface Segregation Principle • Dependency Inversion Principle 上位モジュールはいかなるものも下位モジュールから持ち込んではならない。 双方とも具象ではなく、抽象(インターフェースなど)に依存するべきである
  9. 18 各原則の関係 原則 他の原則との関係 SRP 根底となる原則。適切な責務分割で修正範囲を限定する。 OCP クラス設計で目指す形。各クラスの関係性を工夫し 変更容易性を上げる。 LSP

    OCPのためのテクニック。サブクラスを交換可能にする方法。 ISP OCPのためのテクニック。クラス間のインターフェース定義の方法。 DIP OCPのためのテクニック。クラス間の依存方向をコントロールする方法。 1. SRPでクラスの責務をひとつにし、修正が他のクラスに及ばないようにする 2. LSP/ISP/DIP を用いて、修正・追加が容易なOCPを目指す
  10. 21 • 設定を表現するクラス ◦ ApiConfig:APIの設定を 保持しているクラス ◦ DbConfig:DBの設定を 保持しているクラス ◦

    RedisConfig:Redisの 設定を保持しているクラス 本発表で扱う問題 • 設定クラスを利用するクラス ◦ Api:外部APIを呼び出すクラス ◦ Db:DBからデータ取得するクラス ◦ Redis: Redisからデータ取得するクラス • データを取得して処理するクラス ◦ UserRepository: Api/Db/Redis などのクラスを 使ってデータを処理する ユーザーの情報を 外部APIやDBから取得するシステム
  11. 22 問題設定 • API、DBそれぞれにjson形式の設定ファイルがある • 設定ファイルの中身は、どちらもidとpasswordがある わるい設計 • 設定ファイルのidとpasswordを返すConfigManager •

    idとpasswordを取得したいのは同じなので、ConfigManagerとして共通 化 1. 単一責任の原則( SRP) api_config.json db_config.json 変更するための理由が、一つのクラスに 対して一つ以上あってはならない
  12. 31 1. プロパティが多い 2. クラスの責任を端的に言えない 3. プロパティで条件分岐する 4. テストが書きづらい 5.

    修正が伝播する 単一責任の原則違反のにおい プロパティが多い場合、次の可能性が 高い • 2つ以上の責任を表現しようとして いる • プロパティを媒介に修正が伝播す る
  13. 32 1. プロパティが多い 2. クラスの責任を端的に言えない 3. プロパティで条件分岐する 4. テストが書きづらい 5.

    修正が伝播する 単一責任の原則違反のにおい 幅広い意味を持つ名前のクラスは、様々な 責任を負わされる 「設定を管理する(ConfigManager)」はそ の典型例 もう一段階具体的に説明できないか 考えるべし
  14. 33 1. プロパティが多い 2. クラスの責任を端的に言えない 3. プロパティで条件分岐する 4. テストが書きづらい 5.

    修正が伝播する 単一責任の原則違反のにおい flagやtypeなどのプロパティを持ち、 条件分岐しているもの プロパティによって「やりたいこと」が異な る →つまり責任が異なる 単一責任の原則にしたがってクラスを分 離する
  15. 34 1. プロパティが多い 2. クラスの責任を端的に言えない 3. プロパティで条件分岐する 4. テストが書きづらい 5.

    修正が伝播する 単一責任の原則違反のにおい 複数の責任があると、テストケースが膨 大になる メソッドもシンプルになっているはずな ので、テスト自体も複雑にならない
  16. 35 1. プロパティが多い 2. クラスの責任を端的に言えない 3. プロパティで条件分岐する 4. テストが書きづらい 5.

    修正が伝播する 単一責任の原則違反のにおい 複数の責任が一つのクラスに集まって いる 異なる責任の間でプロパティやメソッド を共有できてしまう ある責任に対する修正が、別の責任を 扱う箇所にも伝播する
  17. 38 問題設定 • UserRepositoryは、データを取得してユーザー一覧を返す • データの取得元にはAPIとDBがあり、切り替えられるようにする わるい設計 • UserRepositoryに、APIクラスとDBクラスのプロパティを持たせる •

    どちらを取得元にするかは、コンストラクタで設定する 2. 開放閉鎖の原則( OCP) ソフトウェアの実体は、拡張に対して開か れているべきであり、修正に対して閉じて いなければならない
  18. 48 問題設定 • APIを実行するApiクラス、DBから データを取得するDbクラス • それぞれの接続情報を ApiConfig、DbConfigに持つ わるい設計 •

    各Configクラスは ConfigInterfaceを実装 4. インターフェース 分離の原則( ISP) 一つの汎用なインターフェースより、 特化したインターフェースがたくさんあっ た方がよい
  19. • DIPは依存の方向をコントロールする手法 • 右のクラス図だけをみても、 設計の良し悪しを議論できない • 議論のために、次の前提を導入する UserRepositoryはApiに依存しているので、Apiの変更はUserRepositoryに 伝播する 逆に、UserRepositoryの変更はApiに伝播しない

    わるい設計の問題点 上位モジュールは下位モジュールから 何も持ち込んではならない 具象ではなく、抽象に依存するべき 55 • Apiの修正が頻繁に行われたり、他のクラスと頻繁に交換される
  20. 61 • DRY原則 Don't Repeat Yourself ◦ すべての知識はシステム内において、単一、かつ明確な、そして信頼 できる表現になっていなければならない •

    KISSの原則 Keep It Simple, Stupid ◦ 単純さを追求し、複雑さを避けること • YAGNI原則 You Ain't Gonna Need It ◦ 本当に必要になるまで作らない方がよい おまけ:その他の設計原則