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

疎結合とは何か?ソフトウェア設計における結合バランスについて考える #phpcon_niigata

疎結合とは何か?ソフトウェア設計における結合バランスについて考える #phpcon_niigata

PHPカンファレンス新潟2026の登壇資料です
https://fortee.jp/phpconniigata-2026/proposal/8ae18ca3-3db5-4ffa-8c27-1fe5d65da631

Takuma Kajikawa

November 14, 2026

Transcript

56 slides
  1. 梶川 琢馬 𝕏 @kajitack 株式会社 TechBowl VPoT TechTrain の開発/メンター PHP

    カンファレンス新潟は 2 回目 佐渡島(200km)を自転車で 1 周したことがある スライドは X で公開します! x.com/kajitack 2/56
  2. 強度、距離、変動性で色んなことが分かる 言葉 式 安定性 NOT (変動性 AND 強度) 変更コスト 変動性

    AND 距離 モジュール性 強度 XOR 距離 複雑性 NOT (強度 XOR 距離) メンテナンスの労力 強度 × 距離 × 変動性 均衡度 (強度 XOR 距離) OR NOT 変動性 意味 上流の変更が下流へ連鎖しにくいこと 変動性か強度が低ければ安定 連鎖的な変更を合わせる実際のコスト 変動性が高く距離が遠いと高い 変更に要る認知負荷を小さく抑える能力 強度と距離が対照的だと高い 変更や理解に要る認知負荷 強度と距離が等しいと高い 依存関係を維持するために予想される労力 3 つのどれかが低ければ小さい 設計がモジュール性と複雑性のどちらに向かうか モジュラーか、変動性が低ければ高い 14/56
  3. 強度 共有する「知識」が多いほど、強度は高い 知識には、メソッド呼び出しの引数や共通のルールなど、さまざまな形がある 相手が公開していない 内部の知識を使う 相手の振る舞いと 前提の知識を持つ 相手のモデルの 知識を共有する 統合用に用意した

    知識だけを使う 例:具象クラスの継承、 trait の use 例:new、静的 メソッド呼び出し 例:引数と戻り値 の型 例:interface への依存 (侵入結合) (機能結合) (モデル結合) (コントラクト結合) 共有が多い 共有が少ない 16/56
  4. 公開されていない内部の知識を使うと、強度はいちばん高い (侵入結合) class Customer { private string $status; } PHP

    別のモジュール // $property = new ReflectionProperty(Customer::class, 'status'); $status = $property->getValue($customer); クラスの作者は、外から読まれていることを知らない プロパティ名を変える度に変更が必要 17/56
  5. 同じルールの知識を別々に持つと、強度はやや高い (機能結合) 注文モジュール // function isFreeShipping(Order $order): bool { return

    $order->totalCost > 1000; } PHP 配送モジュール // function isFreeShipping(Order $order): bool { return $order->totalCost > 1000; } 呼び出し関係はないのに、ルールが変わると両方を同時に直す必要がある 18/56
  6. モデルの知識をまるごと共有する場合、強度は低め (モデル結合) 顧客管理モジュール // class CustomerRepository { public function get(string

    $id): Customer { /* ... */ } } PHP 分析モジュール // $status = $repository->get($customerId)->status; 欲しいのはステータスだけなのに、Customer 全体の構造を知っている 19/56
  7. 統合用に用意した知識だけを使うと、強度はいちばん低い (コントラクト結合) 顧客管理モジュール // class CustomerRepository { public function getStatus(string

    $id): Status { /* ... */ } } PHP 分析モジュール // $status = $repository->getStatus($customerId); Customer の中身が変わっても、分析モジュールは影響を受けない 20/56
  8. データベースの共有 A ↓ B ↓ A の DB(非公開) A ↓

    B ↓ A の DB(読み取り可) A の DB を、B が 勝手に SELECT する A ↓ (侵入結合) 同じテーブル (機能結合) B が A のテーブルの 列をそのまま読む A ↓ B 向けの最小限の 列だけを読む (モデル結合) 公開用のビュー B ↓ B ↓ 同じ入力チェックを A と B の両方に書く (コントラクト結合) 21/56
  9. 非同期処理 非同期にすること自体は、強度を下げない 共有の仕方 専用の DTO を渡す コントラクト結合 Eloquent モデルをそのまま渡す モデル結合

    別のリスナが終わっている前提で動く 機能結合 失敗したら呼び出し元で打ち消しが要る 機能結合 統合用ではないキューを直接読む 侵入結合 なぜその強度か 受け手は DTO の形だけを知る。送り手の内部モデルは漏れていない 受け手がテーブルの構造まで知ることになる 処理の順番を、受け手が前提にしている 全部成功か全部失敗か、という約束を両方で守る 統合のために用意されていない経路を使っている 22/56
  10. 同じ知識を、サービス境界の向こうで共有すると 改善前。同じ計算が、別の境界にある 注文サービス // final class Tax { public function

    of(int $price): int { return (int) ($price * 0.1); } } PHP 請求サービス // final class Tax { public function of(int $price): int { return (int) ($price * 0.1); } } 同じ知識を、サービスの外で共有している 26/56
  11. 同じ知識は、同じ境界の近くで共有する 改善後。同じ境界の中で、1 つの計算を使う 同じサービスの中 // final class Tax { public

    function of(int $price): int { return (int) ($price * 0.1); } } PHP $orderTax = $tax->of($price); $billTax = $tax->of($price); 近くで共有すると、1 箇所を直せばよい 27/56
  12. 距離が遠いと、調整もリリースも分かれる 注文アプリ(リリース ) // A $rate = $this->billingApi->taxRate(); PHP 請求アプリ(リリース

    ) // B public function taxRate(): float { return 0.1; } 税率を変えるとき、2 つのリリースのタイミングを合わせるように調整が必要になる 28/56
  13. 距離が近いと、リリースの単位を同じにできる 同じアプリケーション // final class Tax { public function rate():

    float { return 0.1; } } PHP $order->tax = $tax->of($price); 関係する変更を、同じリリースで反映できる 29/56
  14. 疎結合とは、強度が低く、距離が遠いこと モジュール性 = 強度 XOR 距離 変更に要る認知負荷を小さく抑える能力 複雑性 = NOT

    (強度 XOR 距離) 変更や理解に要る認知負荷 強 度 高 強 度 低 高凝集 密結合 一緒に変わるものが近くにある 一緒に変わるのに遠い モジュラー 複雑 低凝集 疎結合 関係が薄いのに近くにある 関係が薄く、離れている 複雑 モジュラー 距離 低 距離 高 31/56
  15. 変動性の見積もり方は 2 つ ドメイン的に重要な変更なのか、他の変更に影響されていたりバグ修正が多かったりするのか ドメイン分析 ソースコード分析 見るもの サブドメインの種類(コア、支援、汎用) モジュールごとのコミット数 向く場面

    これから変わりやすいかを予測する 既存のコードで、実際の変わり方を見る 注意 将来の予測は難しい 修正と機能追加を分けて数える 変更が少なくても、触れないから変わらないだけのことがある 34/56
  16. 結合バランスの論理式 モジュール性 = (強度 XOR 距離) バランス = モジュール性 OR

    NOT 変動性 = (強度 XOR 距離) OR NOT 変動性 モジュール性が高いか変動性が低ければバランスが取れている状態 35/56
  17. ケーススタディ 01 同じコードベースの設計 同じコードベースの中 たとえば、課題とユーザーが、同じアプリの中にある場合 書き方 ユーザーが、課題の内部テーブルを直接読む 侵入結合 同じ判定を、課題とユーザーの両方に書く 機能結合

    ユーザーが、課題の Eloquent モデルをそのまま使う モデル結合 ユーザーが、課題の用意した DTO だけを使う コントラクト結合 なぜその強度か 課題が公開していない内部を使っている ルールが変わったら、両方を同時に直す必要がある 課題のテーブルの構造まで知っている 課題が公開すると決めた形だけを知っている 40/56
  18. ケーススタディ 03 イベントによる後続処理の分離 キューを挟んでもモデル結合のままになりうる 改善前。送り側のモデルをキューに乗せる final class User { public

    string $name; public string $email; public string $passwordHash; } PHP $queue->push($user); 非同期にしただけでは強度は下がらない 48/56

More Decks by Takuma Kajikawa

Other Decks in Programming