什麼是 C4 模型圖?
這個C4 模型圖是一個分層的四層架構框架,旨在以不同細緻程度記錄軟體架構。由西蒙·布朗所創建,C4 透過將系統地圖結構化為四個明確的抽象鏡頭,避免模糊的方框與線條:上下文(系統層級範圍),容器(應用程式與資料儲存),組件(內部模組),以及程式碼(類別層級的實作)。
為了在文字中有效實現此模型,工程師使用官方的C4-PlantUML標準函式庫擴充。此函式庫以專用巨集取代原始的 UML 形狀,自動注入使用者、系統與資料庫的獨特顏色、形狀與元資料欄位。使用VPasCode,您可以在程式碼中乾淨地定義這些巢狀環境。佈局引擎會動態路由連接向量並調整文字欄位大小,而不會破壞您的佈局幾何。
核心語法指南:元素與構造
使用 PlantUML 建立有效的 C4 模型,取決於匯入正確的函式庫檔案、選擇結構巨集、建立邊界,以及使用專用的關係連結。
1. 匯入 C4 標準函式庫檔案
這個C4-PlantUML擴充功能被拆分成單獨的檔案,直接對應到抽象模型的各個不同層級。為避免效能下降或編譯錯誤,您應僅匯入圖表所針對的特定檔案層級:
@startuml
' 匯入所需的特定 C4 層級檔案
!include <C4/C4_Context>
' 使用 C4_Container 或 C4_Component 以建立更深入的架構地圖
2. 聲明核心參與者與系統(上下文層級)
在高階的系統上下文層級中,您會模擬內部組件、外部相依性以及人類終端使用者。標準函式庫提供特定巨集,接受 ID、視覺標籤與可選的描述標籤:
Person(id, "標籤", "描述")— 代表人類使用者輪廓或系統參與者。System(id, "標籤", "描述")— 代表主要的內部軟體應用程式或服務生態系。System_Ext(id, "標籤", "描述")— 代表外部系統或第三方 API 依賴(以明確的灰色調呈現)。
@startuml C4_Elements
!include <C4/C4_Context>
Person(customer, "銀行客戶", "擁有個人銀行帳戶的客戶")
System(banking_sys, "核心銀行系統", "處理金融交易")
System_Ext(mail_sys, "電子郵件服務", "內部 SMTP 通知網關") 
3. 爆炸邊界(容器與組件層級)
深入探討容器層時,您會建模網頁應用程式、微服務和資料庫。您可以使用「System_Boundary()」巨集包裝器,將這些內部元件隔離於明確的邏輯邊界框內:
!include <C4/C4_Container>
System_Boundary(c1, "電子商務系統生態系") {
Container(web_app, "單頁應用程式", "React 與 TypeScript", "透過網頁檢視提供使用者功能")
ContainerDb(database, "關聯式資料庫", "PostgreSQL", "儲存使用者個人資料與帳目歷史記錄")
} 
4. 建立技術關係
不依賴基本的虛線,C4 使用明確的通訊巨集格式,如Rel(來源ID, 目標ID, "標籤", "技術")。這能讓您的架構圖高度易讀,因為強制要求每個連接都明確說明其目的與底層傳輸協定(例如 HTTPS、gRPC 或 AMQP):
!include <C4/C4_Container>
Person(customer, "銀行客戶", "擁有個人銀行帳戶的客戶")
System(banking_sys, "核心銀行系統", "處理金融交易")
System_Ext(mail_sys, "電子郵件服務", "內部 SMTP 通知網關")
System_Boundary(c1, "電子商務系統生態系") {
Container(web_app, "單頁應用程式", "React 與 TypeScript", "透過網頁檢視提供使用者功能")
ContainerDb(database, "關聯式資料庫", "PostgreSQL", "儲存使用者個人資料與帳目歷史記錄")
}
Rel(customer, web_app, "透過", "HTTPS")
Rel(web_app, database, "透過", "SQL/TCP") 
可讀性良好的 C4 架構最佳實務
- 絕不混合抽象層級: 讓您的圖表專注於單一層級。不要將細粒度的內部軟體元件混入高階的系統上下文圖中。如果系統過於複雜,應將其拆分為獨立的、專用的容器層級圖表。
- 明確定義技術: 始終善用您「
Rel()」巨集的第四個參數,以明確指出所使用的精確技術或協定(例如,"JSON/HTTPS"或"JDBC"). 這能讓你的團隊一目了然地掌握關鍵的實作背景。 - 利用方向性佈局覆寫: 如果你的元件開始出現堆疊不自然的情況,請使用方向性關係巨集(例如
Rel_D()表示向下,Rel_R()表示向右,或Rel_L()表示向左)手動整理你的架構流程。
真實世界的 PlantUML C4 範例
範例 1:高階系統脈絡佈局(第 1 層)
此功能藍圖模擬標準的第 1 層系統脈絡圖,詳細說明客戶如何與網路銀行應用程式及其外部依賴項互動。
@startuml
!include <C4/C4_Context>
title 網路銀行系統的系統脈絡圖
Person(customer, "個人銀行客戶", "擁有個人帳戶的銀行客戶。")
System(banking_system, "網路銀行系統", "讓客戶查看財務資訊並進行轉帳。")
System_Ext(mail_system, "電子郵件子系統", "內部企業 SendGrid 企業郵件伺服器叢集。")
Rel(customer, banking_system, "透過線上儀表板使用")
Rel_R(banking_system, mail_system, "使用", "SMTP")
@enduml 
語法解析: 此圖僅著重於高階範圍。System_Ext 巨集會自動為電子郵件服務套用灰色色調,視覺上將核心系統與外部依賴項分離。Rel_R 巨集會強制佈局引擎將郵件節點直接置於銀行系統區塊的右側。
範例 2:深入探討微服務容器拓撲(第 2 層)
此進階企業藍圖將系統拆解為其組成的容器應用程式與獨立的資料儲存,展示網路流量如何透過 API 網關傳遞至後端微服務。
@startuml
!include <C4/C4_Container>
title 支付門戶網關的容器圖
Person(merchant, "網路商家合作夥伴", "將平台結帳端點整合至其網站。")
System_Boundary(portal_scope, "支付網關生態系") {
Container(api_gateway, "API 路由代理", "Nginx", "截獲入站呼叫,處理頻率限制並平衡節點。")
Container(auth_service, "身分驗證微服務", "Go & OAuth2", "驗證開發者 API 憑證與權限範圍。")
Container(txn_service, "交易帳本", "Java Spring Boot", "處理付款並管理帳本帳戶。")
ContainerDb(ledger_db, "帳本資料儲存", "CockroachDB", "實作分散式 ACID 合規的表格結構。")
}
' 路由流量順暢地穿越內部容器目標
Rel(merchant, api_gateway, "透過", "HTTPS/JSON")
Rel_D(api_gateway, auth_service, "透過", "gRPC")
Rel_D(api_gateway, txn_service, "轉發結帳動作至", "gRPC")
Rel_R(txn_service, ledger_db, "透過", "SQL/TLS")
@enduml 
語法分解: 透過使用 System_Boundary 宏包裝器,內部組件會乾淨地聚集在一個清晰的邊界框內。專用的 ContainerDb 宏會以明確的資料庫圓柱圖示呈現資料儲存,讓計算執行環境與持久化儲存層之間的區分一目了然。