ADR とは何か

ADR(Architecture Decision Record)は、「ある時点においてどのような設計上の判断をなぜ行ったか」を記録する軽量なドキュメントです。 1つの ADR が1つの決定を表し、リポジトリ内の docs/adr/ ディレクトリに番号付きファイルとして蓄積していきます。

ADR がない現場でよく起きる問題は「誰かがなぜこの設計にしたのか分からない」という状態です。 口頭で決まった内容は数ヶ月後に誰も覚えておらず、ドキュメントがないため再議論が発生します。 ADR はこの「設計の忘却問題」を防ぐための最も軽量な手段です。

💡 ADR の特徴

ADR は「不変の記録」です。決定を変更する場合は既存の ADR を書き換えるのではなく、新しい ADR を追加して旧 ADR を「Superseded(置換済み)」に更新します。これにより判断の変遷が追跡できます。

どのタイミングで ADR を書くか

ADR を書くべき判断の基準は「後で理由を説明できないと困るか?」です。以下のような決定は ADR 化の対象です。

判断の種類
技術スタック選定フレームワーク・データベース・メッセージキューの選択
アーキテクチャパターンモノリス vs マイクロサービス・レイヤー構造の採用
外部サービスの採用認証に Auth0 を使う・ストレージに S3 を使う
非機能要件のトレードオフ整合性よりスループットを優先するキャッシュ戦略
コーディング規約の変更例外処理方針・ログフォーマットの統一
廃止・移行の決定旧ライブラリの廃止・API バージョンの削除

ADR の5セクション構成

Michael Nygard が提唱した元の形式にステータスと代替案を加えた5セクション構成が実務で広く使われています。

① タイトル(Title)

番号と内容を一言で表す文字列。「何を決めたか」が分かる名詞句または動詞句で書きます。 ファイル名と一致させることが推奨されます。

Markdown — タイトルの例
# ADR-0012: API ゲートウェイに Kong を採用する

② ステータス(Status)

現在の決定の状態を明示します。詳細は次のセクションで解説します。

③ コンテキスト(Context)

この決定が必要になった背景・制約・課題を記述します。「なぜこの決定が必要だったのか」が分かる情報をすべて含めます。

定義すべき内容:

項目説明
背景・課題何が問題で・何が変わったのか
制約条件予算・チームスキル・既存技術スタック・期限など
関連 ADRこの決定に影響を与えた以前の決定
ステークホルダー誰がこの決定に影響を受けるか

④ 決定(Decision)

「何をするか」を明確に書きます。曖昧な表現は禁物——「〜を検討する」ではなく「〜を採用する」「〜を使用しない」のように断言します。 代替案をここで比較し、採用理由を論理的に説明します。

比較軸KongAWS API GatewayNginx
認証プラグイン豊富(JWT/OAuth/LDAP)Cognito 依存別途実装必要
レート制限ネイティブ対応ネイティブ対応プラグイン要
オンプレ対応✗(AWS 専用)
学習コスト低(AWS 既知)

⑤ 結果・影響(Consequences)

この決定を採用した場合の影響を正直に記載します。ポジティブな面だけでなく、トレードオフ・デメリット・将来リスクも含めます。

Markdown — 結果・影響の記述例
## 結果・影響

### ポジティブ
- 認証・レート制限を API ゲートウェイに集約でき、各マイクロサービスの実装が単純化される
- Kong のプラグインエコシステムにより、将来の機能追加がコードなしで可能

### ネガティブ(トレードオフ)
- Kong 自体の運用スキルが必要になる(学習コスト:2週間想定)
- Kong が SPOF(単一障害点)になるため、高可用性構成(Active-Active)が必要

### 将来への影響
- Kong のバージョンアップに追従するメンテナンスコストが発生する
- オンプレからクラウド移行時に Kong Cloud(Konnect)への移行が選択肢になる

ステータス管理

ADR のステータスは決定の生存状態を表します。以下の4種類が標準的です。

ステータス意味使うタイミング
Proposed 提案中 PR でレビュー中の段階
Accepted 採択済み チームの合意が得られた
Superseded 別 ADR に置換済み 新しい ADR が同じ決定を上書きした
Deprecated 廃止 決定の前提が崩れ無効になった

ファイル命名・保存場所

ADR は以下のルールでリポジトリ内に保存することが一般的です。

ディレクトリ構成例
docs/
└── adr/
    ├── 0001-use-postgresql-for-primary-db.md
    ├── 0002-adopt-layered-architecture.md
    ├── 0003-use-redis-for-session-cache.md
    └── 0012-adopt-kong-as-api-gateway.md

ファイル名は NNNN-内容を表す-kebab-case.md の形式が標準です。番号は4桁ゼロ埋めにすることで ls の昇順ソートで時系列順に並びます。

ADR の記載例

Markdown — ADR テンプレート全体
# ADR-0012: API ゲートウェイに Kong を採用する

## ステータス
Accepted(2026-06-20)

## コンテキスト
マイクロサービス化に伴い、認証・認可・レート制限・ロギングを各サービスが
個別に実装している状態が問題になっている。重複実装の解消と横断的関心事の
集約のため、API ゲートウェイの導入を検討した。

制約:
- オンプレ環境での動作が必須(AWS 専用ソリューションは対象外)
- チームに Nginx の運用経験あり(Kong は未経験)
- 導入まで 3 ヶ月以内

## 決定
API ゲートウェイとして **Kong(オープンソース版)** を採用する。

### 比較した代替案

| 観点 | Kong | AWS API Gateway | Nginx + Lua |
|---|---|---|---|
| オンプレ対応 | ◎ | ✗ | ◎ |
| 認証プラグイン | 豊富 | Cognito 依存 | 自前実装 |
| レート制限 | ネイティブ | ネイティブ | プラグイン要 |
| 学習コスト | 中 | 低 | 高 |

Kong を選定した理由:オンプレ必須という制約を満たしつつ、
プラグインで認証・レート制限を設定のみで実現できるため。

## 結果・影響
### ポジティブ
- 横断的関心事を API ゲートウェイに集約し、各サービスの実装が単純化される
- プラグインによる将来の機能追加がコード変更なしで可能

### ネガティブ(トレードオフ)
- Kong 自体の運用知識が必要(習得コスト 2 週間を見込む)
- 高可用性のための Active-Active 構成が追加インフラコストになる

## 関連 ADR
- ADR-0003: Redis をセッションキャッシュに採用する(セッション管理との連携に影響)

Python で ADR を自動管理する

ADR が増えてくると一覧性が重要になります。Python で ADR ファイルを解析してステータス別一覧を生成するスクリプトを紹介します。

① ADR 一覧を Markdown テーブルで出力

Python — ADR を解析して一覧テーブルを生成
"""
docs/adr/ 配下の Markdown ADR を解析し、
ステータス別の一覧表を標準出力に書き出す。
"""
import re
from pathlib import Path
from collections import defaultdict

ADR_DIR = Path("docs/adr")

STATUS_PATTERN = re.compile(
    r"##\s+ステータス\s*\n(.+?)(?:\n##|\Z)",
    re.DOTALL | re.IGNORECASE
)
TITLE_PATTERN = re.compile(r"^#\s+(.+)", re.MULTILINE)

def parse_adr(path: Path) -> dict:
    text = path.read_text(encoding="utf-8")

    title_m = TITLE_PATTERN.search(text)
    title = title_m.group(1).strip() if title_m else path.stem

    status_m = STATUS_PATTERN.search(text)
    status_raw = status_m.group(1).strip() if status_m else "Unknown"
    # 日付部分を除いてステータス名だけ取り出す
    status = re.split(r"[((]", status_raw)[0].strip()

    return {
        "file":   path.name,
        "title":  title,
        "status": status,
    }

def main():
    if not ADR_DIR.exists():
        print(f"ディレクトリが見つかりません: {ADR_DIR}")
        return

    adrs = sorted(
        [parse_adr(p) for p in ADR_DIR.glob("*.md")],
        key=lambda x: x["file"]
    )

    by_status = defaultdict(list)
    for adr in adrs:
        by_status[adr["status"]].append(adr)

    print("# ADR 一覧\n")
    for status, items in sorted(by_status.items()):
        print(f"## {status}\n")
        print("| ファイル | タイトル |")
        print("|---|---|")
        for item in items:
            print(f"| `{item['file']}` | {item['title']} |")
        print()

if __name__ == "__main__":
    main()

② 次の ADR 番号を自動採番

Python — 次の ADR ファイル名を自動決定してテンプレートを生成
"""
既存の ADR から次番号を自動採番し、テンプレートファイルを生成する。
使い方: python new_adr.py "API ゲートウェイに Kong を採用する"
"""
import sys
import re
from pathlib import Path
from datetime import date

ADR_DIR = Path("docs/adr")

TEMPLATE = """\
# ADR-{num:04d}: {title}

## ステータス
Proposed({date})

## コンテキスト


## 決定


## 結果・影響
### ポジティブ
-

### ネガティブ(トレードオフ)
-

## 関連 ADR
-
"""

def next_number() -> int:
    existing = list(ADR_DIR.glob("*.md"))
    if not existing:
        return 1
    nums = []
    for p in existing:
        m = re.match(r"^(\d+)", p.name)
        if m:
            nums.append(int(m.group(1)))
    return max(nums) + 1 if nums else 1

def main():
    if len(sys.argv) < 2:
        print("使い方: python new_adr.py '決定内容のタイトル'")
        sys.exit(1)

    title = sys.argv[1]
    num = next_number()
    slug = re.sub(r"[^\w\s-]", "", title.lower()).replace(" ", "-")
    filename = f"{num:04d}-{slug}.md"
    path = ADR_DIR / filename

    ADR_DIR.mkdir(parents=True, exist_ok=True)
    path.write_text(
        TEMPLATE.format(num=num, title=title, date=date.today().isoformat()),
        encoding="utf-8"
    )
    print(f"作成しました: {path}")

if __name__ == "__main__":
    main()

ADR のアンチパターン

アンチパターン問題対策
後から書く決定の背景が曖昧になる決定直後・PR 時に書くルールにする
既存 ADR を書き換える判断の変遷が追跡できなくなる新 ADR を追加し旧 ADR を Superseded にする
結果・影響を書かないトレードオフが伝わらないネガティブ面も正直に記述する
小さすぎる決定まで書くADR が増えすぎて誰も読まなくなる「後で理由を説明できないと困るか?」で取捨選択
ADR を Wiki に置くコードとドキュメントが同期しないリポジトリ内の docs/adr/ に置く

まとめ

ADR で定義すべき5要素

□ タイトル — 番号 + 何を決めたかを一言で
□ ステータス — Proposed / Accepted / Superseded / Deprecated
□ コンテキスト — 背景・制約・関連 ADR
□ 決定 — 何をするか・代替案との比較・採用理由
□ 結果・影響 — ポジティブ面とネガティブ面(トレードオフ)を正直に記述

ADR の最大の価値は「なぜそうしたか」を未来の自分やチームメンバーが即座に理解できる点にあります。 Python スクリプトで一覧化・自動採番を仕組み化し、PR テンプレートに「ADR が必要な変更か確認」のチェック項目を加えると、継続して書き続ける文化が育ちます。