Bài 8 · Vận dụng · 22 phút
Diagrams as code
Biên soạn bởi Nguyễn Anh Tuấn
Viết mô hình bằng code thay vì kéo-thả: Structurizr DSL (một model sinh nhiều view), C4-PlantUML và Mermaid C4 - để sơ đồ luôn khớp hệ thống, version cùng Git.
Công cụ kéo-thả như draw.io hay Visio dễ dùng và cho ra hình đẹp. Nhưng khi sơ đồ cần sống lâu cùng dự án, chúng lộ điểm yếu - đúng nỗi lo "lạc hậu" ta gặp ở mức Component.
- ▸Tách rời code: sơ đồ là một file ảnh nằm đâu đó, dễ quên cập nhật khi hệ thống đổi.
- ▸Khó review: một ảnh PNG không "diff" được; người review không thấy đổi gì.
- ▸Lặp công: cùng một phần tử xuất hiện ở nhiều bức; đổi một chỗ phải sửa tay nhiều bức.
Diagrams as code đảo ngược cách làm: bạn MÔ TẢ mô hình bằng văn bản, rồi để công cụ tự vẽ ra sơ đồ. Vì giờ sơ đồ là text, nó hưởng mọi thứ tốt đẹp của code.
- ▸Version cùng Git: sơ đồ đổi theo từng commit, có lịch sử rõ ràng.
- ▸Review qua Pull Request: người khác xem diff text và góp ý ngay.
- ▸Một model, nhiều view: mô tả phần tử một lần, sinh ra nhiều sơ đồ luôn khớp nhau.
- ▸Tự canh bố cục: khỏi mất công kéo từng hộp cho thẳng hàng.
Thật ra, chính các sơ đồ trong khoá này cũng là "diagrams as code" - chúng được sinh ra từ dữ liệu (không vẽ tay), nên luôn nhất quán. Ví dụ một sơ đồ Container do code dựng:
[Người dùng]
Khách hàng
Giao dịch trực tuyến.
[Container: React]
Web App
Ngân hàng trên trình duyệt.
[Container: Swift / Kotlin]
Mobile App
App ngân hàng trên điện thoại.
[Container: Java / Spring]
API Application
Cung cấp API cho web & mobile.
[Container: Oracle]
Cơ sở dữ liệu
Lưu đăng nhập, nhật ký giao dịch.
[Container: RabbitMQ]
Hàng đợi tin
Xử lý giao dịch bất đồng bộ.
[Hệ thống ngoài]
Hệ thống lõi (Core Banking)
Tài khoản & giao dịch.
Structurizr do chính Simon Brown (cha đẻ C4) làm ra, sinh đúng cho C4. Điểm mạnh: bạn dựng một model, rồi định nghĩa nhiều view từ model đó.
ngan-hang.dsl - Structurizr DSL (render ra sơ đồ, không in ra terminal)
workspace {
model {
khachHang = person "Khách hàng"
nganHang = softwareSystem "Ngân Hàng Số" {
web = container "Web App" "React"
api = container "API Application" "Java/Spring"
db = container "Cơ sở dữ liệu" "Oracle"
}
khachHang -> web "Dùng [HTTPS]"
web -> api "Goi [JSON/HTTPS]"
api -> db "Doc/ghi [SQL]"
}
views {
systemContext nganHang {
include *
autolayout lr
}
container nganHang {
include *
autolayout lr
}
}
} - ▸Khối model khai báo phần tử & quan hệ MỘT lần.
- ▸Khối views sinh ra hai sơ đồ (systemContext và container) từ cùng model đó.
- ▸Đổi tên một container? Sửa một dòng, cả hai sơ đồ cập nhật theo.
Hai lựa chọn phổ biến khác mô tả TỪNG sơ đồ một (không có khái niệm model dùng chung), nhưng rất tiện và nhiều nơi hỗ trợ sẵn.
C4-PlantUML - dùng macro Person/Container/Rel (render bằng PlantUML)
@startuml
!include https://raw.githubusercontent.com/plantuml-stdlib/C4-PlantUML/master/C4_Container.puml
Person(khachHang, "Khách hàng")
System_Boundary(nganHang, "Ngân Hàng Số") {
Container(web, "Web App", "React")
Container(api, "API Application", "Java/Spring")
ContainerDb(db, "Co so du lieu", "Oracle")
}
Rel(khachHang, web, "Dung", "HTTPS")
Rel(web, api, "Goi", "JSON/HTTPS")
Rel(api, db, "Doc/ghi", "SQL")
@enduml Mermaid C4 - render thẳng trong Markdown trên GitHub
C4Context
title System Context - Ngan Hang So
Person(khachHang, "Khách hàng", "Giao dịch trực tuyến")
System(nganHang, "Ngân Hàng Số", "Ngân hàng online")
System_Ext(core, "Core Banking", "Tài khoản & giao dịch")
Rel(khachHang, nganHang, "Dùng", "HTTPS")
Rel(nganHang, core, "Lấy số dư", "XML/HTTPS") Trung thực
| draw.io | Kéo-thả, tự do, đẹp nhanh - nhưng tách rời code, khó diff, dễ lạc hậu. |
| Structurizr | Một model sinh nhiều view, đúng C4 nhất - học hơi cong nhưng bền cho đội nghiêm túc. |
| C4-PlantUML | Phổ biến, nhiều tích hợp CI/wiki - mô tả từng sơ đồ một. |
| Mermaid | Render ngay trong Markdown/GitHub, cú pháp gọn - hợp để bắt đầu & README. |
Gợi ý chọn
Giờ bạn tạo được sơ đồ vừa đẹp vừa luôn khớp hệ thống. Còn một kỹ năng nữa quyết định sơ đồ có thực sự hữu ích: trình bày đúng mức cho đúng người.
Bước tiếp theo
Câu hỏi thường gặp
Không bắt buộc. Bản nháp nhanh trên bảng trắng hay draw.io vẫn tiện. Nhưng với sơ đồ cần LƯU LẠI, version và giữ khớp hệ thống lâu dài, viết bằng code thắng rõ: diff được, review qua PR, một model sinh nhiều view.
Structurizr DSL là mã nguồn mở, và Structurizr Lite chạy local hoàn toàn miễn phí (xem một workspace). Ngoài ra có dịch vụ cloud trả phí cho đội. Với người học, Structurizr Lite là đủ để thử.
Mermaid đánh dấu cú pháp C4 là experimental (thử nghiệm), nhưng nó render ngay trong Markdown trên GitHub/GitLab và nhiều trình xem, nên rất tiện cho README và giao tiếp nhanh. Cần sơ đồ nghiêm túc, lâu dài thì cân nhắc Structurizr.
Tick những điều em tự tin làm được. Càng lên cao, em càng hiểu sâu.
Trả lời vài câu để chắc rằng em đã nắm bài.
Lợi ích nào KHÔNG phải của "diagrams as code" so với kéo-thả?
- 1
Viết Context bằng Mermaid
Viết một sơ đồ C4Context bằng Mermaid cho một hệ thống mèo con biết, rồi dán vào một trình xem Mermaid (hoặc README trên GitHub) để render thử.
Hoàn thành khi: Sơ đồ render ra; có ≥1 Person, hệ thống trung tâm, ≥1 hệ thống ngoài, quan hệ có nhãn.
- 2
Một model, hai view
Bằng Structurizr DSL, viết một khối model rồi định nghĩa CẢ HAI view: systemContext và container cho cùng hệ thống.
Hoàn thành khi: Một khối model duy nhất; hai view sinh ra từ nó; mỗi view có autolayout.
- 3
Bảng so sánh công cụ
Lập bảng ưu/nhược cho draw.io, Structurizr, Mermaid theo các tiêu chí: version trong Git, một-model-nhiều-view, độ dễ học, render trên GitHub.
Hoàn thành khi: Bảng đủ 3 công cụ × 4 tiêu chí; mỗi ô một nhận xét ngắn.
- 4
Vì sao diff dễ hơn
Viết một đoạn ngắn giải thích vì sao review một thay đổi sơ đồ dạng code (text) dễ hơn so với một ảnh PNG.
Hoàn thành khi: Nêu được: text diff dòng-theo-dòng, comment trong PR, lịch sử Git rõ ràng.
- 5
Dịch một sơ đồ vẽ tay
Lấy một sơ đồ mèo con từng vẽ tay (vd bài Context), viết lại bằng MỘT trong ba cú pháp (Structurizr/PlantUML/Mermaid).
Hoàn thành khi: Bản code render đúng nội dung sơ đồ gốc; mọi quan hệ có nhãn.
- 6
Chọn công cụ cho đội
Tình huống: một đội nhỏ muốn sơ đồ hiển thị ngay trong README trên GitHub, ít công bảo trì. Chọn công cụ và biện hộ.
Hoàn thành khi: Chọn rõ một công cụ (gợi ý: Mermaid) với ít nhất hai lý do bám tình huống.