init git
This commit is contained in:
184
.claude/skills/sa-lifecycle/references/design-rules.md
Normal file
184
.claude/skills/sa-lifecycle/references/design-rules.md
Normal file
@@ -0,0 +1,184 @@
|
||||
# 12 quy tắc viết tài liệu kiến trúc
|
||||
|
||||
Mọi skill `sa-*` phải tuân thủ. Đây là thứ phân biệt một tài liệu kiến trúc dev đọc xong thi
|
||||
công được với một bộ sơ đồ hộp và mũi tên.
|
||||
|
||||
Bộ này song song với `W1–W12` của bộ BA (`../../ba-lifecycle/references/writing-rules.md`).
|
||||
Khi làm tài liệu chạm cả hai (ví dụ `ICD` đối chiếu `API` của BA), tuân thủ **cả hai bộ**.
|
||||
|
||||
## D1 — Một ADR, một quyết định
|
||||
|
||||
❌ `ADR-004: Chọn stack backend` — bên trong quyết cả ngôn ngữ, framework, ORM, message broker.
|
||||
✅ Bốn ADR. Vì sáu tháng sau khi đổi message broker, bạn cần supersede đúng một quyết định,
|
||||
không phải viết lại một tài liệu còn đúng ba phần tư.
|
||||
|
||||
Ngưỡng "quyết định nào cần ADR": xem `decision-radar.md`.
|
||||
|
||||
## D2 — Cấm NFR định tính
|
||||
|
||||
Danh sách cấm, kèm cách thay:
|
||||
|
||||
| Cấm | Thay bằng |
|
||||
|---|---|
|
||||
| nhanh, phản hồi tốt | `p95 ≤ 300ms cho GET /orders tại 2.000 rps` |
|
||||
| chịu tải cao, mở rộng được | `20.000 đơn/giờ giờ cao điểm, tăng 3×/năm trong 2 năm` |
|
||||
| ổn định, sẵn sàng cao | `99.9%/tháng ⇒ ngân sách lỗi 43 phút/tháng` |
|
||||
| bảo mật | tên mối đe doạ + biện pháp + cách kiểm chứng |
|
||||
| dễ bảo trì | `một dev mới onboard và sửa được một bug trong ≤ 3 ngày` |
|
||||
| dữ liệu lớn | con số + đơn vị + tốc độ tăng |
|
||||
|
||||
Mỗi `QAS` phải trả lời đủ **bốn câu**: kịch bản gì · con số bao nhiêu · đo bằng cách nào · ai đo.
|
||||
Thiếu câu thứ ba là NFR không verify được ⇒ theo `D8` nó chỉ là mong muốn.
|
||||
|
||||
Quét trước khi nộp: `grep -niE "nhanh|ổn định|dễ (bảo trì|dùng)|chịu tải cao|bảo mật$" <file>`
|
||||
|
||||
## D3 — Không có phương án bị loại thì không phải quyết định
|
||||
|
||||
Mọi `ADR` và mọi `OPT` phải nêu **≥ 1 phương án đã cân nhắc và loại**, kèm lý do loại nói được
|
||||
bằng ràng buộc (`CON-nn`) hoặc thuộc tính chất lượng (`QAS-nnn`), không phải bằng sở thích.
|
||||
|
||||
❌ "Chọn PostgreSQL vì team quen."
|
||||
✅ "Chọn PostgreSQL. Loại MongoDB vì `QAS-007` yêu cầu giao dịch nhiều bảng nguyên tử; loại
|
||||
MySQL vì `CON-03` (đội vận hành chỉ có kinh nghiệm Postgres) và chênh lệch hiệu năng ở
|
||||
`QAS-004` không đáng kể theo POC-02."
|
||||
|
||||
"Team quen" là một lý do **hợp lệ** — nhưng phải viết ra như một ràng buộc có tên, để sau này
|
||||
biết quyết định này gắn với con người chứ không phải với kỹ thuật.
|
||||
|
||||
## D4 — Sơ đồ phải khai báo mức, và không trộn mức
|
||||
|
||||
Mỗi sơ đồ ghi rõ ở đầu: **C4 mức nào** (Context / Container / Component / Code) hoặc **loại**
|
||||
(deployment, sequence, state, data flow). Một sơ đồ có cả "trình duyệt người dùng" lẫn "class
|
||||
OrderValidator" là sơ đồ không ai đọc được.
|
||||
|
||||
Kèm mỗi sơ đồ: một **legend** giải thích hình khối và loại mũi tên (sync/async, ai gọi ai,
|
||||
giao thức). Mũi tên không nhãn không mang thông tin.
|
||||
|
||||
**Vẽ bằng mermaid, không ASCII art** — thống nhất với quy tắc `W13` của bộ BA
|
||||
(`../../ba-lifecycle/references/diagram-rules.md`). GitHub/Confluence và Artifact của Claude
|
||||
Code render thẳng, và `git diff` đọc được từng cạnh.
|
||||
|
||||
| Sơ đồ | Loại mermaid | Sinh ở |
|
||||
|---|---|---|
|
||||
| C4 Context / Container / Component | `flowchart` + `subgraph` | `SAD` §3–§5 |
|
||||
| Deployment view | `flowchart TB` + `subgraph` theo vùng/AZ | `SAD` §7, `INF` §3 |
|
||||
| Luồng chính, có nhánh lỗi | `sequenceDiagram` | `SAD` §6 |
|
||||
| Ranh giới tin cậy | `flowchart LR` | `SEC` §1 |
|
||||
| Mô hình dữ liệu khái niệm | `erDiagram` | `DAT` §2 |
|
||||
| Phụ thuộc giữa mục roadmap | `flowchart LR` | `TRM` §4 |
|
||||
| Phương án ở mức khối | `flowchart LR` | `OPT` §3 |
|
||||
|
||||
🔴 **Mỗi sơ đồ phải có bảng đi kèm** (`W13`). Sơ đồ để nhìn; bảng để truy vết, để đặt con số,
|
||||
và để kiểm chứng. Sơ đồ không diễn đạt được timeout, quyền, mã lỗi, hay ai sở hữu cái gì.
|
||||
|
||||
## D5 — Mọi interface có chủ, có contract, có chính sách phiên bản
|
||||
|
||||
Mỗi dòng trong `ICD` phải có: `IF-nnn` · hai đầu · giao thức · sync hay async · **ai sở hữu
|
||||
contract** · nơi contract sống (đường dẫn file OpenAPI/AsyncAPI/proto) · chính sách đổi phiên
|
||||
bản · hành vi khi đầu kia hỏng.
|
||||
|
||||
🔴 Interface không biết ai sở hữu là interface sẽ bị đổi mà không ai báo.
|
||||
|
||||
## D6 — Đường lỗi là bắt buộc cho mọi thứ vượt ranh giới process
|
||||
|
||||
Mọi lời gọi ra khỏi process (HTTP, DB, cache, queue, file, hệ thống ngoài) phải ghi:
|
||||
**timeout · retry (số lần + backoff + có idempotent không) · hành vi khi hết retry · ảnh hưởng
|
||||
tới người dùng**.
|
||||
|
||||
Bốn câu hỏi cho mỗi phụ thuộc, không được bỏ câu nào:
|
||||
|
||||
1. Nó chậm thì sao? *(không phải "hỏng" — chậm nguy hiểm hơn hỏng)*
|
||||
2. Nó hỏng thì sao? Có degrade được không hay chết cả luồng?
|
||||
3. Nó trả sai dữ liệu thì sao? Có phát hiện được không?
|
||||
4. Nó hồi phục thì sao? Có retry storm không? Có cần backpressure không?
|
||||
|
||||
## D7 — Mỗi mảnh dữ liệu có đúng một chủ sở hữu
|
||||
|
||||
Trong `DAT`, mỗi thực thể ghi rõ **hệ thống nào là single source of truth**. Mọi bản sao khác
|
||||
là read model, phải ghi: cập nhật bằng cơ chế gì, độ trễ tối đa bao nhiêu, và **được phép lệch
|
||||
bao lâu** trước khi coi là sự cố.
|
||||
|
||||
❌ "Cả hai hệ thống đều lưu thông tin khách hàng và đồng bộ hai chiều."
|
||||
✅ Chọn một bên làm chủ. Đồng bộ hai chiều không có chủ là cách sinh ra dữ liệu mâu thuẫn
|
||||
không ai gỡ được.
|
||||
|
||||
## D8 — Ràng buộc không verify tự động được là khuyến nghị, không phải ràng buộc
|
||||
|
||||
Mỗi ràng buộc kiến trúc trong `AGD` phải có một trong hai:
|
||||
|
||||
- một **fitness function** trong `FIT` (ArchUnit, dependency-cruiser, lint rule, kiểm thử tải,
|
||||
kiểm tra hạ tầng) chạy trên CI, **hoặc**
|
||||
- ghi thẳng nhãn `⚠️ Khuyến nghị — không tự kiểm được`.
|
||||
|
||||
Không có nhãn và không có bài kiểm ⇒ trong sáu tháng nó sẽ bị vi phạm và không ai biết.
|
||||
|
||||
## D9 — Mọi con số hạ tầng phải quy được ra tiền và ra đơn vị
|
||||
|
||||
"Cần 8 node" ⇒ node loại gì, ở vùng nào, bao nhiêu tiền/tháng, ở mức tải nào. `TCO` và `INF`
|
||||
phải khớp nhau; lệch thì `TCO` sai hoặc `INF` sai, không có khả năng thứ ba.
|
||||
|
||||
Mọi con số ghi kèm **nguồn**: bài đo nào, POC nào, báo giá nào, ngày nào. Con số không nguồn
|
||||
là 🔴 giả định, phải hạ `Confidence` của tài liệu.
|
||||
|
||||
## D10 — Không quyết định thay người có thẩm quyền
|
||||
|
||||
SA trình phương án kèm khuyến nghị. Ba loại quyết định **không** thuộc SA:
|
||||
|
||||
| Loại | Chủ | SA làm gì |
|
||||
|---|---|---|
|
||||
| Trade-off nghiệp vụ (chậm hơn nhưng rẻ hơn) | PO | Trình bảng đánh đổi kèm con số |
|
||||
| Chấp nhận rủi ro bảo mật | Security | Trình threat model + biện pháp + chi phí |
|
||||
| Ngân sách, tiến độ, nhân sự | PO / PM | Trình `TCO` và effort |
|
||||
|
||||
Gặp chỗ chưa rõ, viết:
|
||||
|
||||
```markdown
|
||||
> **OQ-021** — Chấp nhận eventual consistency ≤ 5 giây cho số dư ví không?
|
||||
> **Hỏi:** PO (chị Lan) + Security · **Từ:** 2026-08-29 · **Chặn:** ADR-009, QAS-011
|
||||
> **Phương án SA đề xuất:** Chấp nhận, vì … *(đề xuất, chưa phải quyết định)*
|
||||
> **Nếu không chấp nhận:** phải dùng phân tán 2 pha ⇒ +6 tuần, +30% chi phí hạ tầng
|
||||
```
|
||||
|
||||
Luôn ghi **hệ quả của phương án ngược lại** bằng con số — đó là thứ giúp người có thẩm quyền
|
||||
quyết được trong một lần đọc.
|
||||
|
||||
## D11 — Ghi cả cái kiến trúc KHÔNG làm
|
||||
|
||||
Cuối mỗi tài liệu, hai mục bắt buộc:
|
||||
|
||||
- **Ngoài phạm vi** — những thứ người đọc có thể tưởng là có: *"Không hỗ trợ đa vùng
|
||||
(multi-region) trong phiên bản này; DR dựa trên khôi phục từ backup, RTO 4 giờ."*
|
||||
- **Giả định** — `ASM-nn`, mỗi cái có cách xác minh và hệ quả nếu sai.
|
||||
|
||||
Kiến trúc là tập hợp những thứ đã loại nhiều hơn là những thứ đã chọn. Không ghi ra thì người
|
||||
sau tưởng bạn đã cân nhắc.
|
||||
|
||||
## D12 — Sơ đồ và văn bản mâu thuẫn: chia thẩm quyền rõ ràng
|
||||
|
||||
Ghi câu này trong mọi tài liệu có sơ đồ:
|
||||
|
||||
> Sơ đồ thắng về **quan hệ và luồng** (ai gọi ai, theo thứ tự nào).
|
||||
> Bảng/văn bản thắng về **ràng buộc và con số** (timeout, quyền, định dạng, giới hạn).
|
||||
> Mâu thuẫn ngoài hai loại trên ⇒ là lỗi tài liệu, phải sửa chứ không phải chọn bên.
|
||||
|
||||
---
|
||||
|
||||
## Checklist tự chấm trước khi nộp bất kỳ tài liệu kiến trúc nào
|
||||
|
||||
```
|
||||
[ ] D1 Mỗi ADR chỉ chứa một quyết định
|
||||
[ ] D2 grep NFR định tính trả về rỗng; mọi QAS đủ 4 câu (kịch bản/số/cách đo/ai đo)
|
||||
[ ] D3 Mọi quyết định nêu ≥1 phương án đã loại + lý do gắn với CON hoặc QAS
|
||||
[ ] D4 Mỗi sơ đồ khai báo mức C4 + có legend, không trộn mức
|
||||
[ ] D5 Mọi interface có chủ, contract, versioning policy
|
||||
[ ] D6 Mọi phụ thuộc ngoài process có timeout/retry/fallback + trả lời 4 câu hỏi
|
||||
[ ] D7 Mỗi thực thể dữ liệu có đúng một single source of truth
|
||||
[ ] D8 Mọi ràng buộc có FIT hoặc nhãn "⚠️ Khuyến nghị"
|
||||
[ ] D9 Mọi con số hạ tầng có đơn vị, nguồn, và quy ra tiền; INF khớp TCO
|
||||
[ ] D10 Mọi chỗ chưa rõ là OQ kèm hệ quả phương án ngược, không phải quyết định ngầm
|
||||
[ ] D11 Có mục "Ngoài phạm vi" và mục "Giả định ASM-nn"
|
||||
[ ] D12 Có câu quy định thẩm quyền sơ đồ vs văn bản
|
||||
```
|
||||
|
||||
In checklist này dạng bảng ☐/✅ ở cuối mỗi lần chạy skill. Mục chưa đạt ⇒ nói rõ thiếu gì,
|
||||
**không được đánh ✅ cho có**.
|
||||
Reference in New Issue
Block a user