← C4 Model: vẽ kiến trúc phần mềm

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 - bên trong API Application

[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.

GọiGọiGọiGọiLấy số dư [XML/HTTPS]
  • 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

Bạn không "triển khai" riêng một Order Controller - nó là một phần của API Application. Nếu một thứ chạy/triển khai độc lập được, nó là container, không phải component.

Đâ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):

🗺️ Bản đồ kiến trúc:

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 Mức 2 Mức 3

Mức 1 - System Context

System Context - Lớp Học Trực Tuyến

Học viên
Mèo con học bài, làm quiz, xem tiến độ.
Giảng viên
Soạn bài giảng, chấm bài.
Cổng thanh toán ngoài
Thu học phí.
Dịch vụ Email ngoài
Gửi email thông báo.

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

Cách bền nhất để mức Component khỏi lạc hậu là viết mô hình bằng code rồi sinh sơ đồ - đúng chủ đề bài Diagrams as code.

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

Bài tới gói gọn mức cuối và các sơ đồ "ngoài bộ bốn": Level 4 & sơ đồ bổ trợ - gồm Code, System Landscape, Dynamic và Deployment.

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 →

Theo C4, không nên lồng component trong component. Nếu một container phức tạp tới mức cần nhiều tầng, đó thường là dấu hiệu nên tách nó thành nhiều container, chứ không lồng thêm tầng.

Tick những điều em tự tin làm được. Càng lên cao, em càng hiểu sâu.

Tick những điều em tự tin làm được sau khi học bài này. 0/6

Trả lời vài câu để chắc rằng em đã nắm bài.

Câu 1/3 Điểm: 0

Một "component" trong C4 được hiểu đúng nhất là gì?

  1. 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. 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. 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. 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. 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. 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.