LESSON 40分

ストーリー

佐藤CTO
半年前に”なぜこのデータベースを選んだのか”を聞かれたが、誰も答えられなかった

佐藤CTOが渋い顔で言いました。

佐藤CTO
意思決定した本人はもう退職していた。ドキュメントもない。結果、同じ議論を2週間かけてやり直した
あなた
それは痛いですね…
佐藤CTO
アーキテクチャの意思決定を記録しない組織は、同じ失敗を繰り返す。ADR — Architecture Decision Records は、この問題を解決するための軽量な仕組みだ

ADRとは

概要

項目内容
定義アーキテクチャに関する重要な意思決定を記録する短いドキュメント
目的「なぜその決定をしたか」を将来の自分とチームのために残す
特徴軽量、イミュータブル(一度書いたら変更しない)、コードと一緒に管理
提唱者Michael Nygard(2011年)

ADRの価値

ADRがない組織:
  - 「なぜこう設計したの?」→ 誰も知らない
  - 「この技術を変えていい?」→ 変更の影響がわからない
  - 新メンバー「なぜこの構成に?」→ 説明に毎回1時間

ADRがある組織:
  - 「なぜこう設計したの?」→ ADR-005 を読んで
  - 「この技術を変えていい?」→ ADR-005 の前提条件が変わったか確認しよう
  - 新メンバー「なぜこの構成に?」→ docs/adr/ を読めば経緯がわかる

ADRテンプレート(基本形)

Michael Nygard の原型

# ADR-NNN: [タイトル]

## ステータス
[Proposed | Accepted | Deprecated | Superseded by ADR-XXX]

## コンテキスト
[この決定が必要になった背景と制約条件]

## 決定
[何を決定したか]

## 結果
[この決定によって生じるポジティブ・ネガティブな影響]

「このシンプルさがADRの最大の強みだ。書くのに30分以上かかるなら、それはADRではなく設計書だ」 — 佐藤CTO


MADR(Markdown Any Decision Records)フォーマット

より構造化されたフォーマットで、チームでの議論を促進します。

# ADR-NNN: [タイトル]

## ステータス
Accepted

## コンテキスト

### 問題
[解決すべき問題の説明]

### 決定要因
- [要因1: 例えばパフォーマンス要件]
- [要因2: 例えばチームのスキルセット]
- [要因3: 例えばコスト制約]

## 検討した選択肢

### 選択肢1: [名前]
- 良い点: [メリット]
- 悪い点: [デメリット]

### 選択肢2: [名前]
- 良い点: [メリット]
- 悪い点: [デメリット]

### 選択肢3: [名前]
- 良い点: [メリット]
- 悪い点: [デメリット]

## 決定
[選択肢Xを採用する]

### 理由
[なぜその選択肢を選んだか]

## 結果

### ポジティブ
- [良い影響]

### ネガティブ
- [悪い影響・トレードオフ]

### リスク
- [残存リスクと緩和策]

ADRの実例

例: データベース選定

# ADR-005: 患者データストアとしてPostgreSQLを採用する

## ステータス
Accepted (2026-01-15)

## コンテキスト

### 問題
患者管理システムのデータストアを選定する必要がある。
現在MongoDBを使用しているが、以下の課題がある:
- トランザクション処理の信頼性に不安
- リレーショナルデータの結合が複雑
- SOC 2 監査でスキーマ管理の不備を指摘された

### 決定要因
- 医療データのACID準拠トランザクション
- SOC 2 / HIPAA のコンプライアンス要件
- チームのスキルセット(SQL経験者15名中12名)
- 既存データの移行コスト

## 検討した選択肢

### 選択肢1: PostgreSQL
- 良い点: ACID完全準拠、豊富なデータ型、JSON対応、チームに経験者多数
- 悪い点: 水平スケーリングが複雑

### 選択肢2: MongoDB(現行維持)
- 良い点: 移行コストゼロ、スキーマの柔軟性
- 悪い点: マルチドキュメントトランザクションの制限、監査指摘への対応が必要

### 選択肢3: CockroachDB
- 良い点: 分散SQL、水平スケーリング、PostgreSQL互換
- 悪い点: 運用経験なし、コストが高い、学習コスト大

## 決定
PostgreSQL を採用する。

### 理由
1. 医療データには厳格なACIDトランザクションが必須
2. SOC 2 監査要件への対応が容易(スキーマ管理、アクセス制御)
3. チームの75%がSQL経験者であり、学習コストが最小
4. RDS PostgreSQL により運用負荷を軽減可能

## 結果

### ポジティブ
- トランザクションの信頼性が向上する
- SOC 2 監査への対応が容易になる
- チームの既存スキルを活用できる

### ネガティブ
- MongoDBからのデータ移行コスト(推定3人月)
- 一部のドキュメント指向クエリの書き換えが必要

### リスク
- 将来の水平スケーリング需要に対しては、
  Read Replica + パーティショニングで対応予定
- リスク軽減: 半年後にトラフィック分析を実施し、
  スケーリング戦略を再評価する(→ ADR-010予定)

ADR運用の実践

ディレクトリ構造

project-root/
├── docs/
│   └── adr/
│       ├── 0001-use-postgresql-for-patient-data.md
│       ├── 0002-adopt-event-driven-architecture.md
│       ├── 0003-choose-nestjs-for-backend.md
│       ├── 0004-implement-cqrs-for-reporting.md
│       └── template.md
├── src/
└── ...

ライフサイクル

Proposed → Accepted → [Active]

                    Deprecated(もう従わない)
                         or
                    Superseded by ADR-XXX(新しい決定に置き換え)

TypeScript でのADR管理ツール例

// adr-tool.ts - ADR管理CLI
interface ADR {
  id: number;
  title: string;
  status: 'Proposed' | 'Accepted' | 'Deprecated' | 'Superseded';
  date: string;
  supersededBy?: number;
  deciders: string[];
  tags: string[];
}

// ADR一覧の生成
function generateADRIndex(adrs: ADR[]): string {
  const rows = adrs.map(adr => {
    const status = adr.supersededBy
      ? `Superseded by [ADR-${adr.supersededBy}]`
      : adr.status;
    return `| ${adr.id} | ${adr.title} | ${status} | ${adr.date} |`;
  });

  return [
    '# Architecture Decision Records',
    '',
    '| ID | Title | Status | Date |',
    '|----|-------|--------|------|',
    ...rows,
  ].join('\n');
}

// 新規ADR作成
function createADR(title: string, template: string): string {
  const nextId = getNextADRId();
  const filename = `${String(nextId).padStart(4, '0')}-${slugify(title)}.md`;
  const content = template
    .replace('ADR-NNN', `ADR-${nextId}`)
    .replace('[タイトル]', title)
    .replace('[date]', new Date().toISOString().split('T')[0]);

  return filename;
}

Lightweight ADR Process

lightweight_adr_process:
  when_to_write:
    - "新しい技術やフレームワークの採用"
    - "アーキテクチャパターンの変更"
    - "インフラ構成の重要な変更"
    - "APIの破壊的変更"
    - "セキュリティに関する決定"

  when_not_to_write:
    - "小さなライブラリの追加"
    - "コーディングスタイルの変更"
    - "バグ修正の方法"

  process:
    step1: "PRにADRファイルを含める"
    step2: "チームレビュー(通常のコードレビューと同時)"
    step3: "合意が取れたらマージ(= Accepted)"
    step4: "決定を変更する場合は新しいADRを作成(元のADRはSuperseded)"

  time_budget: "1つのADR作成に30分以内"

Decision Log(意思決定ログ)

ADRの上位レベル管理

decision_log:
  purpose: "全ADRを俯瞰し、技術戦略の一貫性を確認する"
  format:
    columns:
      - "ADR ID"
      - "カテゴリ(データ/インフラ/API/セキュリティ)"
      - "影響範囲(単一サービス/複数サービス/全体)"
      - "ステータス"
      - "関連ADR"

  review_cadence: "四半期ごとにアーキテクチャレビューで棚卸し"

  actions:
    - "前提条件が変わったADRを特定しDeprecated/Supersededにする"
    - "新たな決定が必要な領域を洗い出す"
    - "ADR間の整合性を確認する"
ADR IDカテゴリタイトル影響範囲ステータス
001データPostgreSQL採用全サービスAccepted
002アーキテクチャイベント駆動採用複数サービスAccepted
003フレームワークNestJS採用バックエンドAccepted
004アーキテクチャCQRS導入レポーティングProposed
005インフラEKS移行全サービスAccepted

まとめ

ポイント内容
ADRの目的「なぜその決定をしたか」を記録し、知識の喪失を防ぐ
テンプレートコンテキスト→検討した選択肢→決定→結果の構造
MADR選択肢の比較を構造化した拡張フォーマット
運用コードと一緒にGit管理、PRレビューで承認

チェックリスト

  • ADRの目的と価値を理解した
  • 基本テンプレートとMADRフォーマットを把握した
  • ADRを書くべき場面と書かなくてよい場面を理解した
  • Lightweight ADR Processの運用方法を把握した

次のステップへ

次は「アーキテクチャレビュープロセス」を学びます。ADRで記録した意思決定が、組織全体でどのようにレビュー・承認されるかを見ていきましょう。


推定読了時間: 40分