Nội dung bài viết
Hi các bạn 👋. Mình là Hùng Anh.
Trong quá trình làm việc, hẳn có lúc bạn từng đọc các bản vẽ C4 model trong tài liệu SAD (Software Architecture Document) của các anh Solution Architect. Nhưng bạn đã thực sự hiểu từng loại diagram ở đó mang ý nghĩa gì, và được dùng trong tình huống nào chưa? Nếu ngay bây giờ được giao vẽ sơ đồ kiến trúc cho 1 hệ thống, liệu bạn có làm được không?
Bài này mình và bạn sẽ cùng tìm hiểu C4 model — chuẩn vẽ kiến trúc phổ biến nhất hiện nay — để lần tới gặp những bản vẽ đó, bạn không chỉ đọc hiểu mà còn tự vẽ được.
Bắt đầu thôi.
1. Vấn Đề Của Những Diagram Không Theo Chuẩn
Hình dưới đây có lẽ bạn đã gặp nhiều lần:

Có 3 vấn đề dễ nhận ra:
- Lẫn lộn tầng trừu tượng. "Users" là con người, "OrderServiceImpl" là 1 class Java, "K8s cluster" là hạ tầng — 3 thứ ở 3 tầng trừu tượng khác nhau lại đứng cạnh nhau trong cùng 1 hình.
- Ký hiệu tự chế. Mũi tên từ "API" sang "Auth" nghĩa là gọi sang, phụ thuộc, hay deploy lên? Box hình mây và box hình trụ khác nhau ở điểm nào? Không có chú thích, mỗi người đọc sẽ tự diễn giải 1 kiểu.
- 1 hình phục vụ mọi đối tượng. CTO muốn nhìn tổng quan, dev mới cần chi tiết, SRE quan tâm hạ tầng. Gộp tất cả vào 1 hình thì cuối cùng không nhóm nào dùng được.
2. C4 Model
C4 model là 1 chuẩn mô tả kiến trúc phần mềm theo nhiều mức chi tiết, do Simon Brown tạo ra. Ý tưởng đằng sau rất quen thuộc: các mức zoom của bản đồ. Cùng 1 vùng đất, Google Maps lúc cho bạn nhìn cả đất nước, lúc là 1 thành phố, lúc lại là từng con phố — zoom đến đâu, hiện chi tiết đến đó.
Với phần mềm, C4 định nghĩa 4 mức zoom: Context, Containers, Components, Code. Kèm theo 1 nguyên tắc: thống nhất khái niệm trước, bàn về hình vẽ và màu sắc sau.
2.1. Các Khái Niệm Cốt Lõi
1 software system gồm nhiều container; mỗi container chứa nhiều component; và component được hiện thực bằng code.
- Person — người dùng hệ thống: khách hàng, admin, operator.
- Software System — mức trừu tượng cao nhất: 1 thứ mang lại giá trị cho người dùng. Hệ thống bạn đang xây là 1 software system; cổng thanh toán mà nó gọi sang thì là 1 software system khác.
- Container — 1 đơn vị deploy được độc lập: backend API, SPA, mobile app, database. Cái gì có process riêng và lần deploy riêng, cái đó là container.
- Component — 1 nhóm chức năng bên trong container: service, controller, repository. Component không deploy riêng được — nó nằm trong process của container.
C4 ra đời trước Docker. Container trong C4 là bất cứ thứ gì chạy được, deploy được độc lập — 1 service Spring Boot là 1 container, bất kể bạn chạy nó trong Docker hay trên VM.
2.2. Các Level Trong C4 Model
Để dễ hình dung, mình lấy ví dụ về thiết kế FoodGo — 1 nền tảng đặt đồ ăn: khách hàng đặt món từ các nhà hàng, nhà hàng tự quản lý menu và đơn hàng đến, shipper nhận đơn và đi giao, còn thanh toán đi qua 1 cổng thanh toán bên ngoài.
2.2.1. Level 1: System Context
Level 1 mô tả: hệ thống là gì, ai dùng, và nó nói chuyện với những hệ thống nào?
Không database, không cache, không chi tiết bên trong — cả hệ thống chỉ là 1 box duy nhất. Nhờ vậy ai cũng đọc được, kể cả người không làm kỹ thuật. Đây cũng là hình ít thay đổi nhất, và với bất kỳ hệ thống nào, đây nên là hình được vẽ đầu tiên.
2.2.2. Level 2: Container
Level 2 mô tả: hệ thống gồm những khối kỹ thuật lớn nào, chúng giao tiếp với nhau ra sao?
Đến level này, hệ thống được tách thành các khối kỹ thuật lớn: 1 mobile app dùng chung cho khách hàng và shipper, 1 Restaurant Portal — web app riêng cho chủ nhà hàng, 1 API Spring Boot, PostgreSQL, và Kafka.
Trong hình có 2 lựa chọn thiết kế đáng chú ý. Nhà hàng có hẳn 1 container riêng vì công việc của họ — quản lý menu, theo dõi đơn hàng đổ về — là việc ngồi bàn làm việc mở trình duyệt, không phải việc cầm điện thoại. Kafka có mặt cũng là có chủ đích: API chỉ phát order event, việc gửi thông báo do Notification Worker tiêu thụ event và xử lý riêng — nhờ vậy luồng đặt món không phải chờ push/SMS gửi xong. Ngoài ra, để ý mỗi container đều được ghi rõ công nghệ, mỗi mũi tên đều có động từ và protocol.
Với đa số hệ thống, Context + Container là đủ tài liệu kiến trúc. Nếu hệ thống có vài chục microservice, đừng gộp tất cả vào 1 hình — hãy vẽ mỗi service 1 hình riêng cùng các service liên quan trực tiếp.
2.2.3. Level 3: Component
Level 3 mô tả: bên trong 1 container có gì?
Bên trong API Application là những service quen thuộc: Product Service quản lý danh mục nhà hàng và món ăn (Mobile App gọi vào để xem menu, Restaurant Portal gọi vào để quản lý), Delivery Service gán shipper và theo dõi giao hàng, Order Service xử lý vòng đời đơn hàng. Cả 3 service cùng đọc/ghi vào database dùng chung của ứng dụng, mỗi service chỉ động vào phần dữ liệu của riêng nó. Riêng Order Service còn dùng thêm Payment Connector để gọi sang cổng thanh toán. Mỗi component ứng với 1 package hoặc module trong code, chứ chưa phải các class cụ thể — mức đó là việc của Level 4.
Hình này có 2 chi tiết dễ bị bỏ qua. Thứ nhất, khung nét đứt lúc này chỉ bao quanh API Application: Database hay Message Broker là những container khác của hệ thống nên nằm ngoài khung — khác với C2, nơi khung nét đứt bao trọn hệ thống FoodGo. Thứ hai, việc bắn order event lên Kafka không được vẽ lại ở đây: tương tác đó thuộc về C2, không phải nội bộ container này. Cũng theo logic đó, đừng nhầm C3 với "sơ đồ các service": service là thứ deploy riêng được nên thuộc về C2; C3 là ruột của 1 container — các module trong cùng 1 codebase. Với hệ microservices, từng service hiện ở C2, và C3 sẽ zoom vào từng service một.
Component diagram chỉ nên vẽ ở những chỗ thật sự cần: mức này thay đổi liên tục nên cũng lỗi thời nhanh nhất. Nhiều team bỏ qua hẳn, hoặc dùng tool generate từ code.
2.2.4. Level 4: Code
Class diagram của từng component. Không cần vẽ tay — IDE có thể generate ngay khi cần, và ở mức này thì bản thân code mới là source of truth.
Ngoài ra C4 còn 3 loại diagram bổ trợ: System Landscape (tất cả hệ thống trong tổ chức), Dynamic (các phần tử phối hợp lúc runtime, có đánh số bước), và Deployment (container nào chạy trên hạ tầng nào).
2.3. Tóm Tắt
| Level | Trả lời câu gì | Ai đọc | Tần suất thay đổi |
|---|---|---|---|
| 1. Context | Hệ thống là gì, ai dùng? | Tất cả mọi người | Hiếm khi |
| 2. Container | Gồm những khối nào? | Dân kỹ thuật | Thỉnh thoảng |
| 3. Component | Trong container có gì? | Dev của container đó | Thường xuyên |
| 4. Code | Code viết thế nào? | Dev, khi cần | Liên tục |
Có thể thấy quy luật: càng zoom sâu, đối tượng đọc càng hẹp và hình càng nhanh lỗi thời. Vì vậy hiếm khi cần vẽ đủ cả 4 mức.
2.4. Những Lưu Ý Và Sai Lầm Cần Tránh Khi Vẽ C4 Model
C4 không quy định hình khối hay màu sắc cụ thể, nhưng 1 diagram chuyên nghiệp sẽ luôn có đủ:
- Title — loại diagram + phạm vi ("Container diagram for FoodGo").
- Legend — mọi hình khối, màu sắc, kiểu đường kẻ đều cần được chú thích.
- Mỗi phần tử ghi rõ loại và trách nhiệm — gói gọn trong 1 câu.
- Ghi rõ công nghệ:
[Java, Spring Boot],[PostgreSQL]. - Mũi tên 1 chiều, có nhãn: động từ cụ thể, kèm protocol khi mũi tên vượt qua ranh giới process. Hạn chế tối đa chữ "uses" chung chung.
Dưới đây là 1 vài lỗi phổ biến hay gặp khi vẽ C4 model:
- Tự chế thêm level không có trong chuẩn ("sub-component", "sub-container").
- Vẽ chi tiết bên trong những hệ thống không thuộc quyền quản lý của mình.
- Trộn nhiều mức zoom trong cùng 1 hình — ví dụ class nằm cạnh container, database table nằm cạnh software system.
- Nhồi nhét quá nhiều phần tử trong 1 hình.
Lưu ý thêm: C4 chỉ mô tả cấu trúc tĩnh — để mô tả luồng xử lý hay data model, bạn vẫn cần sequence hoặc ER diagram. Và với 1 team nhỏ chỉ có 1 service thì có thể chỉ cần 1 Context diagram cùng 1 README tốt là đủ. C4 phát huy giá trị khi có nhiều người cần hiểu chung 1 bức tranh về hệ thống.
3. Tổng Kết
- C4 chia 4 mức zoom: Context, Containers, Components, Code — mỗi mức trả lời 1 câu hỏi, cho 1 nhóm người đọc.
- Container trong C4 là thứ deploy độc lập được — không phải Docker container.
- Vẽ tốt Context + Container là đủ dùng. Component chỉ vẽ ở những chỗ xứng đáng; Code để IDE generate.
- Mỗi diagram cần: title, legend, phần tử ghi rõ loại, công nghệ, mũi tên 1 chiều có nhãn.
Lần tới khi được nhờ "vẽ kiến trúc hệ thống", hãy hỏi lại: vẽ ở mức zoom nào, và cho ai xem?
Hẹn gặp lại các bạn trong những bài viết tiếp theo. Happy reading! 🍵
References
- The C4 model for visualising software architecture
- The C4 Model for Software Architecture — Simon Brown, InfoQ
- The C4 Model – Misconceptions, Misuses & Mistakes — Simon Brown, GOTO 2024
- Structurizr DSL documentation
- C4-PlantUML
- What is the C4 model? — IcePanel
Bài viết liên quan
Distributed Lock và Cách Triển Khai với Redis
Trong các hệ thống phân tán, việc đảm bảo tính nhất quán của dữ liệu (data consistency) và ngăn chặn tranh chấp tài nguyên (race condition) là một thách thức lớn, đặc biệt khi nhiều tiến trình hoặc service truy cập đồng thời vào các tài nguyên dùng chung. Distributed lock là giải pháp hiệu quả để xử lý vấn đề này. Bài viết này mình sẽ giúp bạn hiểu rõ distributed lock là gì, tại sao nó cần thiết, các phương pháp để thực hiện và cách triển khai nó với Redis nhé.
Message Broker
Bạn có bao giờ tự hỏi điều gì giúp các dịch vụ thanh toán, mạng xã hội hay giao hàng hoạt động mượt mà mỗi ngày? Bí mật nằm ở Message Broker – công cụ “kết nối vô hình” giúp thông tin truyền đi an toàn và hiệu quả giữa các hệ thống. Hãy cùng mình khám phá Message Broker là gì nhé!
CronJob & Cron Expressions
CronJob là một công cụ quan trọng giúp lập trình viên tự động hóa các tác vụ theo lịch trình định kỳ. Tuy nhiên, để thiết lập CronJob một cách chính xác, bạn cần nắm vững Cron Expression – biểu thức giúp xác định lịch trình cho các công việc tự động. Bài viết này sẽ giới thiệu về CronJob, cách xây dựng Cron Expression, và các công cụ hữu ích để tạo biểu thức cron một cách dễ dàng.
