Hướng dẫn · 29/09/2026

Hướng dẫn viết Architecture Decision Record để quyết định kiến trúc không thất lạc

Mã nguồn cho biết hệ thống đang được xây như thế nào, nhưng hiếm khi cho biết vì sao một phương án được chọn và những lựa chọn nào đã bị loại. Sau vài tháng, thành viên mới có thể nhìn một hàng đợi, một database riêng hay một giới hạn timeout và cho rằng đó là thiết kế tùy tiện. Architecture Decision Record (ADR) lưu lại bối cảnh, lực kéo, phương án, quyết định và hệ quả tại thời điểm nhóm cam kết.

Hướng dẫn viết Architecture Decision Record để quyết định kiến trúc không thất lạc

Mã nguồn cho biết hệ thống đang được xây như thế nào, nhưng hiếm khi cho biết vì sao một phương án được chọn và những lựa chọn nào đã bị loại. Sau vài tháng, thành viên mới có thể nhìn một hàng đợi, một database riêng hay một giới hạn timeout và cho rằng đó là thiết kế tùy tiện. Architecture Decision Record (ADR) lưu lại bối cảnh, lực kéo, phương án, quyết định và hệ quả tại thời điểm nhóm cam kết.

ADR không phải tài liệu kiến trúc đồ sộ cần cập nhật từng sơ đồ. Một bản ghi tốt thường ngắn, gắn với một quyết định có ý nghĩa và nằm gần code để thay đổi qua review. Mục tiêu không phải chứng minh người viết đúng mãi mãi, mà giúp người sau hiểu điều kiện ban đầu, biết khi nào giả định không còn đúng và thay thế quyết định một cách có chủ đích.

1. Những quyết định nào đáng có ADR?

Không cần ADR cho tên biến, thư viện tiện ích nhỏ hoặc lựa chọn dễ đảo ngược trong vài phút. Hãy ghi khi quyết định ảnh hưởng nhiều nhóm, khó thay đổi, tạo ràng buộc vận hành, liên quan bảo mật/tuân thủ hoặc có trade-off mà người hợp lý có thể chọn khác.

  • Chọn database, broker, cloud service hoặc mô hình lưu trữ chủ đạo.
  • Xác định ranh giới module/service và quyền sở hữu dữ liệu.
  • Chọn consistency model, retry, idempotency hoặc chiến lược cache.
  • Thiết lập chuẩn authentication, authorization, encryption và retention.
  • Quy định runtime, deployment, observability hoặc compatibility policy.

Một heuristic hữu ích: nếu sáu tháng sau ai đó có thể “tối ưu” ngược quyết định vì không biết constraint ban đầu, hãy viết ADR. Ngược lại, nếu chi phí ghi và review lớn hơn chi phí đổi lại, issue hoặc comment có thể đủ.

ADR lưu lý do và hệ quả của một cam kết; nó không phải biên bản cho mọi cuộc trò chuyện kỹ thuật.

2. Đặt ADR trong kho mã và dùng trạng thái rõ ràng

Với quyết định gắn trực tiếp một hệ thống, thư mục như docs/adr/ trong cùng repository giúp tài liệu đi qua pull request, ownership và lịch sử Git. Tổ chức nhiều repository có thể giữ ADR xuyên hệ thống ở một kho kiến trúc riêng, nhưng phải liên kết từ code và có quy trình review tương đương. Đừng để tài liệu chỉ tồn tại trong chat, email hoặc trang cá nhân khó tìm.

Tên file nên ổn định, ví dụ 0007-use-transactional-outbox.md. Số thứ tự giúp tham chiếu mà không phụ thuộc tiêu đề. Trạng thái tối thiểu thường gồm:

Trạng tháiÝ nghĩa
ProposedĐang xin phản hồi; chưa phải cam kết để triển khai
AcceptedĐã thống nhất và đang có hiệu lực
RejectedĐã xem xét nhưng không chọn
DeprecatedKhông còn khuyến nghị cho phần mới nhưng có thể vẫn tồn tại
SupersededĐược thay thế bởi ADR khác; cần liên kết hai chiều

Không sửa lịch sử để giả vờ quyết định cũ chưa từng tồn tại. Nếu bối cảnh thay đổi đáng kể, tạo ADR mới và đánh dấu bản cũ là superseded. Sửa typo hoặc làm rõ câu chữ không đổi nghĩa thì có thể cập nhật qua review bình thường.

3. Một template ngắn nhưng đủ thông tin

# ADR-0007: Dùng transactional outbox cho sự kiện đơn hàng

- Status: Proposed
- Date: 2026-09-27
- Owners: Order Platform
- Decision scope: order write path

## Context
Vấn đề, constraint, dữ liệu đo và giả định hiện tại.

## Decision drivers
- Điều gì phải tối ưu hoặc bảo vệ?

## Considered options
1. Ghi trực tiếp database rồi publish.
2. Transactional outbox.
3. Distributed transaction.

## Decision
Chọn gì, phạm vi nào, điều kiện và ngoại lệ nào.

## Consequences
Tác động tích cực, tiêu cực, rủi ro và công việc bắt buộc.

## Validation
Metric, test, checkpoint và ngày xem xét lại.

## References
Issue, benchmark, diagram, incident, ADR liên quan.

Template là điểm tựa, không phải biểu mẫu bắt buộc điền dài. Bỏ mục không liên quan, nhưng đừng bỏ context, options, decision và consequences. Nếu người đọc chỉ thấy “chọn PostgreSQL vì ổn định”, ADR chưa giải thích workload, đội ngũ, yêu cầu transaction, lựa chọn thay thế hay giới hạn của kết luận.

4. Viết bối cảnh bằng constraint và bằng chứng

Bối cảnh tốt mô tả vấn đề tại thời điểm quyết định: traffic, kích thước dữ liệu, latency target, kỹ năng vận hành, ngân sách, compliance, dependency và deadline. Tách dữ kiện khỏi giả định. “P95 hiện là 900 ms với 2.000 request/phút” là dữ kiện; “traffic sẽ tăng gấp mười” là giả định cần nguồn và ngày kiểm tra.

Tránh viết lại toàn bộ lịch sử dự án. Người đọc cần hiểu lực kéo khiến quyết định khó. Nếu benchmark quyết định hướng đi, liên kết script, dataset và môi trường chạy; chỉ dán con số không thể tái hiện sẽ nhanh chóng mất giá trị. Nếu incident là nguyên nhân, liên kết postmortem đã loại bỏ dữ liệu nhạy cảm.

5. So sánh phương án công bằng

Mỗi phương án cần được mô tả ở mức đủ để đánh giá cùng tiêu chí. Đừng dựng một lựa chọn yếu để hợp thức hóa kết quả đã định. Tiêu chí có thể gồm correctness, độ trễ, availability, cost, lock-in, khả năng vận hành, thời gian triển khai và đường thoát.

  • Do nothing: thường là phương án hợp lệ và làm rõ chi phí của thay đổi.
  • Build: kiểm soát cao nhưng phải tính maintenance, on-call và nâng cấp.
  • Buy/managed: giảm vận hành một phần nhưng tăng dependency và chi phí chuyển đổi.
  • Phased option: thử nghiệm giới hạn trước khi cam kết toàn bộ.

Ma trận điểm có thể hỗ trợ thảo luận nhưng không biến judgment thành toán học tuyệt đối. Ghi trọng số, dữ liệu và độ không chắc chắn. Một phương án có tổng điểm cao nhưng vi phạm constraint bắt buộc vẫn không hợp lệ.

6. Câu “Decision” phải kiểm thử được

Quyết định cần nói rõ chọn gì, phạm vi nào, khi nào áp dụng và điều kiện ngoại lệ. “Chúng ta dùng cache” quá mơ hồ. Tốt hơn: “API catalog dùng Redis cache-aside cho response công khai, TTL tối đa 60 giây; dữ liệu giá không dùng cache này; khi Redis lỗi, request đọc database với concurrency limit.” Câu đó cho phép code review và test xác định triển khai có tuân thủ hay không.

Nếu rollout theo giai đoạn, ghi checkpoint: proof of concept, canary, ngưỡng latency/cost, kill switch và người quyết định mở rộng. ADR không thay thế kế hoạch triển khai, nhưng phải liên kết đến kế hoạch và nêu điều kiện khiến lựa chọn được chấp nhận.

7. Ghi cả hệ quả tiêu cực và công việc bắt buộc

Consequences không phải phần quảng cáo. Một database mới có thể cải thiện query nhưng đòi hỏi backup, monitoring, upgrade và kỹ năng on-call. Async messaging giảm coupling theo thời gian nhưng đưa vào duplicate, ordering và lag. Ghi những chi phí này tạo backlog thực tế và ngăn nhóm tuyên bố hoàn thành khi chỉ merge code.

Phân biệt ba loại: hệ quả chấp nhận được; rủi ro cần giảm thiểu; và điều kiện làm quyết định mất hiệu lực. Ví dụ, chọn SQLite cho single-node deployment có thể đúng cho đến khi yêu cầu multi-writer xuất hiện. Đưa trigger đó vào ADR giúp review sau này dựa trên bối cảnh thay vì sở thích.

8. Quy trình review gọn và có owner

  1. Tác giả mở ADR ở trạng thái Proposed cùng issue mô tả deadline quyết định.
  2. Reviewer đại diện development, operations, security hoặc data theo phạm vi tác động.
  3. Câu hỏi và phản biện được giải quyết trong pull request hoặc cuộc họp có kết luận đưa lại vào ADR.
  4. Người có thẩm quyền cập nhật Accepted/Rejected và ngày quyết định.
  5. Implementation link ngược về ADR; checklist hậu kiểm xác nhận consequence đã được xử lý.

Không yêu cầu hội đồng lớn cho mọi ADR. Dùng mức review tương xứng blast radius. Một thay đổi module nội bộ có thể cần hai reviewer; thay đổi identity toàn công ty cần security, platform và chủ sở hữu sản phẩm. Quan trọng là biết ai ra quyết định khi không đồng thuận, tránh tài liệu treo Proposed vô thời hạn.

9. Giữ ADR sống mà không viết lại lịch sử

ADR không cần cập nhật mỗi sprint, nhưng repository nên có index hiển thị status, owner và ADR thay thế. Link checker ngăn reference hỏng; linter có thể kiểm tra front matter và ID trùng. Architecture test hoặc policy-as-code có thể bảo vệ quyết định kiểm thử được, chẳng hạn module A không import trực tiếp module B hoặc image production phải pin digest.

Đặt review trigger thay vì lịch máy móc: incident cho thấy giả định sai, chi phí vượt ngưỡng, vendor ngừng dịch vụ, tải thay đổi lớn hoặc một dự án sắp đi ngược ADR. Review không có nghĩa tự động đổi quyết định; kết quả có thể xác nhận ADR vẫn đúng và cập nhật evidence bằng một note liên kết.

10. Các anti-pattern thường gặp

  • ADR sau khi đã làm xong: tài liệu chỉ hợp thức hóa, không còn giúp quyết định.
  • Chỉ ghi phương án thắng: người sau không biết lựa chọn khác đã được cân nhắc chưa.
  • Không có consequence: chi phí vận hành và migration bị bỏ quên.
  • Một ADR cho cả chương trình: quá rộng, không thể thay thế từng quyết định.
  • Sửa accepted ADR âm thầm: làm mất lịch sử và đánh lừa người đọc.
  • ADR như mệnh lệnh vĩnh viễn: bỏ qua thay đổi của constraint và dữ liệu mới.

Checklist trước khi chấp nhận ADR

  • Tiêu đề mô tả một quyết định, không chỉ tên công nghệ.
  • Context có dữ kiện, constraint và giả định kèm thời điểm.
  • Ít nhất các phương án thực tế và “không đổi” đã được xem xét.
  • Decision nêu phạm vi, ngoại lệ và đủ rõ để review triển khai.
  • Consequences ghi cả lợi ích, chi phí, rủi ro và công việc theo sau.
  • Owner, status, date, reference và trigger xem xét lại đã rõ.
  • ADR không chứa secret, token hoặc dữ liệu cá nhân.

Kết luận

Architecture Decision Record là bộ nhớ có cấu trúc cho những lựa chọn khó đổi. Một ADR tốt không cần dài; nó cần trung thực về bối cảnh, công bằng với phương án, cụ thể về quyết định và rõ ràng về hệ quả. Khi được lưu gần code, đi qua review và được thay thế thay vì viết lại, ADR giúp đội ngũ tránh lặp lại tranh luận cũ, onboarding nhanh hơn và biết chính xác điều kiện nào cho phép kiến trúc tiến hóa.

Thảo luận

Bình luận 0

Đăng nhập để bình luận

Bạn cần có tài khoản để tham gia thảo luận và trả lời độc giả khác.

Đăng nhậpĐăng ký

Chưa có bình luận. Hãy là người đầu tiên chia sẻ ý kiến.