TalentX Tech Blog

Tech Blog

ADRを書き始めた話

TalentXでバックエンドエンジニアをしている中山です。最近、社内の技術的な意思決定をADR(Architecture Decision Record)として残す取り組みを始めました。導入にあたって考えたことや、自分たちの組織に合わせて工夫したことを共有しようと思います。

ADRとは

ADR(Architecture Decision Record)は技術的な意思決定とその背景を残しておくための、シンプルなドキュメントフォーマットです。何を決めたかだけでなく、なぜその決定をしたのかまでを書き残すことで、コードを読んでも分からない設計判断の経緯を補完します。

なぜ書き始めたのか

ADRを書き始めた動機は、大きく二つあります。一つは過去の意思決定を辿れるようにするため、もう一つはAIエージェントに「なぜ」までを含めたコンテキストを渡すためです。

過去の意思決定を辿れるようにする

TalentXではこれまで、技術的な意思決定の背景がSlackのスレッド、ドキュメント、関係者の記憶など複数の場所に分散していることがありました。そのため、後から経緯を確認する際に、複数の情報源をたどる必要がありました。 それでも経緯を把握しきれず、「おそらくこういうことなのだろう」という推測で終わってしまう場面もありました。

特に困るのが、複数のプロダクトを開発している中で、過去にあるプロダクトで採用したアーキテクチャを他のプロダクトに横展開可能かを検討する場面です。「なぜ当時その方式を選んだのか」が残っていないと、別のプロダクトでも同じ検討を一からやり直すことになります。検討した結果同じ結論に落ち着くなら良いのですが、前提が違うのに踏襲してしまったり、逆に良い前例があるのに気付かず一から考え直してしまったり、という無駄が出てきます。

こうした課題感から、ADRの運用を始めることにし、まずは自分から書き始めてみることにしました。

AIエージェントへのコンテキストとして

Claude CodeをはじめとしたAIエージェントを、実装やレビューに活用するケースが増えてきました。一方でエージェントはコードから「何が書かれているか」は読み取れても、「なぜこうなっているか」までは把握しづらい側面があります。

例えば以下のような情報です。

  • 棄却された選択肢: 他にどんな案が検討されていたのか、それらがなぜ選ばれなかったのか。
  • 判断の前提条件: 「このときはこういう制約があったから、この設計にした」という背景。前提が変われば結論も変わり得ます。
  • トレードオフ: 決定には何らかのトレードオフが伴うことが多く、その決定と引き換えにどんなデメリットを受け入れて、それを緩和するためにどんな対策を取っているのか。
  • 過去の失敗の記憶: 以前試して上手くいかなかった、というドメイン固有の経験則。

こういった情報をADRとして蓄積しておき、コンテキストとして渡しておけば、「なぜ」を含めた上での提案や、制約条件に沿った案を引き出しやすくなるのではと考えました。想定するユースケースは次の通りです。

  • 新規機能の設計フェーズ: 対象領域のADRを読ませた上で実装方針を壁打ちする。過去のトレードオフを踏まえた選択肢を引き出しやすくなる。
  • プロダクト横断での展開: あるプロダクトで採用したアーキテクチャを他のプロダクトに横展開したい場合に、参照元プロダクトのADRを渡した状態で実装に入ることで、一貫性のある実装に近づけやすくなる。
  • レビュー時の整合性チェック: 変更内容がADRと整合しているかを確認する。整合しない場合は、ADRの更新を含めた議論の起点になる。

いつ書くのか

「技術的な意思決定が発生したタイミング」としています。迷ったら、以下のいずれかに当てはまるかで判断します。

  • 巻き戻しコストが高い: 一度入れたら剥がしにくい決定。例えば、サービス間でどのサービスにデータを持たせるか、といった選択。
  • 複数の選択肢から1つを選んだ: ライブラリや外部サービスの選定など、後から「なぜこっちにしたのか」を問われるタイプの決定。
  • 暗黙の前提や制約に基づいている: 背景を知らない人がコードだけ見ても理解できないような決定。

逆に、コードを追えばすぐに理解できるような実装上の細かい選択は対象としないことにしました。

ADRのフォーマット

ADRはマークダウンで書くようにしています。後から「何をどう検討して決めたか」が辿れることを重視し、世の中のADRテンプレートを参考にしつつ、自分たちの事情に合わせていくつかの項目を調整しました。

---
id: "{{id}}"
title: "{{title}}"
date: "{{YYYY-MM-DD}}"
authors:
  - "{{author}}"
status: "accepted"
products:
  - "{{product}}"
stacks:
  - "{{stack}}"
tags:
  - "{{tag}}"
---

# コンテキスト

# 検討した選択肢

## 案A: {{案名}}(採用)

## 案B: {{案名}}

# 決定

# 影響

## 期待される効果

## 制約と緩和策

# 関連ドキュメント

フロントマター

ADRのメタデータをマークダウンのフロントマターとして書くようにしています。メタデータがファイル先頭にまとまっていることで、対象のADRを検索しやすくなるだけでなく、AIエージェントがADRを全文読まずに対象を絞り込みやすくなると考えました。

id

ADR間で参照や引用がしやすいように、各文書に0001のようなidを振っています。

status

ADRのステータスを表します。

  • accepted: 承認済み

  • rejected: 棄却。議論内容を履歴として残すため、承認が得られなかったADRも削除せずこのステータスにします。

  • deprecated: 非推奨。代替案を立てずにそのADRの方針を取りやめる場合に指定します。

  • superseded: 代替済み。新しい方針になったときに既存のADRを上書きするのではなく、新しいADRを発行してこのステータスにします。

products

対象プロダクトを記載します。全社共通の場合はallとしています。

stacks

対象の技術スタック(backend / frontend / mobile / infraなど、複数可)。あるプロダクトのバックエンドだけに関わる決定なのか、フロントエンドも含むのか、といった粒度で絞り込めるようにしています。

tags

関連トピック(s3, presigned-urlなど複数可)。products / stacks では拾いきれないテーマや技術領域を補完する軸で、AIエージェントによる探索のしやすさも意識して設計しています。

コンテキスト

解決したい課題、前提、制約を簡潔に書きます。

中でも前提は、決定のベースとなる状況のことを指します。課題や制約と違って暗黙的になりやすく、かつ前提が変われば結論も変わり得る部分なので、「当時の前提は何だったのか」が後から辿れるように意識して残しています。

そのうえで、なぜ今この決定が必要なのかが伝わるよう、過不足なく書くことを意識しています。

検討した選択肢

ライブラリを選定するにも、アーキテクチャを検討するにも複数の案の中から比較検討する場面が多く、ADRの大きな価値はここにあると考えています。

決定された結果だけが残っていると、後から見た人には「なぜそれを選んだか」は伝わっても、「なぜ他を選ばなかったか」が伝わりません。

数ヶ月後に「Bという選択肢のほうが良いのでは?」という声が上がったとき、Bがそもそも検討されていなかったのか、検討した上で棄却されたのか、棄却されたならその理由は何だったのか。これらが残っているかどうかで、議論のスタート地点がまったく変わります。検討済みであれば棄却理由を起点に再評価できますし、未検討であれば新しい観点として議論できます。どちらにせよ、過去の議論を一から掘り起こす必要がなくなります。

書き方として、各案は判断軸を揃えて比較するようにしています。「実装コスト」「運用負荷」「拡張性」など、各案で同じ観点で評価するようにしています。採用案には末尾に (採用) を付けて、一見で分かるようにしています。

決定

「検討した選択肢」のうちどれを採用するかを明記します。実装の細部までは書かず、判断の原則レベルで書くことを意識しています。実装パターンの細かい違いが後から出てきたときに、ADRの内容と矛盾しにくくするためです。

「条件付きで採用」のようなケースでは、その条件もここに書きます。例えば「現状はA案を採用するが、トラフィックが特定の閾値を超えたタイミングでB案への切り替えを検討する」のように、将来的に判断が変わり得るポイントも含めて残します。

影響

「影響」セクションには、決定によって生まれるプラスの影響と、そのトレードオフを書くようにしています。

決定には何らかのトレードオフが発生することがほとんどです。そのため、トレードオフを正直に記載した上で、それを和らげるための運用や仕組みを併記するルールにしています。

例えば、同期的に処理していたものをキューを挟んで非同期化する決定を考えてみます。プラスの影響として、リクエストのレスポンスタイムを短縮できる一方で、処理完了までにタイムラグが生まれ、失敗時のリトライやエラー通知の仕組みが別途必要になるというトレードオフが生じます。この場合は「リトライポリシーとデッドレターキューの運用ルールを定める」「処理状況をユーザーに可視化するUIを用意する」といった緩和策まで書きます。トレードオフを認識した上で、それを引き受ける覚悟と備えがあることまで含めて記録するイメージです。

関連ドキュメント

関連するADRやSlackのスレッド、Pull Requestのリンクなどを貼ります。

どこで管理するか

ADRはGitHub上のリポジトリで管理しています。

理由としてはレビューのしやすさです。ADRを読むのは基本的にエンジニアとAIエージェントなので、エンジニアの作業導線に近く、かつAIエージェントからの読み取りもしやすいGitHubで管理する方針としました。

プロダクトごとではなく1つのリポジトリに集約したのは、複数プロダクトをまたぐ意思決定が多いことが想定されるためです。プロダクトごとのリポジトリにADRを置いてしまうと、どのリポジトリにADRを書くのかに悩んだり、どのリポジトリにADRが置かれているのかが分からなくなることを懸念しました。

また、ディレクトリ構成はフラットにして、どのプロダクトに関係するかはフロントマターのproductsstacksで表現する、という設計にしています。こうすることで、どこに文書を配置するかを考えなくて良いようにしました。

その他工夫したこと

メンバーがADRに何を書けばよいか悩まないように、READMEとテンプレートを充実させました。 これはAIエージェントにADRを書かせやすくするのも目的の1つです。ガイドラインがあれば「この議論の結果をADRとしてまとめて」と頼んだときに、フォーマットに沿った文書を生成してくれます。

やってみた所感

正直に書くと、ADRを書くのには思ったよりも時間がかかりました。

ただ、書く過程で、比較をしようとしたら観点が足りないことに気付いたり、トレードオフ分析が曖昧だと感じたりと、設計に対する深掘りができている実感があります。書く段階で設計の穴に気付ければ、結果的に手戻りの削減にもつながると考えています。

テンプレートはすでに整備していますが、運用しながら気付いた改善点を反映しつつ、チームメンバーがADRを書く際の心理的ハードルをさらに下げていけたらと思います。

最後に

ADRを書き始めたのは、過去の意思決定をきちんと残したかったから、というのはもちろんですが、これからの開発でAIエージェントをより効果的に活用していくための土台を作りたかった、というのが狙いです。コードに残らない「なぜ」が文書として積み上がっていくことで、人間もAIエージェントも過去の判断を踏まえやすくなり、開発効率が上がっていくと考えています。

現在、TalentXでは一緒に働く仲間を募集しております。

talentx.brandmedia.i-myrefer.jp

カジュアル面談も行っておりますので、ぜひご応募ください!

i-myrefer.jp