03. 結合の物差し(統合強度×距離×変動性)

目的

  • 結合を「統合強度(S)×距離(D)×変動性(V)」で扱い、手当の優先順位を付ける
  • 過剰設計(将来不確実性への先回り)を、観測可能な指標で抑制する

得られる判断能力

  • 「結合=知識の共有」として、依存関係を言語化できる
  • S/D/V で結合を半定量評価し、改善の優先順位を付けられる
  • 分離(抽象化・境界追加)と統合(まとめる)のトレードオフを説明できる

前提/用語

  • 統合強度(S): 同時変更・同時デプロイが必要な強さ
  • 距離(D): 依存が跨ぐ境界の遠さ(組織、レポジトリ、実行環境、ネットワーク)
  • 変動性(V): 仕様/実装が変わる頻度と不確実性

S/D/V の採点ガイド

S/D/V は「厳密な測定」ではなく、意思決定の再現性を上げるための半定量です。重要なのは、点数そのものより 根拠(観測) を残すことです。

スケール(目安)

2/4 は中間として扱います(例: 3 と 5 の間)。

統合強度(S) 距離(D) 変動性(V)
1 独立に変更・デプロイできる 同一モジュール/同一プロセス内 ほぼ固定(年単位でしか変わらない)
3 時々同時変更が必要 同一リポジトリ内の別領域/別パッケージ 月〜四半期単位で変わる
5 ほぼ常に同時変更・同時デプロイが必要 別サービス/別組織/ネットワーク越し 週次で変わる/不確実性が高い

観測のしかた(何を見ればよいか)

  • S(統合強度):
    • 変更が同じ PR/同じリリースに乗りがちか
    • 片方だけ変更すると本番で破綻する(互換性がない)か
    • 障害時に「片方だけロールバックできない」か
  • D(距離):
    • 境界をいくつ跨ぐか(例: UI → API → DBusecase → 外部メールI/F
    • レポジトリ/デプロイ単位/実行環境が分かれているか
    • 組織・責任分界(別チーム、別ベンダ)があるか
  • V(変動性):
    • 仕様変更がどの頻度で発生するか(実績/ロードマップ)
    • 例外系・条件分岐が増え続けているか(複雑化の兆候)
    • 「まだ決まっていない」項目が多いか(不確実性が高い)

要点

  • S が強いほど、分離よりも「一体として扱う」ほうがコストが低い場合がある
  • D が大きいほど、契約(インターフェース、合意、テスト)を強める必要が出る
  • V が高い箇所に、固定的な抽象化を入れると破綻しやすい

補足: 本書でいう「結合」は、主に 知識の共有 として扱います。

  • あるモジュールが、別モジュールの内部事情(データ構造、例外、順序、タイミング)を知っているほど、変更が波及しやすい
  • 「知っていること」を減らす手段が、境界(契約)とテスト(契約の検証)です

典型的な手当(S/D/V別)

S/D/V は「分けるべき/まとめるべき」の二択を出す道具ではありません。各軸の悪化に応じて、手当の方向性が変わります。

  • S が高い:
    • 無理に分離せず、同時変更の前提を明確化する(同一モジュールとして扱う、責務の境界だけ整える)
    • 共有データ構造・仕様を domain に寄せ、重複実装を減らす
  • D が高い:
    • 契約(API/スキーマ/インターフェース)を明文化し、統合テストや契約テストで検証する
    • 失敗・遅延・リトライを前提に、運用(ログ/監視/アラート)とセットで設計する
  • V が高い:
    • 固定的な抽象化を増やし過ぎない(将来の不確実性に対する先回りを避ける)
    • 変更点を局所化する(Functional core、設定化、差分吸収の境界を置く)

実務では「S と D と V が同時に高い」領域が最大リスクになりやすい一方で、S が強いなら「まとめる」ほうが合理的な場合があります。点数と合わせて、判断理由(トレードオフ)を残してください。

例(ランニング例)

タスク管理を例に、S/D/V を当てはめます。

  • 期限判定ロジック(期限超過 の定義)を UI と API がそれぞれ独自実装している
    • S: 3(両方同時に直さないと破綻)
    • D: 2(同一リポジトリだが別領域)
    • V: 4(運用で頻繁にルールが変わる可能性)
    • 手当案: 期限判定を domain に集約し、UI/API は同一関数を利用する(知識の共有を domain 側に寄せる)
  • 権限判定(管理者のみ割り当て可)を UI と API が別々に持っている
    • S: 4(同時変更しないと「見えるができない/できるが見えない」が起きる)
    • D: 3(UI と API の境界を跨ぐ)
    • V: 3(役割・例外が増えやすい)
    • 手当案: 判定ロジック(ルール)を domain に寄せ、UI/API は判定結果を利用する
  • メール通知(外部I/F)をユースケースが直接呼んでいる
    • S: 2(通知が失敗しても業務継続できる設計なら同時変更は必須ではない)
    • D: 4(ネットワーク越し、失敗・遅延を前提)
    • V: 3(通知要件が増える余地がある)
    • 手当案: 通知I/Fを adapter として分離し、ユースケースは「通知要求」を発行する(リトライ/監視は境界側に寄せる)

通し例(採点→手当→テスト配分): 割り当て通知

対象: 「タスク割り当て(業務) → 通知(外部I/F)」の依存関係をどう扱うか。

  1. 採点(B-4)
    • S: 2(通知が失敗しても、割り当て自体は成立させたい)
    • D: 4(外部サービス。失敗・遅延・タイムアウトが現実に起きる)
    • V: 3(通知条件/文言/チャネル追加が起きやすい)
    • 観測メモ: 障害時に切り分けが難しい/再送運用が未定、が主要リスク
  2. 手当(設計の方向性)
    • 「割り当ての合否」と「通知の合否」を分離する(仕様の時点で混同しない)
    • ユースケースは外部メール送信を直接呼ばず、通知I/F(port)へ 通知要求 を渡す
    • 通知失敗時の期待(業務継続/検知/再送)を境界側の責務として固定する(任意: Appendix B(B-16) / 記入例: Appendix D(D-24)
  3. テスト配分(B-8)
    • 単体(domain): 割り当て可否(権限/状態)や通知条件のルールを厚く守る
    • 統合(境界): API+DB の永続化と、通知I/Fの「失敗時の扱い(例: 再送起点の記録)」を守る
    • E2E(導線): 管理者が割り当てでき、UI 表示と状態が更新されることを守る(通知到達そのものは外部要因のため分離する)

ポイント: D(距離)が大きいほど「契約の明文化」と「観測点の設計」が支配的になり、テストは外部サービスの到達性ではなく 自系の契約 に寄せます。

演習(最小1個)

「依存関係トップ 10」を列挙し、S/D/V を半定量で採点してください。

  • 採点表は Appendix B-4 を利用してください
  • Appendix B: テンプレ集(B-4. S/D/V 採点表)
  • 記入例: Appendix D: 記入例
  • 結果から「今すぐ手当する 1 つ」を選び、以下を 3〜5 行で説明してください
    • 何が悪いか(S/D/V のどこが効いているか)
    • どんな手当をするか(分離/統合/契約/テスト投資など)
    • 何をトレードオフとして受け入れるか(コスト/運用/速度)

よくある失敗

  • D が小さい(同一モジュール内)にもかかわらず、境界を増やして学習コストを上げる
  • V が高い領域に「正しい抽象」を求め、結果として変更が困難になる
  • S が強い領域を無理に分割し、同時変更が増える
  • 点数だけを付けて根拠が残らず、後から判断が再現できない
  • D(距離)を技術要因だけで扱い、組織・責任分界の距離を無視する

チェックリスト

  • 依存関係の優先順位が明確(トップ 10 など)
  • S/D/V を使って説明できる(感想ではなく観測)
  • 「分ける/まとめる」の判断が、運用・テスト方針に接続している
  • 採点の根拠(観測)が短文で残っている