07. 進化条件(ADRと境界の強化タイミング)

目的

  • 「いつ境界を強めるか」を、観測可能な条件(S/D/V の悪化、運用要件)で判断できるようにする
  • ADR を最小限に運用し、意思決定の再現性と合意形成の速度を上げる

得られる判断能力

  • 「最初から大掛かりにしない」ための進化条件(トリガー)を定義できる
  • 進化の根拠を S/D/V と運用要件で説明できる(気分で境界を増やさない)
  • ADR を最小運用し、意思決定を再利用できる形で残せる

前提/用語

  • ADR: Architecture Decision Record(意思決定の記録)
  • 進化条件: 現状の設計が限界に近づいた兆候(変更の痛み、障害、運用負債)

要点

  • 境界の強化は、コストに見合うトリガーが発生したときに行う(先回りしない)
  • S/D/V の悪化は「結合の偏り」の兆候。トップ依存の再採点で把握する
  • ADR は長文ではなく、Context / Decision / Consequences の最小記録でよい

進化条件(トリガー)の見つけ方

「進化」は理想論ではなく、観測できる痛みから始めます。小規模で有効な観測の例です。

  • 変更の痛み(主に S):
    • 片方を直すと別の箇所が壊れる(暗黙の契約がある)
    • 変更が常に同じ PR に乗る(同時変更が常態化)
    • リリース前に統合不具合が繰り返し見つかる(境界の検証不足)
  • 距離の痛み(主に D):
    • UI → API → DB のような遠い経路で障害が起きると切り分けに時間がかかる
    • 外部 I/F(通知、決済、認証など)で失敗・遅延・仕様差分が顕在化する
    • デプロイ単位/責任分界が分かれ、合意と調整がボトルネックになる
  • 変動性の痛み(主に V):
    • 例外系や分岐が増え、テストが追随できない(仕様が固まっていない)
    • 同じルールが複数箇所に重複し、変更漏れが起きる
    • 「正しい抽象」を求めて設計が停滞する(固定化し過ぎの兆候)
  • 運用要件の顕在化:
    • 障害対応が属人化している(復旧手順が暗黙)
    • ログ/監視が不足しており、原因が追えない
    • 手動リカバリが増え、継続運用コストが上がっている

進化条件は「気分」になりやすいため、Appendix B の Change Drivers テンプレで観測と根拠を先に揃えると再現性が上がります。

トリガー別の最小手当(境界/契約/テスト/運用)

境界強化は「分離する」だけではありません。トリガーに応じて、まず最小コストの手当から始めます。

トリガー(観測) 効いている軸 まずやる手当(最小) 追加投資(必要なら)
UI/API/DB の不具合が多い、切り分けに時間がかかる D 入出力・エラー形式を明文化し、統合テストで固定する(章 05-06) 契約テスト、ログ/監視、アラート
外部 I/F の失敗が業務影響を持つ D 失敗時の期待(業務継続/再送/検知)を受け入れ条件に入れる adapter 強化(タイムアウト/リトライ)、アウトボックス等
変更が常に同じ PR に乗る、同時変更が前提 S 無理に分離せず、一体として扱う粒度を明確化する 共有ロジックの集約、責務境界の整理
ルールが重複し、変更漏れが起きる V ルール(知識)を domain に寄せ、単体テストで守る UI/API の重複排除、ガードレール整備
例外系が増え、仕様が曖昧なまま実装される V 受け入れ条件(例外/失敗時)を先に固定する(Appendix B-3) ADR(重大な分岐のみ)、運用手順の明文化

「手当の効果が期待できるか」を判断するために、トリガーは 1〜2 週間単位で見直せる粒度にします(大規模な再設計を前提にしない)。

よくある進化パターン(トリガー→最小手当→次の投資)

進化条件を「あるある」パターンとして整理しておくと、同じ議論を繰り返さずに済みます。以下はランニング例(タスク管理)で頻出する進化パターンです。

1) 通知が“機能”から“運用”へ成長する(通知チャネル/再送/テンプレ)

  • トリガー(観測):
    • 通知の失敗が業務影響を持つ(問い合わせ/取りこぼしが増える)
    • 通知条件が増え、例外系(送達不可、遅延)が顕在化する
    • D(距離)が大きい外部I/Fのため、切り分けと再送運用がボトルネックになる
  • 最小手当:
    • 仕様(Behavior)で「業務継続/検知/再送」の期待を固定する(曖昧にしない)
    • 通知は adapter 境界の責務として分離し、ユースケースは通知要求(契約)だけを扱う
    • 観測点(ログ/メトリクス/再送起点)を設計し、E2E は到達性ではなく自系の契約を検証する
  • 次の投資(必要になったら):
    • 再送キュー、アウトボックス、テンプレ管理、通知チャネルの追加(メール→別チャネル)
    • 失敗時の判断(停止/継続)を ADR として固定する

2) 権限が増殖する(ロール拡張/例外追加/UIとAPIの不整合)

  • トリガー(観測):
    • UI と API で権限判定がズレる(見えるができない/できるが見えない)
    • 役割が増え、条件分岐が章01の例外系カタログで埋まる
    • V(変動性)が上がり、同時変更(S)も増える
  • 最小手当:
    • 権限ルール(判定)を domain 側に寄せ、UI/API は判定結果を利用する
    • 例外系(403404 の扱い、監査ログ)を仕様として固定し、統合テストで守る
    • ルールの表(ロール×操作×対象)を最小で作り、変更時の影響範囲を可視化する
  • 次の投資(必要になったら):
    • ポリシーの外部化(設定化/ポリシーエンジン)、監査要件の強化(閲覧権限/保持期間)
    • “誰が何をできるか”の前提が変わる場合は ADR 対象にする

3) 監査/整合性が要件化する(履歴/同時更新/冪等性)

  • トリガー(観測):
    • 「いつ誰が何をしたか」が追えず、運用復旧が属人化する
    • 同時更新や二重実行が増え、データの食い違いが顕在化する
    • 障害時の説明責任(監査)が求められる
  • 最小手当:
    • 監査ログの“最小スキーマ”(actor/対象/時刻/結果/相関ID)を決め、成功/失敗を記録する
    • 競合(409 等)と冪等性(二重送信)の振る舞いを仕様で固定し、統合テストで守る
    • DB 制約(ユニーク、外部キー等)を「仕様の裏付け」として使い、破綻を早期に検知する
  • 次の投資(必要になったら):
    • 相関IDの全経路伝播、イベントの永続化、非同期処理の整合性(アウトボックス等)
    • データ整合性の戦略が変わる場合は ADR 対象にする

補助テンプレ:

例(ランニング例)

タスク管理の進化条件を例にします。

  • 通知要件が増え、メール送信が失敗するケースが顕在化した
    • 失敗時の扱い(リトライ、監視、手動復旧)が要件化される
    • D(距離)が大きい外部I/Fのため、境界(adapter)の責務が増える
    • 判断: ユースケースから直接送らず、「通知要求の発行」と「送信処理」を分離する価値が出る
  • 権限モデルが拡張され、UI と API の条件分岐が急増した
    • V(変動性)が上がり、知識の共有が拡散している兆候
    • 判断: 権限判定を domain 側へ寄せ、UI/API は同一の判定結果を利用する

ADR の最小運用(例)

  • ADR は「重大な分岐」だけに絞る(例: 通知方式、権限モデル、データ整合性の戦略)
  • 1 ADR は 1 決定。議事録化しない
  • 見直し条件(いつ再評価するか)を必ず書く

ADR を書くタイミング(実務の目安)

ADR は「後から取り返しがつきにくい」決定に絞ると運用しやすいです。

  • ADR を書く(書く価値がある):
    • 失敗時の期待が変わる(例: 通知失敗で業務を止める/止めない)
    • データ整合性や監査要件が絡む(例: いつ・誰が・何をしたか)
    • 境界の責務が増える(外部 I/F、認可、非同期化)
    • チーム/運用の前提が変わる(オンコール、SLO、別担当)
  • ADR を書かない(テンプレで十分なことが多い):
    • 実装詳細の選択(ライブラリ差し替え等)で、後から容易に戻せる
    • 影響範囲が狭く、障害時の復旧が単純

ADR を書く前に、Change Drivers(Appendix B-6)で「なぜ今変えるか」を整理しておくと、Context が短くなり議論が収束しやすくなります。

演習(最小1個)

ランニング例で「境界を強めるべき」状況を 1 つ選び、次の順で 1 セット作成してください。

  1. Change Drivers(なぜ今変えるか)
  2. ADR(何を決めたか)

例(題材):

  • 状況: 通知(メール)の失敗が業務影響を持ち始めた
  • 選択肢: 直接送信 / 通知要求の発行 + 非同期送信 / リトライキュー導入 など
  • 目的: 失敗時の取り扱いを明確にし、テスト容易性と運用性を確保する

よくある失敗

  • ADR が議事録化し、意思決定の要点が埋もれる
  • 進化の根拠が「気分」になり、境界強化が目的化する
  • 変更の痛みを可視化しないまま、部分最適なリファクタリングを繰り返す

チェックリスト

  • 境界強化のトリガーが明確(S/D/V、運用要件、変更頻度)
  • Change Drivers(なぜ今変えるか)が短文で整理されている
  • ADR の粒度が一定で、検索・再利用できる
  • 設計変更がテスト戦略(配分)に反映されている
  • 見直し条件(いつ再評価するか)が合意されている