はじめに
「なぜあの設計判断をしたのか、半年後に誰も説明できない」 ― チーム開発をしていると、この状況に一度は遭遇するのではないでしょうか。
たとえば、サービス間通信にRESTではなくgRPCを選んだ理由。
当時の担当者はもう異動していて、Slackのログを漁っても断片的な議論しか見つからない。
新しく入ったメンバーが「RESTのほうがシンプルでいいのでは?」と提案し、変更した結果、レイテンシが悪化して上流システムにタイムアウトが連鎖する。
ありがちな話です。
この問題の本質は、設計の「良し悪し」ではありません。判断の根拠が記録されていないこと、そしてリスクが個人の頭の中に閉じていることです。
この記事では、その解決策となる2つの手法を紹介します。
TL;DR
- 設計判断には3つのアンチパターンがある: 決められない、蒸し返される、埋もれる
- ADR(Architectural Decision Record)は、設計判断をTitle / Status / Context / Decision / Consequences / Compliance / Notesの7セクションで記録する文書
- ADRの最大の価値は「何を決めたか」ではなく「なぜそう決めたか」を残すこと
- リスクは「影響度 x 発生可能性」で数値化すると、主観を排除して議論できる
- リスクストーミングは「個人で特定 → チームで合意 → 軽減策を検討」の3フェーズで進める共同ワークショップ
設計判断を台無しにする3つのアンチパターン
冒頭で挙げた「判断の根拠が消える」「リスクが個人に閉じる」といった問題は、決定プロセスに潜むアンチパターンから生じます。
アンチパターンとは、良さそうに見えて実は悪い結果を招くやり方のことです。よく見られる3つのパターンを紹介します。
[1. 決められない] → [2. 蒸し返される] → [3. 埋もれる]
Covering Your Groundhog Day Email-Driven
Assets Architecture
順番に見ていきましょう。
「怖くて決められない」― Covering Your Assets
間違った判断をすることへの恐れから、決定を回避したり先送りにしたりするパターンです。
「もっと情報を集めてから」と言い続けて、永遠に分析し続ける**Analysis Paralysis(分析麻痺)**に陥ります。
Analysis Paralysis(分析麻痺)とは、選択肢の分析に時間をかけすぎて、結局何も決められなくなる状態のことです。
このアンチパターンには2つの対策があります。
対策1: 最後の責任ある瞬間(Last Responsible Moment)を見極める
判断のタイミングには、「早すぎるリスク」と「遅すぎるコスト」の2つの力が働いています。
リスク(高) コスト(高)
| \ / |
| \ / |
| \ / |
| \ / |
| \ / |
| \ / |
| \ / |
| ★ ← ここで決める |
| / \ |
リスク(低) コスト(低)
+---------+---+---+---------+
早い 遅い
← 判断のタイミング →
早すぎれば情報不足でリスクが高く、遅すぎれば開発が止まりコストが増大します。「先延ばしのコストがリスクを上回ったら決める」というのが判断基準です。
対策2: 開発チームとの協働
一人で全てを見通すことは不可能です。開発チームと密に連携することで、実装上の制約を早い段階で発見できます。
たとえば、アーキテクトが「全サービスにレプリケーションキャッシュを導入する」と決定したとします。
レプリケーションキャッシュとは、データのコピーを各サービスのメモリ上に保持する仕組みです。
しかし開発チームが実装を始めると、一部のサービスはスケーラビリティ要件の都合で利用可能なメモリが限られており、キャッシュを載せきれないことが判明しました。
チームと密に連携していたからこそ、早い段階でこの問題に気づき、方針を修正できたわけです。
「同じ議論が何度も繰り返される」
決定はしたものの、「なぜそう決めたか」の正当化が不十分で、何度も同じ議論が蒸し返されるパターンです。
このアンチパターンの原因は、技術的な正当化だけで、ビジネス上の正当化が欠けていることにあります。
たとえば、「モノリスを分割してマイクロサービスにする」と決定したとします。
- 技術的な正当化: 「デプロイを独立させたい」「各サービスのリソース使用量を最適化したい」 ← これだけでは不十分
- ビジネス側の問い: 「それで何が良くなるの?リファクタリングにお金をかける意味は?」
- 必要なもの: 「新機能のリリースが速くなり、Time to Marketが改善する」というビジネス視点の正当化
ビジネス側の正当化には、よく使われる4つの軸があります。
| 軸 | 例 |
|---|---|
| コスト削減 | インフラ費用の削減、開発工数の削減 |
| Time to Market | 新機能をより速くリリースできる |
| ユーザー満足度 | レスポンスの改善、ダウンタイムの削減 |
| 戦略的ポジショニング | 将来の拡張性、競合優位性の確保 |
ビジネスステークホルダーが何を重視しているかを見極めることが大切です。
コスト削減だけを理由にしても、ステークホルダーがTime to Marketを重視しているなら響きません。
ビジネス視点で正当化できるかどうかは、その決定が本当に必要かを見極めるリトマス試験にもなります。
「決定がどこかに埋もれる」― Email-Driven Architecture
決定を下し、正当化もした。しかし、メールの本文にそれを書いて送って終わり ― これがEmail-Driven Architectureです。
メールで決定を共有すると何が起きるでしょうか。
- 各メールがそれぞれコピーとなり、 Single Source of Truth(唯一の情報源) がなくなる
- メールには決定の全ての詳細が書かれていないことが多く、正当化が抜け落ちて再びGroundhog Dayが発生する
- 決定が後から更新されても、古いメールを持っている人は最新の情報に気づかない
対策はシンプルです。メールには決定の文脈と影響範囲だけを書き、詳細はリンクで一元管理された場所に誘導します。
「サービス間通信に関する重要な決定をしました。あなたに直接影響があります。詳細はこちら → [リンク]」
「あなたに直接影響があります」の一文がポイントです。この決定が直接影響しない人にはそもそも通知しない、という判断基準にもなります。
ここまでのまとめ
3つのアンチパターンは互いに関連しており、全てを克服して初めて設計判断が組織の資産になります。では、そもそもどのような判断を記録すべきなのでしょうか。
何をアーキテクチャ決定と呼ぶのか ― 判断すべき範囲を見極める
設計判断を記録する仕組みを導入しても、些細な技術選定まで全て記録していたら形骸化します。
「特定の技術を選ぶこと = アーキテクチャ決定ではない」と思われがちですが、これは必ずしも正しくありません。
たとえば、レイテンシ削減のためにgRPCを選ぶ判断は、パフォーマンスというアーキテクチャ特性に直接影響するため、立派なアーキテクチャ決定です。
ソフトウェアアーキテクチャの分野では、 Architecturally Significant(アーキテクチャ上重要な) という判断基準が知られています。
以下の5つの観点のいずれかに影響を与える決定をアーキテクチャ決定と定義する考え方です。
アーキテクチャ決定の5つの判断基準
┌──────────────────────────────────────┐
│ │
│ 1. 構造 │
│ アーキテクチャパターンや │
│ スタイルに影響する決定 │
│ │
│ 2. 非機能特性 │
│ パフォーマンス、スケーラビリティ │
│ などに影響する技術選定 │
│ │
│ 3. 依存関係 │
│ コンポーネント/サービス間の │
│ 結合に関する決定 │
│ │
│ 4. インターフェース │
│ アクセス方法、契約、 │
│ バージョニング戦略 │
│ │
│ 5. 構築技法 │
│ プラットフォーム、フレームワーク、 │
│ ツール、プロセスの選定 │
│ │
└──────────────────────────────────────┘
いくつか具体例を挙げます。
- 構造: マイクロサービス間でコードを共有する決定は、サービスの境界(Bounded Context)に影響するため、アーキテクチャ決定になる
- 非機能特性: 高可用性のためにデータベースのレプリケーションを導入する判断は、可用性というアーキテクチャ特性に影響するため、アーキテクチャ決定になる
- 依存関係: サービス間の通信方式を同期(REST)にするか非同期(メッセージング)にするかは、結合度に直接影響する
- インターフェース: APIのバージョニング戦略や、API Gatewayの導入判断は、システムの利用者に影響を与える
- 構築技法: 特定のフレームワークやCIツールの選定は、アーキテクチャに間接的に影響することがある
逆に、これらに該当しない純粋な実装の詳細(変数の命名規則、特定のライブラリの使い方など)は、開発チームの裁量に任せるのが一般的です。
ADR ― 設計判断を構造的に記録する
アーキテクチャ決定の範囲がわかったところで、それをどう記録すればチームの資産になるのか。
ADR(Architectural Decision Record)はそのためのシンプルで実践的なフォーマットです。
ADRとは何か
ADRは、1つの設計判断を1~2ページの短いテキストで記録する文書です。
2011年にブログ記事で提唱されました。
2016年にはThoughtWorks Technology Radarが「Adopt(積極的に採用すべき)」に推奨したことで、広く知られるようになりました。
Markdown、AsciiDoc、Wikiページなど、チームに合った形式で書けます。
管理用のCLIツール(adr-toolsなど)も存在しますが、形式やツールよりも 「書く習慣」をチームに定着させること のほうが重要です。
ADRの構造: 7つのセクション
ADRは基本の5セクション(Title / Status / Context / Decision / Consequences)に、ComplianceとNotesを加えた7セクションで構成されます。
1つずつ見ていきましょう。
Title
連番と短い説明文で構成します。
- OrderサービスとPaymentサービス間の非同期メッセージング採用
曖昧さがなく、何についての決定かが一目でわかるタイトルを付けます。
Status
ADRのライフサイクルを表す3つの状態です。
| 状態 | 意味 |
|---|---|
| Proposed | 上位の承認者やアーキテクチャレビューボードの承認待ち |
| Accepted | 承認済みで、実装可能な状態 |
| Superseded | 別の新しいADRに置き換えられた状態 |
Supersededの仕組みは特に強力です。古いADRと新しいADRに相互リンクを張ることで、決定の変遷を追跡可能にします。
ADR 42. OrderサービスとPaymentサービス間の非同期メッセージング採用
Status: Superseded by 68ADR 68. OrderサービスとPaymentサービス間のREST採用
Status: Accepted, supersedes 42
こうしておけば、ADR 68を読んだ人が「メッセージングは検討しなかったの?」と疑問に思っても、ADR 42を辿れば過去の経緯がわかります。
承認基準をあらかじめ設計しておく: 全てのADRが上位承認を必要とするわけではありません。コスト・チーム横断的影響・セキュリティの3軸で「自分で承認できるか、上位承認が必要か」の基準を事前に決めておくと、承認プロセスがスムーズになります。たとえば「コストが$5,000を超える場合はアーキテクチャレビューボードの承認が必要」のように具体的な閾値を設定します。
Context
「何が起きていて、なぜ判断が必要なのか」を記述するセクションです。
OrderサービスはPaymentサービスに注文の支払い情報を渡す必要がある。これはRESTまたは非同期メッセージングで実現できる。
状況と代替案を簡潔に記載します。詳細な比較分析が必要なら、別途Alternativesセクションを追加することもできます。
Contextを書くこと自体がアーキテクチャのドキュメント化にもなる、という点は見逃せません。
特定のサービス間の関係やデータの流れが、自然に記録されていきます。
Decision
「何をするか」と「なぜそうするか」を記述する、ADRの中で最も重要なセクションです。
書き方には1つポイントがあります。
「We will use...」のように断定的な能動態で書くことです。
「...would be the best choice」のような曖昧な表現だと、決定なのか意見なのかが不明確になります。
We will use asynchronous messaging between the Order and Payment services.
そして、Decisionセクションの真価は「何を」ではなく「なぜ」にあります。
冒頭のgRPCの例で考えてみましょう。
gRPCを選んだ理由はレイテンシ削減のためであり、結合度が上がるトレードオフを受け入れた上での判断でした。
その理由がADRに記録されていれば、後任のアーキテクトが安易にRESTに変更してしまう事故を防げたはずです。
Consequences
決定がもたらす影響を、良い面と悪い面の両方から記述します。ここはトレードオフ分析を記録する場所です。
たとえば、Webサイトへのレビュー投稿に非同期メッセージングを採用する決定を考えてみます。
ここではfire-and-forget方式(リクエストを送って完了を待たない方式)を使います。
- 良い面: レスポンスが3,100msから25msに改善。ユーザーはレビューの実際の投稿完了を待つ必要がない
- 悪い面: エラーハンドリングが複雑化する。たとえば不適切な言葉を含むレビューの対処が非同期になる
「エラーハンドリングの複雑化は問題では?」という反論が予想されます。
しかし、「レスポンス改善を優先し、複雑化は受け入れる」とステークホルダーと合意した経緯をConsequencesに残しておけば、同じ議論の繰り返しを防げます。
Compliance
この決定をどう遵守するかを記述します。
手動のコードレビューで確認するのか、自動化されたフィットネス関数で検証するのかを明記します。
フィットネス関数とは、アーキテクチャのルールをテストコードで検証する仕組みです。
たとえば「共有オブジェクトはShared Servicesレイヤに配置する」という決定なら、ArchUnit(Java)やNetArchTest(C#)で依存関係の方向を検証できます。
Notes
著者、承認日、承認者、最終更新日などのメタデータを記録するセクションです。
GitでADRを管理している場合でも、リポジトリのコミット履歴だけでは追えない情報(誰が承認したか、など)を補完するために有用です。
ADRの具体例: オークションシステムの入札キュー
7つのセクションを理解したところで、実際のADRがどのような文書になるか、具体例で確認しましょう。
題材はGGG(Going, Going, Gone)というオークションシステムです。
このシステムでは、Bid Capture(入札受付)サービスが受け取った入札を、2つのサービスに転送する必要があります。
転送先はBid Streamer(入札ストリーミング)とBidder Tracker(入札者追跡)です。
ここでは入札データの転送方式として、トピック(pub/sub: 1つのメッセージを複数の購読者に配信する方式)、個別キュー(point-to-point: 1つのキューに1つの消費者が対応する方式)、RESTの3つが候補に挙がっています。
ADR 76. Bid StreamerとBidder Trackerサービスへの個別キュー採用
STATUS
AcceptedCONTEXT
Bid Captureサービスは、入札を受け取った後、Bid StreamerサービスとBidder Trackerサービスにその入札を転送する必要がある。これは単一のトピック(pub/sub)、個別キュー(point-to-point)、またはREST APIで実現できる。DECISION
個別キューをBid StreamerとBidder Trackerサービスそれぞれに用意する。理由は以下の4点:
- Bid Captureは応答を必要としない(片方向通信のみ)
- Bid Streamerは入札を受付順で受け取る必要がある。FIFOキューを使えば順序が自動保証される
- Bid Streamerは同額の最初の入札だけが必要だが、Bidder Trackerは全ての入札が必要。トピック(pub/sub)だとBid Streamer側でフィルタリングと状態管理が必要になる
- Bidder TrackerはDB書き込みのため処理が遅く、バックプレッシャー(流量制御)が必要。専用キューがその制御点になる
CONSEQUENCES
- キューのクラスタリングと高可用性が必要になる
- Bid Captureサービスが同じ情報を複数のキューに送信する必要がある
- APIレイヤのセキュリティチェックをバイパスする(ARBレビューで許容と判断済み)
COMPLIANCE
定期的な手動コードレビューで、非同期メッセージングの使用を検証する。NOTES
Author: Suzuki Taro
Approved: ARB Meeting Members, 14 JAN 2025
Last Updated: 14 JAN 2025
1つの判断に対して「なぜ」が複数の観点から記録されている点がポイントです。
後からこのADRを読んだ人は、なぜトピックでもRESTでもなく個別キューなのかを明確に理解できます。
ADRの保管と運用
ADRをどこに保管するかも重要な判断です。
ソースコードと同じGitリポジトリに置く方法は、小規模チームには手軽で有効です。しかし、大規模組織では2つの問題があります。
- リポジトリにアクセスできない人(ビジネスステークホルダーなど)が決定を参照できない
- アプリケーション横断的な決定(サービス間連携やエンタープライズレベルの方針)の置き場がない
そのため、大規模な組織では専用のADRリポジトリまたはWikiを用意することが推奨されています。ディレクトリ構造の例は以下の通りです。
adr/
├── application/
│ ├── common/ ... 全アプリ共通の決定
│ ├── order-system/ ... 注文システム固有の決定
│ └── payment-system/ ... 決済システム固有の決定
├── integration/ ... システム間連携の決定
└── enterprise/ ... 組織全体の決定
この構造はあくまで一例です。組織の状況に合った名前と構造を選べばよいのですが、チーム間で一貫していることが大切です。
ADRの応用
ADRには、設計判断の記録以外にも活用方法があります。
ドキュメントとしてのADR
Context + Decision + Consequencesの組み合わせは、そのままアーキテクチャドキュメントとして機能します。
「なぜパフォーマンスよりスケーラビリティを優先したか」のような判断根拠は、構成図だけでは伝わらない情報です。
ADRを積み重ねていくことで、アーキテクチャの「なぜ」が自然に蓄積されていきます。
標準規約としてのADR
社内標準をADRの形式で記述すると、Contextで「なぜこの標準が必要か」を書く必要が生まれます。
正当化できない標準はそもそも不要なのでは、という健全なフィルターが働きます。
開発者にとっても、「なぜ」が明記された標準は納得して受け入れやすくなります。
既存システムへの適用
ADRは新規プロジェクト限定ではありません。
既存システムの重要な設計判断について遡ってADRを書くことで、その判断が今も妥当かを検証する機会になります。
当時の担当者がもういなくても、代替案とトレードオフを改めて分析し、ADRとして残す価値は十分にあります。
コラム: 生成AIはアーキテクチャ決定を代替できるか
LLM(大規模言語モデル)は「最も確率の高い回答」を返しますが、アーキテクチャ決定は「特定の文脈におけるトレードオフ分析」です。ビジネスの関心事(Time to Market vs コスト削減など)をアーキテクチャ特性に翻訳し、その上でトレードオフを判断するプロセスは、文脈への依存度が高く、現時点のAIには難しい領域です。
有効な使い方としては、トレードオフの洗い出し補助があります。「この決定で見落としているトレードオフはないか」をAIに壁打ちすることで、抜け漏れを減らせます。ただし、最終的な判断は人間が行うものです。言い換えれば、AIには知識(knowledge)はあるが、判断に必要な知恵(wisdom)はまだありません。
リスクを「見える化」する ― リスクマトリックスとリスクアセスメント
設計判断を記録する方法はわかりました。
しかし、そもそも「どこにリスクがあるか」を正しく認識できなければ、適切な判断はできません。
ここからは、リスクを主観ではなく客観的に評価する方法を見ていきます。
リスクマトリックス: 主観を数値に変える
アーキテクチャには常にリスクが伴います。
運用面では可用性、スケーラビリティ、データ整合性。構造面ではコンポーネント間の静的な結合。
こうしたリスクの評価は主観的になりがちで、「高リスクだと思う」「いや中リスクでしょ」という意見の対立が起きます。
リスクマトリックスは、 影響度(Impact)x 発生可能性(Likelihood) の2軸でリスクを数値化する手法です。
発生可能性
Low(1) Medium(2) High(3)
┌─────────┬──────────┬─────────┐
High(3) │ 3(中) │ 6(高) │ 9(高) │
影 ├─────────┼──────────┼─────────┤
響 Med(2) │ 2(低) │ 4(中) │ 6(高) │
度 ├─────────┼──────────┼─────────┤
Low(1) │ 1(低) │ 2(低) │ 3(中) │
└─────────┴──────────┴─────────┘
1-2: 低リスク 3-4: 中リスク 6-9: 高リスク
リスクを評価するときは、まず影響度を評価し、次に発生可能性を評価する順番で進めます。発生可能性から考えると「滅多に起きないから大丈夫」というバイアスがかかり、影響度の評価が甘くなりがちだからです。発生可能性が不明な場合は、確認が取れるまで高(3)を仮置きしてください。
具体例で使い方を確認します。アプリケーションの中央データベースの可用性リスクを評価する場合を考えましょう。
- 影響度: DBが落ちたらシステム全体に影響する → 高(3)
- 発生可能性: 高可用性のクラスタ構成で冗長化されている → 低(1)
- リスク値: 3 x 1 = 3(中リスク)
このように数値化することで、「危なそう」という感覚的な議論が「影響度は高いが発生可能性は低いので中リスク」という客観的な議論に変わります。
リスクアセスメント: システム全体を俯瞰する
リスクマトリックスを個別のリスク評価に使ったら、次はシステム全体のリスクを一覧化します。これがリスクアセスメントです。
リスクアセスメントは、行にリスク基準(評価したいアーキテクチャ特性)、列に文脈(ドメイン領域)を配置した表です。
各セルには、リスクマトリックスで算出したリスク値(影響度 x 発生可能性)が入ります。
以下の例では、可用性、弾力性(Elasticity)、セキュリティなどの特性を評価しています。
顧客登録 カタログ 注文処理 配送 累積
┌────────┬────────┬────────┬───────┬────┐
可用性 │ 2(低) │ 3(中) │ 2(低) │ 3(中) │ 10 │
├────────┼────────┼────────┼───────┼────┤
弾力性 │ 3(中) │ 6(高) │ 1(低) │ 3(中) │ 13 │
├────────┼────────┼────────┼───────┼────┤
セキュリティ │ 6(高) │ 3(中) │ 2(低) │ 3(中) │ 14 │
├────────┼────────┼────────┼───────┼────┤
データ整合性 │ 6(高) │ 6(高) │ 3(中) │ 2(低) │ 17 │ ← 最高
├────────┼────────┼────────┼───────┼────┤
パフォーマンス│ 3(中) │ 6(高) │ 3(中) │ 1(低) │ 13 │
├────────┼────────┼────────┼───────┼────┤
累積 │ 20 │ 24 │ 11 │ 12 │ │
└────────┴────────┴────────┴───────┴────┘
↑
最もリスクが高い
ドメイン
弾力性(Elasticity)は、急激なアクセス増加に短時間でスケールアウトする能力です。長期的な成長に対応するスケーラビリティとは異なります。
この表から2つの視点で優先度を判断できます。
- 行の累積: データ整合性(17)が最もリスクの高い特性 → データ整合性の改善が優先度の高い候補になる
- 列の累積: カタログ(24)が最もリスクの高いドメイン → カタログ領域にリソースを重点配分する判断材料になる
リスク基準には「そのシステムにとって重要なアーキテクチャ特性」を選びます。パフォーマンスが重要でないシステムでパフォーマンスリスクを分析しても意味がありません。また、文脈はサービス単位だと細かすぎるため、ドメイン単位が適切です。
フィルタリングで報告を効果的にする
ステークホルダーへの報告時は、低リスク・中リスクの領域をフィルタリングし、高リスク領域のみを表示すると、メッセージのシグナルが強くなります。
全てのセルが埋まった表を見せるよりも、高リスクのセルだけが浮かび上がる表のほうが、何に注力すべきかが一目瞭然です。
リスクの方向性を追跡する
リスクアセスメントは時点のスナップショットです。
リスクが改善しているのか悪化しているのかを追跡するために、方向性を示す記号を加えることができます。
| 記号 | 意味 |
|---|---|
| ▲(上向き三角) | リスクが悪化している |
| ▼(下向き三角) | リスクが改善している |
| ●(丸) | 変化なし |
フィットネス関数で定期的に計測することで、この方向性を客観的に判断できます。
リスクストーミング ― チームでリスクを洗い出す
リスクの数値化方法はわかりました。
しかし、一人のアーキテクトが全てのリスクを見抜くことはできません。全ての技術領域に精通している人もいません。
アーキテクチャ図を囲んでチーム全員でリスクを洗い出すワークショップ ― それがリスクストーミングです。
リスクストーミングとは
リスクストーミングは、アーキテクト、シニア開発者、テックリードが参加する共同ワークショップです。
開発者を巻き込むことには2つの利点があります。
実装の視点からリスクを発見できることと、開発者自身のアーキテクチャへの理解が深まることです。
リスクストーミングは3つのフェーズで進みます。
リスクストーミングは、できるだけ1つの観点(例: 可用性、セキュリティ)に絞って実施するのが効果的です。複数の観点を同時に扱うと、参加者の注意が分散し、リスクの議論が混乱しやすくなります。
フェーズ1: 個人でリスクを特定する
ファシリテーター(主催者のアーキテクト)が、事前にアーキテクチャ図と分析対象(「今回は可用性リスクを評価する」など)を参加者に共有します。
各参加者は一人でリスクマトリックスを使い、アーキテクチャの各部分にリスクレベルを評価します。
評価結果は色付きの付箋に書きます(緑: 低リスク、黄: 中リスク、赤: 高リスク)。
なぜ個人フェーズが必要なのでしょうか。
最初からグループで議論すると、声の大きい人や権威のある人の意見に引きずられてしまいます。
まず各自がバイアスのない独自の評価を行うことで、多様な視点を確保するためです。
フェーズ2: チームで合意を形成する
大きなアーキテクチャ図を壁に貼り(リモートならMiroやFigJamなどのオンラインホワイトボードに表示し)、全員が付箋を貼り出します。
全員の評価が一致している箇所は議論不要です。意見が分かれた箇所を中心に議論します。具体的なケースを3つ紹介します。
ケース1: ロードバランサー
2人が中リスク(3)、1人が高リスク(6)と評価しました。
高リスクと評価した人は「ロードバランサーが落ちたらシステム全体にアクセスできなくなる」と主張。
影響度は確かに高いのですが、クラスタ構成により発生可能性が低いことを他の2人が指摘し、最終的に 中リスク(3) に合意しました。
ケース2: Push Expansion Server
1人だけが高リスク(9)と評価し、他の参加者は何もリスクを感じていませんでした。
その人は、過去に類似の負荷環境でPush Expansion Serverがクラッシュした経験を持っていたのです。
この参加者がいなければ、本番稼働後まで気づかなかったリスクでした。
ケース3: Redisキャッシュ
開発者の1人が高リスク(9)と評価しました。理由を聞くと「Redisキャッシュって何ですか?」。
このケースは重要な原則を示しています。
未知の技術は自動的に最高リスク(9)に設定するのが原則です。リスクマトリックスで評価しようがないからです。
この事実は、技術の変更を検討するか、トレーニングコストをかけてチームのスキルを引き上げるかの判断材料になります。
3つ目のケースは、開発者をリスクストーミングに参加させることの価値を端的に示しています。
合意が取れたら、全ての付箋を統合してこのフェーズは終了です。
フェーズ3: リスクを軽減する
合意したリスクに対して、軽減策を共同で検討します。
軽減策には当然コストが伴うため、ビジネスステークホルダーを巻き込んで「コスト vs リスク」を判断することが重要です。
たとえば、データベースの可用性が中リスク(4)と評価された場合を考えます。
| 案 | 内容 | コスト | 結果 |
|---|---|---|---|
| 案1 | クラスタ化 + 物理DB分割 | $50,000 | ビジネスオーナーが「コストに見合わない」と却下 |
| 案2 | ドメイン単位でDBを2つに分割 | $16,000 | ステークホルダーが合意し採用 |
リスクストーミングは単にアーキテクチャを改善するだけでなく、アーキテクトとビジネスステークホルダーの間の交渉の場にもなります。
実践例: ECプラットフォームのカスタマーサポートシステムのリスクストーミング
リスクストーミングがアーキテクチャをどのように改善するのか、ECプラットフォームのカスタマーサポートシステムの事例を通して見てみましょう。
このシステムは、CSオペレーターが顧客の問い合わせに対応するカスタマーサポートの支援システムです。主な要件は以下の通りです。
- サードパーティのAI問い合わせ分類エンジンが、オペレーターと顧客を質問形式で案内する(処理能力は500リクエスト/秒)
- 顧客はカスタマーサポートに電話するか、セルフサービスのチャットボットを利用できる
- 250人の同時接続オペレーターと、数十万の同時接続セルフサービス利用者をサポート
- 個人情報保護法準拠が必須。顧客の個人情報(注文履歴・住所・連絡先など)にアクセスできるのはオペレーターのみ
- 年末商戦や大型セール時にアクセスが急増する
担当アーキテクトは、3つのWeb UI、API Gateway、4つの主要サービスからなるアーキテクチャを設計しました。
初期の構成は以下の通りです(リスクストーミングの結果、この構成は大きく変わります)。
セルフサービスUI オペレーターUI 管理者UI
| | |
+-------+-------+------------+
|
API Gateway (CSシステム)
|
+----------+----------+----------------+
| | | |
問い合わせ オペレーター 顧客情報 AI分類エンジン
管理 プロファイル インターフェース インターフェース
| 管理 | |
| | | |
+----+-----+----------+ サードパーティ
| AI分類エンジン
中央データベース (500 req/s)
※ 問い合わせルーティングサービスが
着信をオペレーターに振り分ける
担当アーキテクトはこの設計に自信を持っていましたが、リスクストーミングを実施したところ、3つの観点で重要なリスクが発見されました。
可用性リスクの発見と軽減
外部システムのリスクを評価する際は、SLAやSLOを確認することが有効です。
SLA(Service Level Agreement) は、サービス提供者が保証する稼働率などを定めた契約です。
SLO(Service Level Objective) は、法的拘束力はないものの、提供者が目標とする稼働水準を示します。
| リスク | 評価 | 軽減策 |
|---|---|---|
| 中央DBが落ちると問い合わせルーティングが停止する | 高リスク(6) | オペレータープロファイル用DB(クラスタ化)と問い合わせ管理用DBに分割 |
| AI分類エンジンが利用不能になる | 高リスク(9) | SLAを確認 → 99.99%の可用性保証(年間約52.56分のダウンタイム)を確認しリスクを受容 |
弾力性リスクの発見と軽減
AI分類エンジンは500リクエスト/秒しか処理できません。
250人のオペレーターだけなら問題ありませんが、年末商戦や大型セール時にセルフサービスのアクセスが急増すると、処理能力を超えてしまいます。
チームは段階的に3つの軽減策を積み重ねました。
- 非同期キューでバックプレッシャー: API GatewayとAI分類エンジンの間にメッセージキューを挟み、リクエストが溢れた場合の緩衝材にする
- チャネルの分離: オペレーター用とセルフサービス用で2つのメッセージチャネルを用意し、オペレーターのリクエストを優先的に処理する(Ambulanceパターン)
- キャッシュの導入: セール時のよくある問い合わせ(「配送状況を知りたい」「返品したい」など、同じ質問が大量に繰り返される)をキャッシュし、AI分類エンジンへの呼び出し自体を削減する
Ambulanceパターンは、救急車が優先的に道路を通れるように、重要なリクエストを別チャネルで優先処理するパターンです。
セキュリティリスクの発見と軽減
全てのユーザー(管理者、セルフサービス利用者、オペレーター)が同じAPI Gatewayを通る構成では問題があります。
API Gatewayの認証・認可チェックが突破された場合に、セルフサービス利用者が顧客の個人情報にアクセスできてしまう個人情報保護法違反のリスクがあるのです。
軽減策として、ユーザー種別ごとにAPI Gatewayを分離しました。
管理者用、セルフサービス用、オペレーター用の3つに分けることで、非オペレーターのリクエストが顧客情報インターフェースに到達すること自体を防ぎます。
リスクストーミングによるアーキテクチャの変化
リスクストーミングの前後で、アーキテクチャは大きく変わりました。
| 要素 | Before | After |
|---|---|---|
| データベース | 単一の中央DB | オペレータープロファイル用(クラスタ化)+ 問い合わせ管理用の2つに分割 |
| AI分類エンジンとの通信 | REST直接呼び出し | 非同期キュー + オペレーター/セルフサービス別チャネル + セール時キャッシュ |
| API Gateway | 全ユーザー共通の1つ | 管理者/セルフサービス/オペレーターの3つに分離 |
リスクストーミングを実施しなければ、これらの問題は本番稼働後に発覚していた可能性が高いものでした。
まとめ ― 決定を記録し、リスクを可視化することで何が変わるか
この記事では、設計判断とリスク管理に関する2つの手法を見てきました。
ADRで判断の「なぜ」を記録し、リスクマトリックスとリスクストーミングでリスクをチームの共有知にする。
この2つに共通するのは、「暗黙知を形式知にする」というアプローチです。
個人の頭の中にある判断根拠やリスク認識を、チーム全員が参照できる形に変換することが、設計判断の質を底上げする第一歩になります。
リスクストーミングは一度きりのイベントではありません。大きな機能追加や開発の節目ごとに継続的に実施することで、アーキテクチャの健全性を保ちます。
設計そのものの巧拙も重要ですが、それ以上に、決定を記録し、リスクを可視化する習慣がチームの意思決定の質を長期的に変えていきます。
まずは次の設計判断で、1つADRを書いてみるところから始めてみてはどうでしょうか。