Hướng dẫn cú pháp mô hình C4 của PlantUML

Mô hình sơ đồ C4 là gì?

Thư viện sơ đồ mô hình C4 là một khung kiến trúc phân cấp, bốn cấp độ, được thiết kế để ghi chép kiến trúc phần mềm với các mức độ chi tiết khác nhau. Được tạo bởi Simon Brown, C4 tránh những hình hộp và đường nét mơ hồ bằng cách cấu trúc bản đồ hệ thống thành bốn ống kính trừu tượng rõ ràng: Bối cảnh (phạm vi cấp hệ thống), Bộ chứa (ứng dụng và kho lưu trữ dữ liệu), Thành phần (các mô-đun nội bộ), và Mã nguồn (triển khai ở cấp độ lớp).

Để triển khai mô hình này hiệu quả trong văn bản, các kỹ sư sử dụng thư viện mở rộng chính thức C4-PlantUMLmở rộng thư viện chuẩn. Thư viện này thay thế các hình dạng UML thô bằng các macro chuyên dụng, tự động chèn màu sắc, hình dạng và các trường dữ liệu phụ trợ riêng biệt cho người dùng, hệ thống và cơ sở dữ liệu. Với VPasCode, bạn có thể định nghĩa các môi trường lồng ghép này một cách sạch sẽ trong mã nguồn. Bộ động lực bố cục tự động định tuyến các vectơ kết nối và điều chỉnh kích thước các trường văn bản mà không làm hỏng hình dạng bố cục của bạn.

Hướng dẫn cú pháp cốt lõi: Các thành phần và cấu trúc

Xây dựng một mô hình C4 hợp lệ bằng PlantUML phụ thuộc vào việc nhập đúng các tệp thư viện, chọn các macro cấu trúc, thiết lập ranh giới và sử dụng các liên kết quan hệ chuyên biệt.

1. Nhập các tệp thư viện chuẩn C4

Thư viện C4-PlantUMLmở rộng được chia thành các tệp riêng biệt, tương ứng trực tiếp với các cấp độ khác nhau trong mô hình trừu tượng. Để tránh hiện tượng chậm hiệu suất hoặc lỗi biên dịch, bạn chỉ nên nhập lớp tệp cụ thể mà sơ đồ của bạn nhắm đến:

@startuml
' Nhập tệp lớp C4 cụ thể cần thiết
!include <C4/C4_Context>
' Sử dụng C4_Container hoặc C4_Component để tạo bản đồ kiến trúc sâu hơn

2. Khai báo các tác nhân và hệ thống cốt lõi (cấp độ Bối cảnh)

Ở cấp độ Bối cảnh hệ thống cấp cao, bạn mô hình hóa các thành phần nội bộ, các phụ thuộc bên ngoài và người dùng cuối là con người. Thư viện chuẩn cung cấp các macro cụ thể chấp nhận một ID, nhãn trực quan và một thẻ mô tả tùy chọn:

  • Person(id, "Nhãn", "Mô tả") — Đại diện cho hồ sơ người dùng con người hoặc tác nhân hệ thống.
  • System(id, "Nhãn", "Mô tả") — Đại diện cho một hệ sinh thái ứng dụng hoặc dịch vụ phần mềm nội bộ chính.
  • System_Ext(id, "Nhãn", "Mô tả") — Đại diện cho một hệ thống bên ngoài hoặc phụ thuộc API bên thứ ba (được hiển thị bằng bảng màu xám rõ ràng).
@startuml C4_Elements
!include <C4/C4_Context>
Person(customer, "Khách hàng Ngân hàng", "Một khách hàng có tài khoản ngân hàng cá nhân")
System(banking_sys, "Hệ thống Ngân hàng Chính", "Xử lý các giao dịch tài chính")
System_Ext(mail_sys, "Dịch vụ Thư điện tử", "Cổng thông báo SMTP nội bộ")

3. Mở rộng ranh giới (cấp độ Container và Thành phần)

Khi đi sâu hơn vào lớp Container, bạn mô hình hóa các ứng dụng web, microservices và cơ sở dữ liệu. Bạn có thể tách biệt các thành phần nội bộ này bên trong một hộp ranh giới logic rõ ràng bằng cách sử dụngSystem_Boundary()bọc macro:

!include <C4/C4_Container>

System_Boundary(c1, "Hệ sinh thái Hệ thống Thương mại điện tử") {
    Container(web_app, "Ứng dụng Trang đơn", "React & TypeScript", "Cung cấp các tính năng người dùng thông qua giao diện web")
    ContainerDb(database, "Cơ sở dữ liệu quan hệ", "PostgreSQL", "Lưu trữ hồ sơ người dùng và lịch sử sổ cái")
}

4. Bản đồ các mối quan hệ kỹ thuật

Thay vì dựa vào các đường nét đứt cơ bản, C4 sử dụng định dạng macro giao tiếp rõ ràng nhưRel(From_ID, To_ID, "Nhãn", "Công nghệ"). Điều này giúp bản đồ kiến trúc của bạn dễ đọc cao bằng cách buộc mỗi kết nối phải nêu rõ mục đích và giao thức truyền tải nền tảng (ví dụ: HTTPS, gRPC hoặc AMQP):

!include <C4/C4_Container>

Person(customer, "Khách hàng Ngân hàng", "Một khách hàng có tài khoản ngân hàng cá nhân")
System(banking_sys, "Hệ thống Ngân hàng Chính", "Xử lý các giao dịch tài chính")
System_Ext(mail_sys, "Dịch vụ Thư điện tử", "Cổng thông báo SMTP nội bộ")

System_Boundary(c1, "Hệ sinh thái Hệ thống Thương mại điện tử") {
    Container(web_app, "Ứng dụng Trang đơn", "React & TypeScript", "Cung cấp các tính năng người dùng thông qua giao diện web")
    ContainerDb(database, "Cơ sở dữ liệu quan hệ", "PostgreSQL", "Lưu trữ hồ sơ người dùng và lịch sử sổ cái")
}
Rel(customer, web_app, "Sử dụng các tính năng cửa hàng qua", "HTTPS")
Rel(web_app, database, "Đọc và ghi dữ liệu giao dịch qua", "SQL/TCP")

Các thực hành tốt nhất cho kiến trúc C4 dễ đọc

  • Không bao giờ trộn các mức độ trừu tượng:Giữ cho sơ đồ của bạn tập trung vào một lớp duy nhất. Không trộn các thành phần phần mềm nội bộ chi tiết vào bản đồ ngữ cảnh hệ thống cấp cao. Nếu một hệ thống trở nên quá phức tạp, hãy tách nó ra thành một sơ đồ cấp Container riêng biệt và chuyên biệt.
  • Xác định rõ ràng các công nghệ:Luôn tận dụng tham số thứ tư trong macro của bạnRel()để nêu rõ công nghệ hoặc giao thức cụ thể đang được sử dụng (ví dụ:"JSON/HTTPS" hoặc "JDBC"). Điều này cung cấp cho đội của bạn bối cảnh triển khai quan trọng chỉ trong một cái nhìn.
  • Tận dụng các ghi đè bố cục theo hướng: Nếu các thành phần của bạn bắt đầu chồng chéo một cách khó chịu, hãy sử dụng các macro quan hệ theo hướng (như Rel_D() để xuống, Rel_R() để phải, hoặc Rel_L() để trái) để tự tay làm sạch luồng kiến trúc của bạn.

Ví dụ thực tế về PlantUML C4

Ví dụ 1: Bố cục Bối cảnh Hệ thống cấp cao (Mức 1)

Bản thiết kế chức năng này mô hình hóa một sơ đồ Bối cảnh Hệ thống Mức 1 tiêu chuẩn, chi tiết cách khách hàng tương tác với ứng dụng ngân hàng trực tuyến và các phụ thuộc bên ngoài của nó.

@startuml
!include <C4/C4_Context>

title Sơ đồ Bối cảnh Hệ thống cho Hệ thống Ngân hàng Trực tuyến

Person(customer, "Khách hàng Ngân hàng Cá nhân", "Một khách hàng của ngân hàng có tài khoản cá nhân.")
System(banking_system, "Hệ thống Ngân hàng Trực tuyến", "Cho phép khách hàng xem thông tin tài chính và thực hiện chuyển khoản.")
System_Ext(mail_system, "Hệ thống Thư điện tử", "Cụm máy chủ thư điện tử nội bộ doanh nghiệp SendGrid.")

Rel(customer, banking_system, "Sử dụng bảng điều khiển trực tuyến qua")
Rel_R(banking_system, mail_system, "Gửi thông báo và mã xác minh bằng", "SMTP")
@enduml

Phân tích cú pháp: Sơ đồ này chỉ tập trung vào phạm vi cấp cao. Macro System_Ext tự động áp dụng kiểu màu xám cho dịch vụ thư điện tử, tách biệt trực quan hệ thống chính từ các phụ thuộc bên ngoài. Macro Rel_R buộc động cơ bố cục đặt nút thư điện tử ngay bên phải khối hệ thống ngân hàng.

Ví dụ 2: Topo container Microservice chi tiết sâu (Mức 2)

Bản thiết kế doanh nghiệp nâng cao này phân tích một hệ thống thành các ứng dụng container thành phần và các kho dữ liệu cô lập, cho thấy cách lưu lượng web được định tuyến qua cổng API xuống các microservice phía sau.

@startuml
!include <C4/C4_Container>

title Sơ đồ Container cho Cổng Thanh toán Portal

Person(merchant, "Đối tác Thương mại Web", "Tích hợp các điểm cuối thanh toán nền tảng vào trang web của họ.")

System_Boundary(portal_scope, "Ecosys Cổng Thanh toán") {
    Container(api_gateway, "Cổng định tuyến API", "Nginx", "Chụp các cuộc gọi đầu vào, xử lý giới hạn tốc độ và cân bằng các nút.")
    Container(auth_service, "Microservice Xác thực", "Go & OAuth2", "Xác minh token API và phạm vi của nhà phát triển.")
    Container(txn_service, "Sổ giao dịch", "Java Spring Boot", "Xử lý thanh toán và quản lý tài khoản sổ giao dịch.")
    ContainerDb(ledger_db, "Kho dữ liệu Sổ giao dịch", "CockroachDB", "Thực hiện các lược đồ bảng tuân thủ ACID phân tán.")
}

' Định tuyến luồng lưu lượng một cách rõ ràng qua các mục tiêu container nội bộ
Rel(merchant, api_gateway, "Gửi dữ liệu thanh toán qua", "HTTPS/JSON")
Rel_D(api_gateway, auth_service, "Xác minh token đầu vào qua", "gRPC")
Rel_D(api_gateway, txn_service, "Chuyển tiếp hành động thanh toán đến", "gRPC")
Rel_R(txn_service, ledger_db, "Lưu trữ các mục giao dịch qua", "SQL/TLS")
@enduml

Phân tích cú pháp: Bằng cách sử dụng Hệ thống_Biên_giới bao bọc macro, các thành phần nội bộ được nhóm gọn gàng bên trong một hộp viền rõ ràng. Macro chuyên dụng ContainerDb macro hiển thị kho dữ liệu với biểu tượng hình trụ cơ sở dữ liệu rõ ràng, giúp phân biệt rõ ràng giữa các lớp thời gian chạy tính toán và lớp lưu trữ bền vững chỉ trong một cái nhìn.

Lên đầu trang