Ngoài ADR: design doc, Diátaxis, runbook và sơ đồ C4 Trung cấp
Thời gian đọc ước tính: 6 phút
Cần đọc trước
Trang này trả lời: ngoài ADR, team cần những tài liệu nào, mỗi loại viết cho ai, và trông thế nào khi viết đúng.
Design doc / RFC trước, ADR sau
Phần tiêu đề “Design doc / RFC trước, ADR sau”Design doc là tài liệu tương đối không chính thức, viết trước khi code, để nêu chiến lược và trade-off rồi xin review. Nhiều công ty gọi nó là RFC.
Malte Ubl mô tả cấu trúc hay dùng ở Google:
- Context and scope
- Goals and non-goals
- The actual design
- Alternatives considered
- Cross-cutting concerns (security, privacy, observability)
| Design doc / RFC | ADR | |
|---|---|---|
| Thời điểm | Trước khi làm, khi còn mơ hồ | Lúc chốt quyết định (thường cuối design review) |
| Mục đích | Khám phá phương án, xin phản biện, tạo đồng thuận | Ghi lại một quyết định và lý do |
| Phạm vi | Cả một thay đổi, có thể sinh nhiều quyết định | Đúng một quyết định |
| Độ dài | Ubl: khoảng 10–20 trang cho dự án lớn, “mini design doc” 1–3 trang | 1–2 trang (Nygard) |
| Sau khi xong | Lỗi thời dần; Ubl khuyên cập nhật khi thiết kế đổi lúc còn đang làm | Bất biến; đổi ý thì supersede |
| Người đọc chính | Reviewer hiện tại | Kỹ sư tương lai |
Đang tải diagram…
Design doc có thể cũ đi; ADR thì không cần cập nhật.
Ubl cũng nói khi nào không viết design doc: bài toán không mơ hồ, hoặc doc thực chất là “implementation manual” không có trade-off. Khi đó viết thẳng ADR, hoặc chỉ cần PR description tốt.
Diátaxis: tổ chức phần tài liệu còn lại
Phần tiêu đề “Diátaxis: tổ chức phần tài liệu còn lại”Phần còn lại hay hỏng vì trộn lẫn: README vừa là tutorial, vừa là reference, vừa giải thích kiến trúc. Diátaxis chia tài liệu theo nhu cầu người đọc thành bốn loại:
| Loại | Diátaxis mô tả | Ví dụ cho order service | Dấu hiệu viết sai |
|---|---|---|---|
| Tutorial | Một bài học; người đọc học bằng cách làm | README quickstart: clone, docker compose up, tạo đơn đầu tiên, thấy event trong Kafka |
Rẽ nhánh “nếu bạn dùng X thì…”; giải thích dài |
| How-to guide | Hướng dẫn đạt một mục tiêu thực tế, cho người đã biết việc | “Replay event outbox cho một khoảng thời gian”, “Rotate secret Kafka”, runbook | Dạy lại khái niệm từ đầu |
| Reference | Mô tả kỹ thuật chính xác, đầy đủ, trung tính | OpenAPI spec, JSON schema event, bảng env var kèm default | Có ý kiến, có “nên”; viết tay rồi lệch code |
| Explanation | Bối cảnh, lý do, bức tranh lớn | ADR, architecture.md với sơ đồ C4, “Vì sao đơn có 7 trạng thái” |
Chèn lệnh từng bước |
Hai mẹo thực dụng:
- Reference nên sinh từ code (OpenAPI từ decorator NestJS, bảng env var từ schema validate config). Thứ viết tay sẽ lệch.
- README là cửa vào, không phải kho. Giữ quickstart ngắn, link sang how-to, reference và
docs/adr/.
Runbook cho on-call
Phần tiêu đề “Runbook cho on-call”Runbook là how-to guide cho người bị page lúc 3 giờ sáng, có thể không phải người viết code. Mỗi alert nên link tới đúng một runbook; alert không có runbook là alert chưa xong.
Prometheus mô tả annotations là chỗ chứa thông tin dài hơn như mô tả alert hoặc link runbook:
- alert: OutboxBacklogHigh # metric do relay tự export: tuổi (giây) của dòng pending cũ nhất expr: outbox_oldest_pending_age_seconds > 60 for: 5m labels: severity: page annotations: summary: Outbox có dòng pending cũ hơn 60s runbook_url: https://git.example.com/order-service/-/blob/main/docs/runbooks/outbox-backlog.mdRunbook tương ứng:
# Runbook: OutboxBacklogHigh
Alert: dòng outbox pending cũ nhất > 60s trong 5 phút. Dashboard: <link>Owner: team Checkout. Cập nhật lần cuối: 2026-09-12 (bởi Minh)
## Ảnh hưởngShipping nhận OrderPaid chậm. Thanh toán KHÔNG bị ảnh hưởng (xem ADR-0012).
## Chẩn đoán (theo thứ tự)1. Relay có chạy không? `kubectl get pods -l app=outbox-relay`2. Kafka có nhận không? Xem lỗi publish trên dashboard relay.3. Có dòng "độc" retry mãi không? SELECT id, event_type, created_at FROM outbox WHERE published_at IS NULL ORDER BY id LIMIT 20;
## Xử lý- Relay crash loop: rollback relay về image trước.- Kafka down: không làm gì với outbox; backlog sẽ tự xả khi Kafka về. Báo #inc-kafka.- Dòng độc: KHÔNG xoá. Chuyển sang bảng outbox_parked theo hướng dẫn <link>, mở ticket.
## EscalationSau 30 phút chưa giảm: gọi secondary on-call Checkout, rồi SRE.Những điểm làm runbook dùng được:
- Ảnh hưởng tới người dùng nói trước.
- Lệnh copy-paste được, theo thứ tự chẩn đoán.
- Ghi rõ việc không được làm.
- Có ngày cập nhật và owner.
Ngưỡng alert nên xuất phát từ SLO (xem SLI, SLO và error budget).
Sơ đồ C4 mức 1–2 cho một service
Phần tiêu đề “Sơ đồ C4 mức 1–2 cho một service”C4 model của Simon Brown có bốn mức: System context, Container, Component, Code. Trang C4 nói thẳng: system context và container diagram đủ cho đa số team; chỉ vẽ mức nào thêm giá trị.
“Container” trong C4 là ranh giới runtime chạy code hoặc lưu dữ liệu, không phải Docker container.
Đang tải diagram…
Cách đọc:
| Mức | Cách nhìn sơ đồ trên | Trả lời |
|---|---|---|
| 1 — System context | Coi khung Order system là một hộp |
Ai dùng, nói chuyện với hệ thống nào |
| 2 — Container | Mở khung ra | Process và datastore nào, giao tiếp bằng gì |
| 3 — Component | Bên trong Order API | Thường không đáng vẽ tay: đổi theo từng refactor |
Quy tắc giữ sơ đồ đúng:
- Sơ đồ là code: Mermaid trong
docs/architecture.md. - Mỗi mũi tên ghi giao thức hoặc ý nghĩa.
- PR thêm datastore hay tích hợp mới phải sửa sơ đồ.
Tiếp theo: Giữ tài liệu sống và checklist.