Mở đầu — vì sao bài này quan trọng
Hãy tưởng tượng bạn vừa gia nhập một team đang vận hành hệ thống core của một sàn thương mại điện tử. Tháng đầu tiên, bạn hỏi anh kiến trúc sư trưởng: "Tại sao mình lại dùng Kafka thay vì gọi API trực tiếp giữa Order Service và Inventory Service?" Anh ấy ngập ngừng vài giây rồi nói: "Ờ... hồi đó có lý do, nhưng mình quên rồi, để hỏi lại người làm trước." Người làm trước đã nghỉ việc hai năm. Không ai còn nhớ chính xác vì sao quyết định đó được đưa ra, đánh đổi gì, đã loại bỏ phương án nào. Kết quả: cả team sống chung với một quyết định mà không ai dám đụng vào vì sợ phá vỡ thứ gì đó "có lý do của nó".
Đây là một trong những nỗi đau âm thầm nhất của ngành phần mềm: kiến thức về lý do đằng sau quyết định kiến trúc bị bốc hơi theo thời gian. Code thì còn đó, tài liệu kỹ thuật (tech spec) mô tả cách hệ thống hoạt động cũng còn đó, nhưng cái tại sao — bối cảnh, ràng buộc, các phương án đã cân nhắc và bị loại — thì biến mất cùng với người ra quyết định.
Architecture Decision Record (ADR) chính là công cụ để chống lại sự bốc hơi đó. Và với vai trò Technical BA, đây là một trong những tài sản tài liệu giá trị nhất bạn có thể tạo ra. Vì sao? Vì BA là người đứng giữa business và kỹ thuật — bạn nắm bối cảnh nghiệp vụ, hiểu ràng buộc, và thường là người duy nhất có cái nhìn xuyên suốt từ "vì sao business cần" đến "kỹ thuật quyết định thế nào". Bạn không nhất thiết là người đưa ra quyết định kiến trúc, nhưng bạn rất thường là người ghi lại nó một cách có hệ thống. Bài này sẽ dạy bạn làm điều đó cho đúng.
Khái niệm cốt lõi
ADR là gì và không phải là gì
ADR (Architecture Decision Record) là một tài liệu ngắn — thường chỉ một trang — ghi lại một quyết định kiến trúc quan trọng, cùng với bối cảnh dẫn đến quyết định đó và hệ quả của nó. Khái niệm này được Michael Nygard phổ biến năm 2011 và nhanh chóng trở thành chuẩn de-facto trong nhiều tổ chức kỹ thuật trên thế giới.
Điểm mấu chốt cần khắc ghi ngay: ADR ghi lại WHY (vì sao), không phải HOW (như thế nào). Cái HOW thuộc về tech spec, về API documentation, về sequence diagram. ADR trả lời câu hỏi: "Tại sao chúng ta chọn phương án này thay vì các phương án khác, trong bối cảnh nào, và chấp nhận đánh đổi gì?"
Để dễ phân biệt:
- Tech spec nói: "Order Service publish event
OrderCreatedlên topic Kafkaorders.v1, Inventory Service consume và giảm tồn kho." - ADR nói: "Chúng ta chọn giao tiếp bất đồng bộ qua message queue thay vì gọi API đồng bộ, vì cần chịu được tình huống Inventory Service down mà vẫn nhận đơn, và chấp nhận đánh đổi là tồn kho có độ trễ vài giây (eventual consistency)."
Một quyết định "đáng" ghi ADR là quyết định như thế nào
Không phải mọi quyết định đều cần ADR. Nếu ghi tất tần tật, ADR sẽ thành rác và không ai đọc. Một quyết định xứng đáng có ADR khi nó architecturally significant — tức là khó đảo ngược, ảnh hưởng rộng, hoặc tốn kém nếu chọn sai. Dấu hiệu nhận biết:
- Ảnh hưởng đến nhiều team hoặc nhiều service.
- Khó hoặc tốn kém để thay đổi sau này (chọn database, chọn message broker, chọn pattern giao tiếp).
- Liên quan đến đánh đổi rõ rệt (chi phí vs hiệu năng, đơn giản vs linh hoạt, bảo mật vs trải nghiệm).
- Có thể gây tranh cãi — sẽ có người sau này hỏi "sao không làm cách kia?".
Cấu trúc một ADR chuẩn (theo Nygard)
Một ADR điển hình gồm các phần sau, đặt trong một file Markdown:
ADR-001: Chọn message queue cho giao tiếp giữa Order và Inventory
Status (Trạng thái)
Accepted — 2026-03-15Context (Bối cảnh)
Mô tả vấn đề, ràng buộc, áp lực kỹ thuật/nghiệp vụ
dẫn đến việc phải ra quyết định. Viết trung lập,
chưa thiên về phương án nào.Decision (Quyết định)
"Chúng ta sẽ..." — nêu rõ quyết định, viết ở thể chủ động.Consequences (Hệ quả)
Cả mặt tích cực lẫn tiêu cực. Sau khi chọn phương án này,
thế giới của chúng ta thay đổi ra sao — cái gì dễ lên,
cái gì khó đi.Alternatives Considered (Các phương án đã cân nhắc)
Liệt kê phương án bị loại và lý do loại — đây là phần
giá trị nhất nhưng hay bị bỏ quên.
Hãy chú ý phần Status. Vòng đời của một ADR thường là: Proposed (đề xuất) → Accepted (chấp nhận) → có thể về sau thành Deprecated (lỗi thời) hoặc Superseded by ADR-XXX (bị thay thế bởi ADR khác). Một nguyên tắc vàng: ADR là bất biến (immutable). Khi đã Accepted, bạn không sửa nội dung cũ. Nếu quyết định thay đổi, bạn viết một ADR mới và đánh dấu ADR cũ là Superseded. Lý do: bản thân lịch sử thay đổi quyết định cũng là kiến thức quý — nó cho thấy team đã học được gì.
Vì sao Technical BA nên quan tâm
Có ba lý do rất thực tế:
- BA là người giữ bối cảnh. Phần Context của ADR — vốn là phần khó viết nhất với dev — lại chính là thứ BA làm hằng ngày: hiểu ràng buộc business, SLA cam kết với khách hàng, quy định pháp lý, ngân sách. Dev biết viết phần Decision, nhưng phần Context thường cần BA.
- ADR là vũ khí chống "knowledge silo". Khi nhân sự nghỉ việc — điều cực kỳ phổ biến ở thị trường IT Việt Nam với tỷ lệ nhảy việc cao — ADR giúp người mới hiểu hệ thống trong vài giờ thay vì vài tuần.
- ADR là cầu nối khi audit và compliance. Trong các dự án ngân hàng, fintech, khi đoàn kiểm toán hỏi "vì sao hệ thống lưu dữ liệu thẻ theo cách này?", một bộ ADR rõ ràng là bằng chứng cho thấy quyết định được cân nhắc có trách nhiệm.
Tình huống thực tế
Tình huống 1: Sàn TMĐT chọn eventual consistency cho tồn kho
Một sàn thương mại điện tử tại Việt Nam (tạm gọi ShopFast) đang dùng kiến trúc monolith, mọi thao tác đặt đơn đều gọi đồng bộ tới module tồn kho trong cùng một transaction. Vào dịp sale 12/12, lượng truy cập tăng gấp 40 lần, module tồn kho trở thành nút thắt cổ chai, toàn hệ thống đặt đơn sập theo. Mỗi phút downtime ước tính mất khoảng 180 triệu đồng doanh thu.
Team quyết định tách Order và Inventory thành hai service, giao tiếp bất đồng bộ qua message queue. BA của dự án — người nắm rõ con số thiệt hại và cam kết SLA "99.9% uptime trong giờ cao điểm" — ngồi cùng kiến trúc sư viết ADR-014:
- Context: Mô tả sự cố 12/12, con số thiệt hại 180 triệu/phút, yêu cầu nghiệp vụ "phải nhận đơn được kể cả khi tồn kho chậm".
- Decision: Dùng giao tiếp async, chấp nhận eventual consistency cho số lượng tồn kho.
- Consequences: Tích cực — hệ thống chịu tải tốt hơn, Order độc lập với Inventory. Tiêu cực — có thể oversell (bán quá số lượng) trong cửa sổ vài giây, cần thêm cơ chế bù trừ và quy trình xử lý đơn vượt tồn.
- Alternatives: Đã cân nhắc tăng cứng tài nguyên (vertical scaling) — bị loại vì chi phí cao và vẫn có trần. Đã cân nhắc giữ đồng bộ nhưng dùng cache — bị loại vì không giải quyết được gốc rễ nút thắt.
Tình huống 2: Ngân hàng số chọn lưu OTP ở Redis thay vì database
Một ngân hàng số (tạm gọi VBank Digital) cần lưu mã OTP cho giao dịch chuyển tiền. Team có hai lựa chọn: lưu ở database chính (PostgreSQL) hay lưu ở Redis với TTL (thời gian sống) tự động hết hạn.
BA phụ trách phần authentication viết ADR-008:
- Context: OTP có vòng đời ngắn (90 giây), tần suất ghi/đọc cực cao trong giờ cao điểm, và yêu cầu compliance là OTP không được tồn tại sau khi hết hạn.
- Decision: Lưu OTP ở Redis với TTL 90 giây, không lưu ở database chính.
- Consequences: Tích cực — giảm tải database chính, OTP tự xóa, đáp ứng yêu cầu không lưu trữ dữ liệu nhạy cảm lâu dài. Tiêu cực — nếu Redis mất dữ liệu (restart không bền vững), một số OTP đang chờ sẽ mất, người dùng phải yêu cầu lại; cần Redis cấu hình cụm có dự phòng.
- Alternatives: Lưu ở database chính — bị loại vì áp lực ghi quá lớn và phải tự xây cơ chế dọn dẹp dữ liệu hết hạn.
Tình huống 3: Startup logistics suýt mất kiến thức vì không có ADR
Một startup logistics ở TP.HCM (tạm gọi GiaoNhanh) tăng trưởng nhanh, team kỹ thuật từ 3 lên 25 người trong một năm. Họ không viết ADR. Khi CTO sáng lập nghỉ, không ai biết vì sao hệ thống định tuyến đơn hàng lại dùng thuật toán "gán tài xế theo vùng cố định" thay vì "gán động theo khoảng cách thực".
Team mới cho rằng cách cũ là kém tối ưu nên đầu tư hai tháng làm lại theo khoảng cách động. Khi triển khai, chi phí gọi API bản đồ tăng vọt, và tệ hơn — đội vận hành phản ứng dữ dội vì cách "gán theo vùng" vốn là thỏa thuận với các nhà xe đối tác, mỗi nhà xe được giao một khu vực theo hợp đồng. Đây là ràng buộc business, không phải kỹ thuật. Hai tháng công sức đổ sông đổ biển.
Bài học: Chỉ cần một ADR ghi rõ "Decision: gán tài xế theo vùng cố định. Context: ràng buộc hợp đồng với nhà xe đối tác, mỗi đối tác độc quyền một khu vực" là đủ để ngăn toàn bộ thảm họa này. Đây cũng cho thấy giá trị riêng của BA: phần Context kỹ thuật thuần thường bỏ sót ràng buộc business, mà đó lại chính là nơi BA tỏa sáng.
Hướng dẫn từng bước
Đây là quy trình tạo một ADR mà bạn — với vai trò Technical BA — có thể chủ trì hoặc đồng hành cùng team:
Bước 1 — Nhận diện quyết định đáng ghi. Trong các buổi họp thiết kế, lắng nghe những câu như "chúng ta nên dùng A hay B?", "cái này khó đổi về sau đấy", "đánh đổi ở đây là...". Đó là tín hiệu cần ADR. Nếu nghi ngờ, hãy hỏi: "Sáu tháng nữa người mới vào có thắc mắc vì sao mình làm thế này không?" Nếu có, viết ADR.
Bước 2 — Đánh số và đặt tên. Dùng quy ước ADR-NNN: [động từ] [đối tượng], ví dụ ADR-015: Chọn JWT cho session người dùng. Đánh số tuần tự, không tái sử dụng số. Lưu file trong repo, thường ở thư mục docs/adr/.
Bước 3 — Viết phần Context trước, viết trung lập. Đây là phần bạn đóng góp nhiều nhất. Mô tả vấn đề, ràng buộc nghiệp vụ, SLA, ngân sách, quy định pháp lý, áp lực kỹ thuật. Quan trọng: chưa nhắc đến giải pháp. Người đọc phải tự thấy rằng "với bối cảnh này, đúng là phải ra quyết định gì đó".
Bước 4 — Ghi rõ Decision ở thể chủ động. Bắt đầu bằng "Chúng ta sẽ...". Một câu rõ ràng, không mơ hồ. Tránh viết "có lẽ chúng ta nên cân nhắc" — đã quyết thì viết dứt khoát.
Bước 5 — Liệt kê Consequences cả tốt lẫn xấu. Đây là phép thử độ trung thực. Nếu một ADR chỉ toàn hệ quả tích cực, gần như chắc chắn nó đang giấu đánh đổi. Hãy hỏi thẳng team: "Sau quyết định này, cái gì sẽ khó hơn?"
Bước 6 — Ghi lại Alternatives đã cân nhắc. Mỗi phương án bị loại kèm lý do loại. Phần này chính là thứ ngăn người sau lặp lại tranh luận cũ.
Bước 7 — Lấy đồng thuận và đổi Status thành Accepted. Cho team review (có thể qua pull request), đạt đồng thuận, ghi ngày và chuyển trạng thái. Khi quyết định thay đổi về sau, đừng sửa — viết ADR mới và đánh dấu cái cũ Superseded.
Lỗi thường gặp & mẹo
Lỗi 1 — Viết ADR thành tech spec. Sai lầm phổ biến nhất. Người viết sa đà mô tả schema, endpoint, từng bước triển khai. Nhớ: ADR là WHY, không phải HOW. Nếu thấy mình đang viết tên cột database, dừng lại — đó là tech spec.
Lỗi 2 — Bỏ quên phần Alternatives. Không có phương án bị loại thì người đọc không hiểu vì sao phương án được chọn lại tốt hơn. Một ADR không có Alternatives giống như một bản án không có lý do tuyên.
Lỗi 3 — Sửa ADR đã Accepted. Khi đổi ý, người ta hay vào sửa nội dung cũ. Điều này phá hủy lịch sử quyết định. Hãy luôn viết ADR mới và liên kết Superseded.
Lỗi 4 — Viết quá dài. ADR nên gói trong một trang. Nếu dài hơn, bạn đang nhồi nhét HOW vào hoặc gộp nhiều quyết định. Mỗi ADR — một quyết định.
Lỗi 5 — Chỉ toàn hệ quả tích cực. Như đã nói, đây là dấu hiệu của sự thiếu trung thực kỹ thuật. Mọi quyết định kiến trúc đều có giá.
Mẹo hay:
- Để ADR sống cùng code. Lưu trong cùng repo, review qua pull request. Documentation as code (chủ đề bài khác trong khóa) áp dụng rất hợp ở đây.
- Viết ngay khi quyết định còn nóng. Đừng để vài tuần — lúc đó bối cảnh đã phai. Lý tưởng là viết trong hoặc ngay sau buổi họp thiết kế.
- Dùng ngôn ngữ business trong Context. Đó là giá trị BA mang lại. "Mất 180 triệu/phút" thuyết phục hơn nhiều "hệ thống có vấn đề hiệu năng".
- Lập một index. Một file
README.mdtrong thư mục ADR liệt kê tất cả ADR cùng trạng thái, giúp người mới định hướng nhanh.
Bài tập thực hành
Bài 1 — Phân loại. Cho danh sách quyết định sau, đánh dấu cái nào đáng viết ADR: (a) đổi màu nút "Đặt hàng"; (b) chuyển từ REST sang gRPC cho giao tiếp nội bộ; (c) chọn lưu file ảnh trên S3 thay vì server cục bộ; (d) đặt tên biến trong một hàm; (e) chọn dùng soft-delete thay vì xóa cứng dữ liệu khách hàng. Giải thích lý do với từng mục.
Bài 2 — Viết một ADR hoàn chỉnh. Bối cảnh: công ty fintech của bạn cần quyết định lưu lịch sử giao dịch của khách hàng trong 10 năm theo quy định, nhưng database chính đang phình to và truy vấn chậm. Team cân nhắc: (1) giữ tất cả trong DB chính; (2) chuyển dữ liệu cũ hơn 1 năm sang kho lưu trữ lạnh (cold storage) rẻ hơn; (3) nén và lưu dạng file. Hãy viết ADR đầy đủ với 5 phần Status, Context, Decision, Consequences, Alternatives. Cố ý đưa ít nhất hai hệ quả tiêu cực.
Bài 3 — Sửa ADR lỗi. Tìm một quyết định kỹ thuật bất kỳ trong dự án bạn đang làm (hoặc một dự án giả định) mà bạn nghi ngờ "không ai còn nhớ vì sao". Viết ADR truy hồi (retroactive) cho nó. Lưu ý phần Context phải dựng lại được bối cảnh gốc — nếu không dựng được, đó chính là bằng chứng cho thấy tổ chức đã mất kiến thức.
Tóm tắt
ADR là tài liệu ngắn ghi lại lý do (WHY) đằng sau một quyết định kiến trúc quan trọng — khác với tech spec vốn mô tả cách làm (HOW). Một ADR chuẩn gồm năm phần: Status, Context, Decision, Consequences, và Alternatives Considered. Nguyên tắc cốt lõi: chỉ viết cho quyết định architecturally significant (khó đảo ngược, ảnh hưởng rộng, có đánh đổi rõ), giữ ADR bất biến (đổi ý thì viết bản mới và đánh dấu Superseded), và luôn trung thực về cả hệ quả tiêu cực.
Với Technical BA, ADR là sân chơi tự nhiên: bạn nắm bối cảnh business và ràng buộc — chính là phần Context khó viết nhất và giá trị nhất. Như ba tình huống ShopFast, VBank và GiaoNhanh cho thấy, một ADR tốt cứu team khỏi đảo ngược sai lầm, làm bằng chứng khi audit, và chống lại sự bốc hơi kiến thức khi nhân sự ra đi. Hãy bắt đầu thói quen: lần tới ngồi họp thiết kế, khi nghe "nên dùng A hay B", hãy là người giơ tay nói "để mình ghi lại quyết định này".