コンテンツにスキップ

ADR の書き方

このガイドが解く問題: 記録に値する決定があり、templates/5_adr.md を目の前にしている。各セクションに何を書くか、何を書か ない か、ADR がよく失敗する典型を避ける方法は? このガイドは MADR v3.0 に特化した深掘りで、汎用の how-to/choose-the-right-template.md を補完します。

これは how-to です ―― すでに ADR が正しい artefact だと決めた前提(未確認なら choose-the-right-template.md §よくある混同 #2 から)。

形式の正本リファレンスは MADR v3.0 です。本ページはその上に 運用ガイダンス を重ねます ―― pentaglyph プロジェクトでフォーマットをどう使いこなすか。


  1. 1 ADR 1 決定。決定文に「かつ / と」が入っているなら分割
  2. Status は Proposed で始める。チームレビュー後にのみ AcceptedAccepted ADR の本文を編集してはいけない ―― 新 ADR で supersede する
  3. Alternatives セクションは必須。代替案を検討していないなら、アーキテクチャ判断ではなく default を持っているだけ
  4. ファイル名: arc42/09-decisions/NNNN-<kebab-title>.mdNNNN は次の連番 4 桁、0 埋め
  5. 相互リンク: 決定をトリガした PRD、それを実装する Module DD、ベースまたは supersede 関係の先行 ADR

arc42/09-decisions/ の中で最大の既存 ADR 番号を探す:

Terminal window
ls docs/arc42/09-decisions/ | grep -E '^[0-9]{4}-' | sort | tail -1

次の連番 4 桁を使う。「将来のカテゴリ用」にギャップを予約しないこと ―― 番号は 単なる識別子 で、階層ではありません。番号予約は ADR 連番に紛らわしい穴を作る最頻出の失敗パターンです。

Terminal window
cp docs/templates/5_adr.md docs/arc42/09-decisions/NNNN-<kebab-title>.md

あるいは Claude に頼む(prompt-cookbook §3):

docs/templates/5_adr.md から ADR を書いて、次の決定を記録: <1 文サマリ>docs/arc42/09-decisions/<next-NNNN>-<kebab-title>.md に配置。Status Proposed。必須セクションをすべて埋めて。

タイトルは 決定そのもの であって、トピックではありません。動詞句として書く:

✅ Good(決定)❌ Bad(トピック)
「主永続化に PostgreSQL を採用」「データベース選定」
「first-party クライアントに OAuth 2.1 PKCE を使用」「認証」
「async ジョブを in-process でなく Cloudflare Queues で実行」「ジョブ処理」

「〜-tion」「〜選定」名詞で終わるタイトル(Authentication、Selection、Processing)はほぼ常に間違った形です。読者がタイトルから何が決まったか分かりません。

2〜4 文。要素 2 つ:

  1. forcing function(駆動要因)。コードベース・プロダクト・制約で何が変わってこの決定が必要になったか?「v1 API を Q2 にリリースする必要」/「PoC のデータベースが負荷テストで接続上限を超えた」/「コンプラレビューがログ 90 日保持を要求」
  2. decision space。決定の瞬間にテーブル上にあった候補アプローチ。選ばれたもの(後で出てくる)ではなく、選んだ space

4 文を超えそうなら、議論を narrate している可能性大。要点に切り詰めて。

アンチパターン: ミーティング議事録のような Context(「Alice が問題を提起、それから Bob が…」)。ADR は永続記録であってチャットログではない。

5. Decision を書く(何を選んだか

Section titled “5. Decision を書く(何を選んだか)”

1〜3 文。選んだオプションを明確に宣言。読者は このセクション単体で実装できる べき。

例:

ユーザー / 注文 / 監査テーブルの主永続化に PostgreSQL 16 を使う。スキーマは db/migrations/ にあり、Alembic でバージョン管理。Read replica はこの決定のスコープ外(ADR-0024 を参照)。

最後の節に注目: スコープ を明示的に印付けすると、将来の読者がこの ADR がカバーしていないものをカバーしていると誤解するのを防げます。

6. Consequences を書く(何が続くか

Section titled “6. Consequences を書く(何が続くか)”

ここで ADR は価値を稼ぎます。3 つのサブセクション:

Positive consequences。どんな良い結果を期待するか? 具体的に:「検索ユースケース向けに pg_vector を解放」が「より良い技術基盤」より優れる。

Negative consequences。何をコストとして受け入れているか?「SQLite に対する運用複雑度の増加 ―― バックアップ・レプリケーション・バージョン更新手順が必要に」。negative セクションがトレードオフを真剣に取った証拠です。

Neutral consequences。良くも悪くもないが続くもの。空でも構いません。

アンチパターン: 空の Negative consequences。downside を 1 つも挙げられないなら、決定を実際に weigh していない ―― rationalize しているだけ。小さくてもいいので最低 1 つコストを挙げる。

7. Alternatives を書く(何を却下したか、なぜか

Section titled “7. Alternatives を書く(何を却下したか、なぜか)”

最も重要なセクション。真剣に検討した各代替案を、却下の具体的な理由 と共にリストアップ。

代替案ごとの形式:

#### SQLite
検討理由: 低い運用オーバーヘッド、組み込みデプロイ。
却下理由: 負荷テストで同時 ~200 エージェントで接続プール枯渇。
500 エージェント目標を下回る。WAL モードで改善するもギャップを埋めず。

避けるべき 2 つの失敗モード:

失敗修正
わら人形代替案「フラットファイルを検討。遅い」(誰も真剣に提案していない)5 分以上真剣に検討された代替案のみリスト
漠然とした却下理由「MongoDB を検討。document store はユースケースに合わない」失格させた 具体的な特性 を挙げる。「スキーマドリフトが migration layer での厳密型付けを妨げる」、ではなく「合わない」では不可

本当に代替案がなかったなら(プラットフォームが選択を強制したなど)、それはアーキテクチャ判断ではなく制約です。arc42/09-decisions/ ではなく arc42 §2(Constraints)に記録。

---
status: Proposed # → review 後 Accepted → 置換時 Superseded
date: 2026-05-17
deciders: ["alice", "bob"] # GitHub handle または名前
supersedes: 0007 # この ADR が別の ADR を置換する場合のみ
superseded-by: ~ # 後でこの ADR が supersede されたら埋める
---
  • deciders: 3 か月後に「なぜ?」と聞ける人々。チーム全員ではなく、実際にトレードオフを weigh した 2〜4 人
  • supersedes: 古い ADR を置換するときに名指す。次に 古い ADR の front-matter を更新 して superseded-by: <this-NNNN>status: Superseded をセット。古い ADR の本文は編集しない

双方向リンクを追加:

  • PRD から(該当する場合): 「決定は ADR-NNNN に記録」の行を追加
  • PRD へ: ADR Context セクションに「[PRD link] によって駆動」の行
  • それを実装する Module DD から: 「ADR-NNNN に従い、~~~を使う」の行
  • 先行 ADR との間: 特に supersede チェーン

相互リンクが 6 か月後に ADR を findable にする要素です。リンクのない ADR はデッドウェイトです。

Status flow:

Proposed → Accepted (チームレビューが承認したあと)
Proposed → Rejected (チームが提案に反対した場合)
Accepted → Superseded (後の ADR が置換する場合)

Proposed → Accepted 遷移だけがチーム sign-off を要します。他は事実の記録で、許可を求めていません。

Rejected ADR はディスクに残す。削除しないこと ―― 却下に至った推論は価値があります。status: Rejected をセットし、本文は無傷で残す。


最頻出の失敗モードは、ADR ラベルの下に間違った artefact を書くことです:

ADR に見えるが違うもの正しい置き場
実装詳細付きの小さなデザイン docdetailed-design/<module>.md
チームが従うべき「原則」「ガイドライン」リストdesign-guide/<topic>.md
ミーティングサマリSlack メッセージか Notion ページ。リポジトリ外
レトロスペクティブの気づきtask-list/YYYY-MM-DD_sprint-NN-retro.md
外部からの制約(規制・プラットフォーム)arc42 §2 Constraints
関連するから bundle した 3 決定3 つの別 ADR、相互リンク

迷ったら自問: 「将来の読者が、Decision セクションだけから実装できるか? Alternatives セクションが「でも X は?」という当然の疑問に答えているか?」 YES なら valid な ADR。NO なら上の表のいずれか変装したもの。


ADR はどのくらいの長さであるべきか?

Section titled “ADR はどのくらいの長さであるべきか?”

MADR の例と我々の経験は同じ答えに収束します: 半ページから 1 ページ がスイートスポット。

  • 100 語未満 は通常、3 か月後に決定を defend するには薄すぎ
  • 600 語超 は通常、実装詳細を ADR に引きずり込んでいる。Module DD に移す

長い ADR は「より厳密」ではなく、通常はより load-bearing でないです。規律は どの段落が生き残るか であって、 何段落書いたか ではありません。


最終的には決定を変える必要が出てきます。ルール:

変更タイプやること
typo・broken link・欠落した front-matter フィールド既存ファイルを直接編集
決定 そのもの が変わる(PostgreSQL をやめて CockroachDB に)新 ADR を supersedes: <old NNNN> 付きで書く。古い本文を編集しない
決定が部分的に obsolete(依然 PostgreSQL だが read replica 追加)古い ADR を 拡張 する新 ADR を書く。古いものは Accepted のまま。新 ADR の Context が古いものを引用

「Accepted 本文を編集しない」が非交渉なのは、ADR の価値が安定した歴史記録だからです。編集者が過去の決定を書き直せるなら、audit trail は崩壊します。新 ADR を書くコストは 低い(1 ページ)。trail を腐らせるコストは 高い(チームが ADR を信頼しなくなる)。


  • タイトルは動詞句、名詞ではない
  • 1 決定、bundle しない
  • Context が forcing function と decision space を名指している
  • Decision セクションがそれ単体で実装可能
  • Consequences に negative が最低 1 つ含まれる
  • Alternatives セクションに具体的な却下理由付きで 2 件以上
  • front-matter に statusdatedeciders
  • PR タイトルと説明が ADR を参照
  • 別 ADR を supersede するなら、古い ADR の front-matter が本文編集なしで更新済み
  • 長さは 100〜600 語