Bài 5 · Vận dụng · 20 phút
Level 3: Component
Biên soạn bởi Nguyễn Anh Tuấn
Zoom vào MỘT container thành các component (controller, service, repository) - nhóm chức năng liên quan; khi nào nên vẽ và khi nào bỏ qua để sơ đồ khỏi lạc hậu.
Ở bài trước, hệ thống đã tách thành các container. Giờ ta chọn MỘT container (thường là API) và zoom vào trong nó: sơ đồ Component cho thấy container đó được tạo từ những nhóm chức năng nào.
Mở tiếp container API Application của Ngân Hàng Số (ở bài trước) ra - đây là các component bên trong nó:
[Component: Spring MVC]
Sign-in Controller
Xử lý đăng nhập, cấp token.
[Component: Spring MVC]
Accounts Controller
Trả về số dư & lịch sử.
[Component: Lớp nghiệp vụ]
Transfer Service
Thực hiện chuyển khoản.
[Component: Lớp tích hợp]
Core Banking Facade
Bọc giao tiếp với hệ thống lõi.
[Component: Lớp truy cập]
Database Gateway
Đọc/ghi cơ sở dữ liệu.
[Hệ thống ngoài]
Hệ thống lõi (Core Banking)
Tài khoản & giao dịch.
- ▸Component là mức zoom thứ ba: bên trong MỘT container.
- ▸Khán giả: lập trình viên sắp viết hoặc sửa code trong container đó.
- ▸Đây là mức gần code nhất mà vẫn còn hữu ích cho phần lớn người đọc.
Một component là một nhóm chức năng liên quan, đứng sau một interface, nằm bên trong một container. Nó KHÔNG triển khai riêng được - nó chạy cùng tiến trình của container.
- ▸Controller: nhận yêu cầu từ bên ngoài (vd Sign-in Controller, Order Controller).
- ▸Service: chứa nghiệp vụ (vd Transfer Service, Progress Service).
- ▸Gateway / Repository: truy cập dữ liệu hoặc hệ thống ngoài (vd Database Gateway).
- ▸Một component thường GỘP nhiều class - đừng nhầm component (mức 3) với một class (mức 4).
Đừng nhầm với container
Đây là mức cần thành thật nhất. Sơ đồ Component nằm sát code nên dễ lạc hậu, vì vậy đừng vẽ cho có:
- ▸NÊN vẽ: container lớn, phức tạp, hoặc quan trọng tới mức nhiều người cần hiểu bên trong.
- ▸BỎ QUA: container đơn giản (vd một SPA chỉ hiển thị dữ liệu) - vẽ ra cũng ít giá trị.
- ▸Phần lớn dự án dừng ở Container; chỉ một vài container "nặng" mới đáng zoom tới đây.
- ▸Vẽ mà không bảo trì được thì có hại: sơ đồ sai còn tệ hơn không có sơ đồ.
Hãy soi bên trong API của một nền tảng học. Trong widget, chọn Lớp Học Trực Tuyến, zoom tới mức Component (vào hệ thống, rồi vào container API Application):
Nền tảng học online: học viên xem bài, làm quiz, theo dõi tiến độ.
Mức 1 - System Context
System Context - Lớp Học Trực Tuyến
Quan hệ (có nhãn & hướng)
- Học viên → Lớp Học Trực Tuyến : Học & làm bài [HTTPS]
- Giảng viên → Lớp Học Trực Tuyến : Soạn bài & chấm [HTTPS]
- Lớp Học Trực Tuyến → Cổng thanh toán : Thu học phí [API]
- Lớp Học Trực Tuyến → Dịch vụ Email : Gửi email [SMTP]
- ▸Controller nhận yêu cầu (Sign-in, Course); Service xử lý nghiệp vụ (Progress, Quiz).
- ▸Mọi truy cập dữ liệu đi qua một Database Gateway - tập trung một chỗ, dễ thay đổi.
- ▸Lần một luồng: Course Controller → Progress Service → Database Gateway → Cơ sở dữ liệu.
- ▸Đây là bản đồ cho người sắp viết code BÊN TRONG API, không phải cho sếp kinh doanh.
- ▸Vẽ THÔ: gộp theo nhóm chức năng, đừng phản chiếu từng class - càng chi tiết càng mau sai.
- ▸Sinh tự động từ code khi có thể, để sơ đồ luôn khớp thực tế.
- ▸Nếu không bảo trì nổi, thà bỏ mức Component và để code tự nói.
Cầu nối
Ta đã đi hết ba mức zoom chính: Context, Container, Component. Còn mức thứ tư (Code) và những sơ đồ bổ trợ thì sao?
Bước tiếp theo
Câu hỏi thường gặp
Không hẳn. Component là một NHÓM chức năng liên quan, đứng sau một interface, thường gồm nhiều class. Ví dụ "Transfer Service" có thể gồm vài class nhỏ bên trong. Một class đơn lẻ là Code element (mức 4), không phải Component.
Container chạy/triển khai riêng được; component thì không - nó sống bên trong một container và chạy cùng tiến trình của container đó. Bạn không "triển khai" riêng một Order Controller; nó là một phần của API Application.
Không. Chỉ vẽ cho container đủ phức tạp và đủ quan trọng để người đọc cần hiểu bên trong. Phần lớn dự án dừng ở Container; chỉ một vài container "nặng" mới đáng zoom tới Component.
Vì nó nằm sát code: thêm/bớt/đổi tên một service là sơ đồ đã sai. Càng gần code, vẽ tay càng mau lỗi thời. Giải pháp là vẽ thô (gộp nhóm), hoặc sinh tự động từ code, hoặc đơn giản bỏ qua mức này.
Cách sinh sơ đồ từ code: Diagrams as code →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.
Một "component" trong C4 được hiểu đúng nhất là gì?
- 1
Tách component cho một API
Chọn một API mèo con biết. Phác các component bên trong: controller (nhận yêu cầu), service (nghiệp vụ), gateway (truy cập dữ liệu).
Hoàn thành khi: Có ≥1 controller, ≥1 service, ≥1 gateway; mỗi cái một dòng vai trò ngắn.
- 2
Component hay class hay container?
Phân loại: (a) "Order Controller" gồm 3 class, (b) class PaymentValidator, (c) cơ sở dữ liệu Oracle. Mỗi cái là Component, Code element hay Container?
Hoàn thành khi: Phân loại đúng cả 3; giải thích vì sao (a) là component dù gồm nhiều class.
- 3
Lần luồng trong widget
Dùng widget Bước 4 (Lớp Học Trực Tuyến, mức Component). Lần một luồng từ controller tới cơ sở dữ liệu, viết ra chuỗi component đi qua.
Hoàn thành khi: Viết đúng một chuỗi (vd Course Controller → Progress Service → Database Gateway → CSDL).
- 4
Vẽ hay bỏ qua?
Cho hai container: (a) một API lớn 30 nghìn dòng, (b) một SPA đơn giản hiển thị dữ liệu. Quyết định có nên vẽ sơ đồ Component cho từng cái không, vì sao.
Hoàn thành khi: Quyết định rõ cho cả hai; lý do bám tiêu chí "phức tạp & quan trọng".
- 5
Giữ sơ đồ khỏi lạc hậu
Viết 3 cách giữ một sơ đồ Component không lỗi thời sau vài tháng.
Hoàn thành khi: Nêu được ít nhất: vẽ thô (gộp nhóm), sinh từ code, hoặc bỏ qua và dựa vào code.
- 6
So ba mức
Với một hệ thống tự chọn, viết một câu cho mỗi mức (Context, Container, Component) nói mức đó cho thấy gì.
Hoàn thành khi: Đủ 3 câu; mỗi câu đúng nội dung mức và đúng độ chi tiết tăng dần.