ADR(Architecture Decision Record)入門 ── 在小規模開發中留下「為何採用此設計」的最小做法

· · 設計, 設計審查, 文件, ADR, 技術諮詢, 維護, 委託開發, Windows 開發

「為什麼這裡是用檔案交換啊,直接看資料庫不就好了嗎」──接手系統程式碼的開發者,幾乎一定會遇到這類疑問。而且多數情況下,知道答案的人早已不在專案裡了。

理由應該是存在的。也許是沒有拿到直接連接對方系統資料庫的許可,也許是當時的交期只容許採用那種安全的方式。但如果理由沒有留下來,接手的人不是面對「不知道能不能動的程式碼」而停下手,就是連理由一起破壞掉。

在本部落格中,我們曾以「委外・委託開發 Windows 應用程式前該整理的事項」說明委託開發的進行方式,並以「借鏡IPA『標準交易・合約範本』學習準委任與承攬的區分運用」說明合約的框架。本文要談的是這之後的事——「做出來之後,如何撐過接下來的數年」。我們將以小規模委託開發、企業內部開發為前提,說明用最少工夫留下設計判斷理由的機制,ADR(Architecture Decision Record)

1. 先講結論

  • 應該比全面的設計文件更早留下「決定的記錄」。因為維護時真正讓人困擾的,不是不知道「在做什麼」,而是不知道「為什麼要這麼做」。
  • ADR是一種將1個決定以「標題/狀態/背景/決定/結果」的固定格式寫成1個檔案的輕量格式。由Michael Nygard於2011年提出,原則上每件控制在1〜2頁以內。1
  • 存放位置是與程式碼相同的儲存庫(例如:docs/adr/0001-title.md)。不是放在Wiki或共用資料夾,而是與程式碼一起做版本控制,並在程式碼審查時一併查看。12
  • 決定不會被覆寫。要變更方針時,新增一份新的ADR,並將舊ADR的狀態改為Superseded(已被取代),彼此互相參照。ADR是一種只能新增、不能改寫的日誌。2
  • 不是什麼都寫,而是只寫「事後難以變更」「曾有多個合理選項」「受限制因素左右」的決定。命名規則、格式化工具設定等不在此列。2
  • 依筆者的經驗,將分量控制在每件15〜30分鐘可以寫完,是能持續下去的條件。過於厚重的範本,往往寫到第3件就會中斷。
  • 在委託開發中,ADR會成為可以與發包方共享的成果物。它可以直接當作驗收時的說明資料,以及承辦人異動、供應商更換時的交接資料使用。

本文腳注所指的一手資料共有3項:提出ADR原型的Michael Nygard原始文章1、整理了運用原則(僅供新增、篩選對象、置於版本控制之下)的Microsoft Learn Well-Architected Framework指引2,以及彙整範本與工具的社群網站adr.github.io3。以下的腳注編號皆指向這三者之一。

2. 「不知道為什麼會這樣」的問題

2.1 程式碼會說明What,但不會說明Why

只要閱讀程式碼,(花點時間的話)就能明白「在做什麼」。不明白的是以下這類「為什麼」。

  • 為什麼資料庫用的是SQLite,而不是SQL Server
  • 為什麼與其他系統的連接是用CSV檔案交換,而不是Web API
  • 為什麼只有這份報表要啟動Excel來列印
  • 為什麼還停留在.NET Framework,沒有升級到目前的.NET

這類決定背後,必定有當時的預算、交期、客戶端的限制、與既有資產的權衡等存在於程式碼之外的理由。這些理由寫在註解裡太龐大,寫進設計文件裡「決定的來龍去脈」又顯得格格不入。結果就是,理由哪裡都沒有留下。

2.2 決定的存放地點,幾乎都是幾年後就會消失的東西

那麼實際上,設計判斷的理由現在都放在哪裡呢?我們來比較一下常見的存放地點。

存放地點 幾年後是否還留著 與程式碼的距離 接手的人找得到嗎
口頭・會議上的共識 不會留下 不可能
聊天(Teams/Slack) 隨對話流走,實質上消失 幾乎不可能
電子郵件 埋沒在個人收件匣中 隨離職而消失
會議紀錄(共用資料夾) 會留下,但品質參差不齊 不知道「是哪一次的會議紀錄」
Wiki・設計文件 停止更新,與現況脫節 找得到,但無法信任
ADR(儲存庫內) 與程式碼一起留存 相同的儲存庫 打開 docs/adr/ 就好

Microsoft的架構師指引也明確指出,沒有被記錄下來的決定會被遺忘,進而招致相同討論的重演,以及違背當初用意的變更2

2.3 在委託開發中,合約的斷點就是記憶的斷點

如果是自家公司開發,「問那個人就知道了」還能撐一陣子;但在委託開發中,除了承辦人異動、離職之外,還會發生供應商更換。一旦開發的廠商與維護的廠商變成不同單位,存在於口頭與聊天記錄裡的「為什麼」就會完全消失。

從合約的角度來看,開發與維護分屬不同合約、不同流程,也是很正常的事(這個結構我們在「借鏡IPA『標準交易・合約範本』學習準委任與承攬的區分運用」中討論過)。此外,正如「為避免淪為偽裝承攬的準委任合約正確工作方式」中整理的,正因為準委任是由受託方自主推動業務,能向發包方展示「判斷了什麼、如何判斷」的記錄,才會成為信任的依據。ADR對這兩點都有幫助。

3. 什麼是ADR

3.1 Nygard的提案 ── 5個要素與2頁上限

ADR是Michael Nygard在2011年的部落格文章「Documenting Architecture Decisions」中提出的格式。1 要點如下。

  • 1個決定對應1個檔案。依序編號,號碼不重複使用
  • 檔案採用Markdown等輕量格式,存放於專案的儲存庫內
  • 結構由標題/狀態/背景/決定/結果(Consequences)這5個要素組成
  • 狀態從提案中(proposed)推進到已核准(accepted),要推翻時則改為廢止(deprecated)或已被取代(superseded)。舊有的記錄不刪除
  • 全體控制在1〜2頁以內。寫成未來的開發者讀起來像在對話一樣、完整的文章

只把狀態的變化畫成圖,就能更容易理解ADR是一種「只能新增的日誌」。

建立ADR經審查後核准決定本身不再需要由新ADR取代proposedaccepteddeprecatedsuperseded

無論哪一個箭頭,需要改寫的都只有狀態那一行。背景與決定的本文都不會去動。從 accepted 轉為 superseded 時,加到舊ADR裡的,只有指向新ADR的參照那1行。由於過去的狀態不會被覆寫而是保留下來,事後就能追溯「什麼時候、為什麼方針改變了」。

雖然名字裡有「架構」二字,但這並不是大型系統專用的手法。反而是在沒有專任架構師、也沒有專責文件化人員的小規模開發中,這種「最小限度的固定格式」才更能發揮作用。此外,ADR的範本與工具在社群網站(adr.github.io)上有系統性的整理,可以作為「將架構上重要的決定連同依據與取捨一起記錄下來」這個想法的入門參考。3

3.2 Markdown範本

以下是筆者在小規模案件中使用的範本,完全依循Nygard格式的最小範本。

# ADR-NNNN:(以簡短一句話說明決定內容)

## 狀態

提案中 | 已核准 | 廢止 | 已被取代(→ ADR-MMMM)

## 背景

為什麼需要這個決定。要寫得讓不了解當時狀況的讀者也能明白,
包括技術面・業務面的前提、限制條件(預算・交期・既有資產・客戶環境)、
以及曾經考慮過的選項。

## 決定

以「要~」的主動語態明確斷言。1〜3句。

## 結果

同時寫出這個決定帶來的好處與壞處(取捨)。
若有將來重新檢視這個決定的契機或條件,也一併寫上。

狀態欄位只寫狀態本身也無妨,但建議採用像 已核准 (2026-07-17) 這樣附上狀態變更日期的寫法。第7章的實例也採用這種格式。既然要作為只能新增的日誌來使用,「什麼時候核准的」「什麼時候被取代的」就和本文一樣是重要的資訊。要標記為已被取代時,可以像 已被取代 (2026-08-20) ── 由 ADR-0007 取代 這樣,把日期與取代對象放進同一行。請在專案內統一採用其中一種寫法。

重點在於「結果」欄要連壞處也一併寫出來。沒有取捨的決定,幾乎沒有記錄的價值。Microsoft的指引也強調,不論是刻意或偶然,都不應該隱瞞決定所帶來的後果,而沒有依據的記錄會隨著時間流逝而失去價值。2

4. ADR該寫什麼、不該寫什麼

ADR無法持續下去的最大原因,是「什麼都想寫」。Microsoft的指引指出,值得記錄的僅限於會影響系統結構或重要品質特性、以及難以回頭的事項2 把這一點套用到日常判斷上,就會得到下表。

決定的類型 範例 是否寫進ADR 理由
事後難以變更的技術選型 資料庫採用SQLite、通訊採用檔案交換 要寫 變更成本高,不知理由就動手很危險
從多個合理選項中做出的選擇 報表採用函式庫產生而非COM連接 要寫 「為什麼捨棄另一個」能縮短接手者重新檢討的時間
受限制條件左右的決定 因客戶環境為離線狀態而放棄自動更新 要寫 限制條件消失時(環境更新時)可以重新檢視
與外部的約定 CSV的文字編碼・版面配置配合對方規格 要寫 可以明確標示這是自家公司無法單方面變更的邊界
規約・風格的統一 命名規則、格式化工具、using排序 不寫 .editorconfig 等設定檔加自動化就足夠
隨時可以變更的實作細節 內部類別的切分、private方法的組成 不寫 用程式碼與程式碼審查就足夠
例行性的維運作業 函式庫的修補版本更新 不寫 用變更歷史(commit log)就足夠

猶豫不決時的判斷基準只有一個:「1年後看到這段程式碼的人(包括自己在內)會不會想問『為什麼?』」。會想問就寫,只要看程式碼或設定就一目瞭然的話就不寫。

另一個陷阱,是用「文件的種類」去思考該寫多細。事先像下面這樣決定好角色分工,就不會猶豫。

想留下的資訊 適合的地方 與ADR的關係
為什麼選擇這個方式 ADR 主體
目前的架構圖・資料流向 設計文件(精簡版) 從ADR參照過去
個別變更的內容 Commit訊息 / PR 寫上ADR編號建立關聯
操作步驟 操作手冊 屬於不同性質的文件(讀者不同)。寫法可參考「製作手冊時要先打好底的 Word 基本 - 以壞習慣與最佳實務並列整理
故障處理的記錄 故障單・issue 若處理結果導致方式變更,則另立ADR

5. 小規模委託開發中的運用

5.1 目錄與檔案名稱

在儲存庫的根目錄下建立 docs/adr/,以「連續編號+簡短slug」的方式存放。Slug指的是用小寫英文字母與連字號、簡短表達內容的字串(像 use-sqlite-for-local-storage 這樣的形式)。因為會被當作檔案名稱或URL的一部分使用,所以要避開空白、日文與符號,維持機器容易處理的形式,這是一種約定。

docs/
  adr/
    0001-record-architecture-decisions.md
    0002-use-sqlite-for-local-storage.md
    0003-excel-report-via-com-automation.md
    0007-excel-report-via-openxml-library.md

這個範例中之所以缺少 00040006,是因為它們被用於其他決定(例如驗證方式或記錄設計等)。0007 是取代 0003 方式的決定,但不會因此把編號往前擠,也不會重複使用 0003。連續編號只是按決定發生的順序遞增而已,有缺號才是正常狀態。

第一件通常會是「決定要使用ADR」這件事本身的ADR。這樣一來,接手的人只要看 docs/adr/,就能連同運用規則一起理解。

5.2 何時撰寫、由誰審查

  • 撰寫的時機是「決定之後立刻」。作為設計討論的收尾,把會議的結論當天就寫成ADR。後面會提到,累積起來事後才寫會失敗。
  • 把ADR納入程式碼審查。只要檢查涉及方式的變更之PR裡,是否包含ADR的新增・更新即可。不需要ADR專用的核准會議,把它變成審查的一部分,是小規模團隊的現實解法。將ADR置於版本控制之下,這一點Microsoft的指引也建議如此。2
  • 要推翻決定時,撰寫新的ADR,並把舊ADR的狀態改為Superseded,兩者互相參照。本文不會被改寫。不編輯已核准的記錄,而是靠一連串的取代來保留歷史──這就是把ADR當作「只能新增的日誌」來對待。2

5.3 作為與發包方共享成果物的ADR

在委託開發中,建議把ADR當作交付物的一部分,與發包方共享。這麼做有3個效果。

  1. 可以作為驗收・說明的材料。不必用口頭說明「為什麼是這種架構」,只要出示ADR就夠了。以限制條件(預算・交期・環境)為決定關鍵的決定,發包方本身正是當事人,有記錄在,可以避免日後認知落差。
  2. 成為供應商更換時的保險。站在發包方的立場,是否有能交給下一家廠商的「判斷歷史」,會大幅左右交接的成本與風險。發包前的整理,正如「委外・委託開發 Windows 應用程式前該整理的事項」中所寫,但在簽約時決定「交付後要留下什麼文件」時,ADR屬於投資報酬率最高的一類。
  3. 與準委任的報告制度相性良好。準委任合約要求業務執行的報告,設計階段的報告可以直接沿用ADR。

5.4 所需時間的實際感受

依筆者的經驗,依照範本寫1件大約需要15〜30分鐘。小規模案件的決定頻率大概是每月數件,所以只要每月投入1〜2小時,就能把所有「為什麼」都留下來。與幾年後為了調查・重新檢討・交接而耗費的時間相比,幾乎沒有不划算的現場。

6. 常見的失敗

失敗模式 症狀 對策
寫太多 連瑣碎的決定都寫成ADR,3週就精疲力盡 用第4章的判斷表篩選對象。每月數件才正常
範本過於厚重 附有核准欄・影響分析・風險評估的格式,沒有人願意寫 回歸只用Nygard的5個要素。上限1〜2頁1
寫在Wiki裡 與程式碼分處不同地方,更新停止,逐漸脫節而失去信任 放在儲存庫內,與PR一起審查
事後才彙整撰寫 「等告一段落再寫」→記憶已消失,寫不出來 決定之後立刻寫。若寫不出來,就在做決定的當下邊共享畫面邊寫
改寫過去的ADR 歷史消失,搞不清楚「方針是什麼時候變的」 以Superseded方式取代,本文保持不變2
不寫結果(壞處) 淪為單純的決定通知,對重新檢討沒有幫助 一定要寫出取捨與「重新檢視的條件」

特別是「事後才彙整撰寫」,是在既有系統中途導入ADR時容易掉入的陷阱。不要試圖把過去所有的決定都還原,現實的做法是只針對已知的主要決定回溯寫幾件,之後再從今天以後的決定開始逐步累積。即使是既有(棕地)系統,只要有已掌握的過去決定,回溯記錄下來仍然有價值。2

7. ADR的實例

以小規模Windows業務應用程式中常見的題材,展示2份實際ADR全文的樣貌(內容為一般化後的範例)。

第1份是技術選型中的經典題材——資料庫的決定。

# ADR-0002:業務資料的儲存位置改用SQLite

## 狀態

已核准 (2026-07-17)

## 背景

本系統為單一據點的庫存管理桌面應用程式。使用者有2〜3名,但實際運用上是
安裝在辦公室主要負責人的1台PC上,輪流使用(同時使用僅1人)。
客戶公司內部沒有能夠運維資料庫伺服器的人員,也沒有導入伺服器主機的預算。
資料量預估即使運作10年也只有數百MB左右。
考慮過的選項有 SQL Server Express / SQLite / Access檔案(.accdb)。
SQL Server Express因客戶端沒有能持續進行伺服器建置與Windows Update後
運作確認的體制而放棄採用。Access則考量到同時更新時的損毀風險
與未來的可遷移性而放棄採用。

## 決定

資料儲存採用SQLite。DB檔案不放在共用資料夾,而是放在主要負責人PC的
本機端。備份方式為每日以VACUUM INTO建立快照並儲存到NAS
(在運作中對主檔進行OS層級的檔案複製是不允許的,因為會遺漏WAL檔案中
尚未反映的內容,或因寫入競爭而產生損毀的備份)。

## 結果

- 好處:不需要建置・維護資料庫伺服器。備份也只要1道SQL指令就能完成
- 好處:應用程式發布時可以內含執行環境(runtime),安裝變得單純
- 壞處:寫入會變成以DB為單位的鎖定,無法擴展到多據點・多人數的情境
- 壞處:未來若要遷移到伺服器DB,需要進行資料遷移與連線層的改造
- 一旦需要從多台PC同時使用,就要重新檢視這個決定(屆時將改為伺服器DB或透過API的架構)

這個範例中出現的SQLite專用術語,在此補充說明。VACUUM INTO是一種SQL陳述式,會將運作中資料庫的邏輯內容原封不動地寫出到另一個檔案,SQLite官方文件中也將它定位為「為運作中的資料庫建立備份、作為備份API的替代手段」。4 WAL(Write-Ahead Logging,預寫日誌)是一種日誌方式,更新內容會先寫入與主檔分開的 -wal 檔案,之後才反映到主檔。在採用這種方式時,如果只用作業系統的檔案複製功能,在運作中把主要的 .db 檔案取出,-wal 側尚未反映的更新就會遺漏,變成不完整的備份。ADR-0002的「決定」之所以特地連備份方法都寫進去,正是因為這個陷阱與決定本身密不可分。

第2份是推翻曾經做過的決定的範例。請一併留意Superseded的用法。

# ADR-0007:報表的Excel輸出改用函式庫產生,不再使用COM連接

## 狀態

已核准 (2026-07-17) ── 取代 ADR-0003(採用COM自動化)

## 背景

有以Excel檔案輸出交貨單與月結彙總的需求。
最初依照ADR-0003以Excel的COM自動化實作,但在無人執行的
夜間批次作業中,反覆發生Excel處理序殘留導致處理停止的情況,
執行用PC需要Office授權這一點,也在每次更換機台時造成問題。
考慮過的選項有:繼續使用COM連接(加上處理序監控)/
改用直接產生Open XML格式的函式庫 /
將報表改為PDF化(規格變更)。PDF化因為往來對象是以在Excel中
追加填寫為前提,所以不可行。

## 決定

報表改為以函式庫直接產生.xlsx的方式。
不依賴Excel本體。格式以範本.xlsx的形式包含在儲存庫中,
以儲存格套用資料的方式產生。

## 結果

- 好處:執行環境不再需要Excel,無人執行變得穩定
- 好處:處理序殘留的問題在結構上消失
- 壞處:無法使用Excel的全部功能,既有報表的部分格式需要簡化
- 壞處:既有報表範本化需要花費改造工時
- ADR-0003標記為Superseded,並附上指向本ADR的參照

相信只要讀完這2份,就能回答交接時必定會出現的疑問——「這個系統為什麼沒有伺服器DB」「為什麼報表程式碼裡有啟動Excel的痕跡」。兩份加起來也只有大約1,500字左右,寫起來不到1小時。

8. 總結

  • 在維護・交接時失去了會讓人困擾的不是What,而是Why。沒有被記錄下來的決定會被遺忘,招致討論重演與違背意圖的變更。2
  • ADR是1個決定=1個檔案、5個要素、1〜2頁以內的輕量記錄格式。完全依照Nygard的原型,就能直接用在小規模開發上。1
  • 只寫「難以變更」「曾有選項」「受限制條件左右」的決定。規約與格式交給自動化處理,不列入ADR的對象。2
  • 存放位置為docs/adr/,審查與PR一起進行。決定不覆寫,而是以Superseded取代,讓歷史保持不變。12
  • 在委託開發中,ADR會成為驗收的說明資料、供應商更換時的交接資料,是對發包方也有價值的交付物
  • 1件15〜30分鐘。請先從下一個設計判斷開始寫1份,若是既有系統,則從已知的主要決定中回溯寫幾份開始。

相關文章

相關諮詢領域

合同會社小村軟體提供設計審查中的ADR導入支援、既有系統設計判斷的盤點與文件化、以及著眼於交接・供應商更換的維護體制建置等服務。

參考連結

  1. Michael Nygard,Documenting Architecture Decisions。ADR的原典(2011年)。內容涵蓋標題/背景/決定/狀態/結果這5個要素、提案中→已核准→廢止/已被取代的狀態流程、1〜2頁的份量、以連續編號檔案的形式存放於儲存庫中,以及不刪除舊決定而以Superseded等方式保留的做法。  2 3 4 5 6 7

  2. Microsoft Learn,Maintain an architecture decision record (ADR)。Azure Well-Architected Framework的指引。內容涵蓋將ADR視為只能新增的日誌、不編輯已核准的記錄,變更時以新記錄取代並互相連結,將對象限定於會影響系統結構・重要品質特性且難以回頭的決定,應包含背景與依據・取捨・狀態(Proposed/Accepted/Superseded),沒有被記錄的決定會被遺忘並招致討論重演與違背意圖的變更,以及即使是既有工作負載也有回溯記錄的價值。  2 3 4 5 6 7 8 9 10 11 12 13 14

  3. adr.github.io,Architectural Decision Records。ADR的社群網站。內容涵蓋架構上的決定(AD)與架構上重要的需求(ASR)的定義、ADR是記錄單一決定及其依據・取捨・後果的文件這一性質,以及各類範本與工具的整理。  2

  4. SQLite,VACUUM。說明附加INTO子句的VACUUM會在不變更原始檔案的情況下,將相同的邏輯內容寫出到新的資料庫檔案,以及作為建立運作中資料庫備份的手段、可替代備份API的用法。 

共用相同標籤的最新文章。能以相近的主題延伸理解。

與本文相近的主題頁面。以本文為起點,可進一步連到相關服務與其他文章。

本文連結到以下服務頁面,歡迎從最接近的入口查看。

常見問題

整理諮詢這個主題時常見的問題。

什麼是ADR(Architecture Decision Record)?
這是一種將與軟體結構相關的1個決定,以「標題/狀態/背景/決定/結果」這種簡短的固定格式記錄成1個檔案的文件。這是Michael Nygard在2011年提出的輕量格式,基本原則是每件控制在1〜2頁以內,並以Markdown的形式與程式碼一起提交到相同的儲存庫。與涵蓋一切的設計文件不同,它專門用來留下「為什麼做了這個選擇」與「捨棄了哪些選項」。
ADR該寫什麼,又不需要寫什麼?
該寫的是事後難以變更的決定(資料庫或通訊方式的選型、外部連接的格式等)、從多個合理選項中做出的決定,以及以預算・交期・既有資產等限制條件為決定關鍵的決定。反之,像命名規則或格式化工具設定這種可以透過工具或規約機械式統一的事項,以及容易變更、只要讀程式碼就足夠理解的事項,就不需要寫。猶豫不決時,以「1年後的自己會不會想問『為什麼?』」作為判斷基準。
想要變更決定時,可以改寫過去的ADR嗎?
不能改寫,而是新增一份新的ADR來取代。舊的ADR要把狀態改為Superseded(已被取代),並附上指向新ADR的參照,本文則維持原樣保留。Microsoft的指引也建議,ADR應被視為只能新增的日誌,不應事後編輯已核准的記錄。這樣一來,「什麼時候・為什麼方針改變了」這段歷史本身,就會成為交接資料。
如果有設計文件,是不是就不需要ADR了?
兩者的角色不同。設計文件呈現的是「目前是什麼結構(What)」,但通常不會留下「為什麼選擇了這個結構、捨棄了什麼(Why)」。而且涵蓋一切的設計文件容易停止更新,數年後往往會與程式碼脫節。ADR只是每次決定時新增幾百字,因此不容易停止更新,即使設計文件過時了,「判斷的理由」依然能存活下來。在小規模開發中,將詳細設計文件精簡化、搭配ADR併用的架構才是現實的做法。

作者檔案

本文作者的個人檔案頁面。

Go Komura

小村軟體有限公司 代表

以 Windows 軟體開發、技術諮詢與故障調查為中心,在難以重現的故障調查與既有資產仍在運作的專案上具有優勢。

回到部落格一覽