作者:京東物流 覃玉杰
1. 前言
本文將給大家介紹一種簡潔明了軟體架構可視化模型——C4模型,并手把手教大家如何使用代碼繪制出精美的C4架構圖,
閱讀本文之后,讀者畫的架構圖將會是這樣的:

注:該圖例僅作繪圖示例使用,不確保其完整性、可行性,
2. C4模型
2.1 C4模型整體介紹
C4是軟體架構可視化的一種方案,架構可視化,指的是用圖例的方式,把軟體架構設計準確、清晰、美觀地表示出來,架構可視化不是指導開發者如何進行架構設計,而是指導開發者將架構設計表達出來,產出簡潔直觀的架構圖,
架構可視化的方法有很多,主流的有“4+1”視圖模型、C4模型,視圖模型描述的是架構本身,架構確定之后,不管用什么模型去表達,本質上都應該是一樣的,并沒有優劣之分,
C4 模型是一種易于學習、對開發人員友好的軟體架構圖示方法,C4模型沒有規定使用特定的圖形、特定的建模語言來畫圖,因而使用者可以非常靈活地產出架構圖,
C4模型將系統從上往下分為System Context, Containers, Components, Code四層視圖,每一層都是對上一層的完善和展開,層層遞進地對系統進行描述,如下圖,


2.2 System Context diagram
System Context(系統背景關系)視圖位于頂層,是軟體系統架構圖的起點,表達的是系統的全貌,System Context視圖重點展示的是系統邊界、系統相關的用戶、其他支撐系統以及與本系統的互動,本層不涉及到具體細節(例如技術選型、協議、部署方案和其他低級細節),因此System Context可以很好地向非技術人員介紹系統,
作用:清晰地展示待構建的系統、用戶以及現有的IT基礎設施,
范圍:待描述的核心系統以及其相關用戶、支撐系統,不應該出現與核心系統無關的其他系統,例如我們要描述一個打車系統,不應該把無關聯的藥店系統繪制進去,并且要確保一個System Context只有一個待描述的軟體系統,
主要元素:Context內待描述的軟體系統,
支持元素:在范圍內直接與主要元素中的軟體系統有關聯的人員(例如用戶、參與者、角色或角色)和外部依賴系統,通常,這些外部依賴系統位于我們自己的軟體系統邊界之外,
目標受眾:軟體開發團隊內外的所有人,包括技術人員和非技術人員,
推薦給大多數團隊:是的,
示例:
這是該網上銀行系統的系統背景關系圖,它顯示了使用它的人,以及與該系統有關系的其他軟體系統,網上銀行系統是將要建設的系統,銀行的個人客戶使用網上銀行系統查看其銀行賬戶的資訊并進行支付,網上銀行系統本身使用銀行現有的大型機銀行系統來執行此操作,并使用銀行現有的電子郵件系統向客戶發送電子郵件,

圖例:

2.3 Container diagram
Container(容器)視圖是對System Context的放大,是對System Context細節的補充,
注意這里的容器,指的不是Docker等容器中間件,Container的描述范圍是一個可單獨運行/可部署的單元,Container一般指的是應用以及依賴的中間件,例如服務器端 Web 應用程式、單頁應用程式、桌面應用程式、移動應用程式、資料庫架構、檔案系統、Redis、ElasticSeach、MQ等,
Container顯示了軟體架構的高級形狀以及系統內各容器之間的職責分工,
在Container這一層,還顯示了系統的主要的技術選型以及容器間的通信和互動,
作用:展示系統整體的開發邊界,體現高層次的技術選型,暴露系統內容器之間的分工互動,
范圍:單個軟體系統,關注的系統內部的應用構成,
主要元素:軟體系統范圍內的容器,例如Spring Boot打包后的應用,MySQL資料庫、Redis、MQ等,
支持元素:直接使用容器的人員和外部依賴系統,
目標受眾:軟體開發團隊內外的技術人員,包括軟體架構師、開發人員和運營/支持人員,
推薦給大多數團隊:是的,
注意:Container視圖沒有說明部署方案、集群、復制、故障轉移等,部署相關的視圖,會通過Deployment視圖進行展示,
示例:
網上銀行系統(此時System Contenxt中的系統已經被展開,所以用虛線框表示)由五個容器組成:服務器端 Web 應用程式、單頁應用程式、移動應用程式、服務器端 API 應用程式和資料庫,
- Web 應用程式是一個 Java/Spring MVC Web 應用程式,它只提供構成單頁應用程式的靜態內容(HTML、CSS 和 JS),
- 單頁應用程式是在客戶的網路瀏覽器中運行的 Angular 應用程式,是網上銀行功能的前端,
- 客戶也可以使用跨平臺 Xamarin 移動應用程式來訪問網上銀行,
- 單頁應用程式和移動應用程式都使用 JSON+HTTPS API,該 API 由運行在服務器上的另一個 Java/Spring MVC 應用程式提供,
- API 應用程式從關系資料庫中獲取用戶資訊,
- API 應用程式還使用專有的 XML/HTTPS 介面與現有的大型機銀行系統進行通信,以獲取有關銀行賬戶的資訊或進行交易,
- 如果 API 應用程式需要向客戶發送電子郵件,它也會使用現有的電子郵件系統,

該容器圖的圖例如下,主要是引入了資料庫、APP、瀏覽器的圖例,

2.4 Component diagram
將單個容器放大,則顯示了該容器內部的組件,Component(組件)視圖顯示了一個容器是如何由許多“組件”組成的,每個組件是什么,它們的職責以及技術實作細節,
作用:展示了可執行的容器內部構成與分工,可直接指導開發,
范圍:單個容器,
主要元素:范圍內容器內的組件,通常可以是Dubbo介面、REST介面、Service、Dao等,
支持元素:直接連接到容器的人員和外部依賴系統,
目標受眾:軟體架構師和開發人員,
推薦給大多數團隊:Component用于指導開發,當有需要時創建,
示例:

圖例:

2.5 Code diagram
放大組件視圖,則得到出組件的Code視圖(代碼視圖),
Code視圖一般采用 UML 類圖、ER圖等,Code視圖是一個可選的詳細級別,通常可以通過 IDE 等工具按需生成,除了最重要或最復雜的組件外,不建議將這種詳細程度用于其他任何內容,
在注重敏捷開發的今天,一般不建議產出Code視圖,
范圍:單個組件,
主要元素:范圍內組件內的代碼元素(例如類、介面、物件、函式、資料庫表等),
目標受眾:軟體架構師和開發人員,
推薦給大多數團隊:不,大多數 IDE 可以按需生成這種級別的詳細資訊,
2.6 System Landscape diagram
C4 模型提供了單個軟體系統的靜態視圖,不管是 System Context、Container、Component都是針對單個軟體系統的進行描述的,但在實際中軟體系統不會孤立存在,為描述所有這些軟體系統如何在給定的企業、組織、部門等中與其他系統組合在一起,C4采用擴展視圖System Landscape (系統景觀圖),
系統景觀圖實際上只是一個沒有特定關注的軟體系統的系統背景關系圖(System Context diagram),系統景觀圖內的軟體系統都可以采用C4進行深入分析,
適用范圍:企業/組織/部門/等,
主要元素:與所選范圍相關的人員和軟體系統,
目標受眾:軟體開發團隊內外的技術人員和非技術人員,
示例:

圖例:

2.7 Dynamic diagram
Dynamic diagram(動態圖)用于展示靜態模型中的元素如何在運行時協作,動態圖允許圖表元素自由排列,并通過帶有編號的箭頭以指示執行順序,
范圍:特定功能、故事、用例等,
主要元素和支持元素:按照實際需要,可以是軟體系統、容器或組件,
目標受眾:軟體開發團隊內外的技術人員和非技術人員,
示例:

圖例:

2.8 Deployment diagram
Deployment diagram(部署圖)用于說明靜態模型中的軟體系統(或容器)的實體在給定環境(例如生產、測驗、預發、開發等)中的部署方案,
C4的部署圖基于UML 部署圖,但為了突出顯示容器和部署節點之間的映射會做略微的簡化,
部署節點表示表示軟體系統/容器實體運行的位置,類似于物理基礎架構(例如物理服務器或設備)、虛擬化基礎架構(例如 IaaS、PaaS、虛擬機)、容器化基礎架構(例如 Docker 容器)、執行環境(例如資料庫服務器、Java EE web/應用服務器、Microsoft IIS)等,部署節點可以嵌套,也可以將基礎設施節點包括進去,例如 DNS 服務、負載平衡器、防火墻等,
可以在部署圖中隨意使用 Amazon Web Services、Azure 等提供的圖示,只需確保被使用的任何圖示都包含在圖例中,不產生歧義,
范圍:單個部署環境中的一個或多個軟體系統(例如生產、暫存、開發等),
主要元素:部署節點、軟體系統實體和容器實體,
支持元素:用于部署軟體系統的基礎設施節點,
目標受眾:軟體開發團隊內外的技術人員;包括軟體架構師、開發人員、基礎架構架構師和運營/支持人員,
示例:
網上銀行系統的開發環境部署圖:

圖例

網上銀行的生產環境部署圖:

圖例

2.9 C4模型規范以及Review CheckList
為了確保C4模型的架構圖的可讀性,C4模型提供了作圖規范,并且提供了CheckList供自查,
2.9.1 C4模型規范
- 圖表
每個圖都應該有一個描述圖型別和范圍的標題(例如“我的軟體系統的系統環境圖”),
每個圖表都應該有一個關鍵/圖例來解釋所使用的符號(例如形狀、顏色、邊框樣式、線型、箭頭等),
首字母縮略詞和縮寫詞(業務/領域或技術)應為所有受眾所理解,或在圖表鍵/圖例中進行解釋,
- 元素
應明確指定每個元素的型別(例如,人員、軟體系統、容器或組件),
每個元素都應該有一個簡短的描述,以提供關鍵職責的“一目了然”的視圖,
每個容器和組件都應該有明確指定的技術,
- 關系
每條線都應該代表一個單向關系,
每一行都應該被標記,標記與關系的方向和意圖一致(例如依賴或資料流),嘗試盡可能具體地使用標簽,最好避免使用“使用”等單個詞,
容器之間的關系(通常代表行程間通信)應該有明確標記的技術/協議,
2.9.2 Review Checklist
C4模型圖表繪制完成后,可以通過Review Checklist 進行自查,檢查是否有不規范之處,Review Checklist被制成網頁,可以通過 https://c4model.com/review/ 進行訪問,

3. C4模型架構圖代碼繪制實戰
3.1 文本繪圖工具選型
關于C4模型的架構圖的繪制,一般有兩種方式:
第一種是采用繪圖工具,這類工具直接拖拽元素、調整樣式,即可產出圖片,例如draw.io、PPT等工具,繪圖工具的優點是非常靈活,可以滿足很多細節需求;缺點是通常調整元素的樣式會比較繁瑣,
第二種是采用基于文本的繪圖工具,根據一定的語法去描述圖片元素,最后根據文本自動渲染成圖片,例如PlantUML,基于文本的繪圖工具的優點是繪圖快捷,只要根據語法寫出描述檔案,即可渲染出來,元素的樣式已經默認除錯好;缺點是樣式不一定符合我們的審美,調整不方便,
本文著重講解第二種,即基于文本的繪圖工具,
基于文本的繪圖工具有很多,例如:structurizr、PlantUML、mermaid,分別有自己的語法,
| 工具 | 語法 | 使用方式 | 地址 |
|---|---|---|---|
| structurizr | DSL | 提供Web界面渲染圖片,并且可以生成C4-PlantUML和mermaid的代碼 | https://structurizr.com/ |
| C4-PlantUML | PlantUML | VS Code插件、IntelliJ Idea插件 | https://github.com/plantuml-stdlib/C4-PlantUML |
| mermaid | mermaid | Markdown插件,提供Live Editor | https://mermaid.js.org/syntax/c4c.html ,Mermaid Live Editor |
由于IntelliJ Idea、VS Code目前在開發者中非常普及,我們選擇使用C4-PlantUML,結合VS Code和IntelliJ Idea分別進行C4模型的繪制,
VS Code環境的安裝,見3.2,
IntelliJ Idea環境的安裝,見3.3
3.2 VS Code 下C4-PlantUML安裝
3.2.1 安裝VS Code
直接官網下載安裝即可,程序略去,
3.2.2 安裝PlantUML插件
在VS Code的Extensions視窗中搜索PlantUML,安裝PlantUML插件,

3.2.3 配置VS Code代碼片段
安裝完PlantUML之后,為了提高效率,我們最好安裝PlantUML相關的代碼片段,
打開VS Code選單,層級為Code→Preferences→User Snippets,如下圖:

在選擇Snippets File Or Create Snippets彈窗中,選擇New Global Snippets file,如下圖:

在接下來的彈窗中,輸入Snippets file的檔案名,如下圖:

使用瀏覽器打開以下鏈接,并將瀏覽器回傳的文本內容粘貼到VS Code編輯區
https://github.com/plantuml-stdlib/C4-PlantUML/blob/master/.vscode/C4.code-snippets
如圖:

3.2.4 安裝Graphviz
如果圖形渲染出現問題,提示安裝graphviz庫,直接到graphviz官網安裝即可,官網鏈接如下:
https://graphviz.gitlab.io/download/
Mac系統推薦采用MacPorts安裝,
3.3 IntelliJ Idea 下C4-PlantUML安裝
3.3.1 安裝Idea
3.3.2 安裝PlantUML Integration插件

3.3.3 安裝代碼模版
通過以下鏈接,下載IntelliJ live template,
https://github.com/plantuml-stdlib/C4-PlantUML/blob/master/intellij/c4_live_template.zip
通過選單路徑 File | Manage IDE Settings | Import Settings ,選擇下載的 ZIP檔案, c4_live_template.zip,匯入并重啟Idea即可,
3.4 案例實戰及C4-PlantUML語法介紹
C4-PlantUML的詳細語法可以到官網github專案主頁( https://github.com/plantuml-stdlib/C4-PlantUML )去了解,在此只做簡單介紹,
3.4.1 案例
以某招聘APP服務端架構圖(Container級)為例子進行講解,以下是渲染出來的效果圖,

以下是完整plantuml代碼:
@startuml
!include https://raw.githubusercontent.com/plantuml-stdlib/C4-PlantUML/master/C4_Context.puml
!include https://raw.githubusercontent.com/plantuml-stdlib/C4-PlantUML/master/C4_Container.puml
!include https://raw.githubusercontent.com/plantuml-stdlib/C4-PlantUML/master/C4_Component.puml
!define SPRITESURL https://raw.githubusercontent.com/rabelenda/cicon-plantuml-sprites/master/sprites
!define DEVICONS https://raw.githubusercontent.com/tupadr3/plantuml-icon-font-sprites/master/devicons
!define DEVICONS2 https://raw.githubusercontent.com/tupadr3/plantuml-icon-font-sprites/master/devicons2
!define FONTAWESOME https://raw.githubusercontent.com/tupadr3/plantuml-icon-font-sprites/master/font-awesome-5
!include DEVICONS/java.puml
!include DEVICONS/mysql.puml
!include DEVICONS2/spring.puml
!include DEVICONS2/redis.puml
!include DEVICONS2/android.puml
!include DEVICONS2/apple_original.puml
title 招聘APP架構圖(Container)
Person(P_User, "找作業的APP用戶(應聘者)")
System_Boundary(Boundary_APP, "招聘APP系統邊界"){
Container(C_ANDROID, "安卓移動端", "android", "移動APP安卓端",$sprite="android")
Container(C_IOS, "iOS移動端", "iOS", "移動APP iOS端",$sprite="apple_original")
Container(C_GATEWAY, "HTTP網關", "Netty", "鑒權、協議轉換",$sprite="java")
Container(C_GATEWAY_CACHE, "網關快取", "Redis", "快取認證憑據",$sprite="redis")
Container(C_BFF, "BFF網關", "Spring Boot","整合后端介面",$sprite="spring")
Container(C_CERT, "實名認證服務", "Spring Boot", "內部實名認證服務",$sprite="spring")
Container(C_BIZ_1, "職位服務", "Spring Boot", "發布、搜索職位",$sprite="spring")
Container(C_PAYMENT, "支付服務", "Spring Boot", "內部支付服務",$sprite="spring")
ContainerDb(CDB_MYSQL, "職位資訊資料庫", "MySQL", "持久化職位資訊",$sprite="mysql")
}
System_Ext(OUT_S_CERT, "實名認證服務","對用戶進行姓名身份證號實名認證")
System_Ext(OUT_S_PAYMENT, "第三方支付服務","支持用戶使用多種支付方式完成支付")
Rel(P_User, C_ANDROID, "注冊登陸投遞簡歷")
Rel(P_User, C_IOS, "注冊登陸投遞簡歷")
Rel(C_ANDROID, C_GATEWAY, "請求服務端","HTTPS")
Rel(C_IOS, C_GATEWAY, "請求服務端","HTTPS")
Rel_L(C_GATEWAY, C_GATEWAY_CACHE, "讀寫快取","jedis")
Rel(C_GATEWAY, C_BFF, "將HTTP協議轉為RPC協議","RPC")
Rel(C_GATEWAY, C_BIZ_1, "將HTTP協議轉為RPC協議","RPC")
Rel(C_GATEWAY, C_PAYMENT, "將HTTP協議轉為RPC協議","RPC")
Rel(C_BFF, C_CERT, "通過BFF處理之后,對外暴露介面服務","RPC")
Rel(C_BIZ_1, CDB_MYSQL, "讀寫資料","JDBC")
Rel(C_CERT, OUT_S_CERT, "對接外部查詢實名資訊介面","HTTPS")
Rel(C_PAYMENT, OUT_S_PAYMENT, "對接外部支付系統","HTTPS")
left to right direction
SHOW_LEGEND()
@enduml
3.4.2 PlantUML檔案
PlantUML檔案以puml作為檔案擴展名,
3.4.3 @startuml和@enduml
整個檔案由@startuml和@enduml包裹,是固定語法,
@startuml
@enduml
3.4.4 注釋
PlantUML中使用單引號(即')作為注釋標識,
3.4.5 include陳述句
首先是C4各個視圖的include陳述句,以下陳述句代表引入了C4的Context、Container、Component視圖,
!include https://raw.githubusercontent.com/plantuml-stdlib/C4-PlantUML/master/C4_Context.puml
!include https://raw.githubusercontent.com/plantuml-stdlib/C4-PlantUML/master/C4_Container.puml
!include https://raw.githubusercontent.com/plantuml-stdlib/C4-PlantUML/master/C4_Component.puml
其次是圖示庫:
!define SPRITESURL https://raw.githubusercontent.com/rabelenda/cicon-plantuml-sprites/master/sprites
!define DEVICONS https://raw.githubusercontent.com/tupadr3/plantuml-icon-font-sprites/master/devicons
!define DEVICONS2 https://raw.githubusercontent.com/tupadr3/plantuml-icon-font-sprites/master/devicons2
!define FONTAWESOME https://raw.githubusercontent.com/tupadr3/plantuml-icon-font-sprites/master/font-awesome-5
!include DEVICONS/java.puml
!include DEVICONS/mysql.puml
!include DEVICONS2/spring.puml
!include DEVICONS2/redis.puml
!include DEVICONS2/android.puml
!include DEVICONS2/apple_original.puml
注意這里有一個define語法,先通過!define定義一個標識,之后使用該標識的地方都會被替換
!define DEVICONS2 https://raw.githubusercontent.com/tupadr3/plantuml-icon-font-sprites/master/devicons2
!include DEVICONS2/spring.puml
‘ 等價于 !include https://raw.githubusercontent.com/tupadr3/plantuml-icon-font-sprites/master/devicons2/spring.puml
使用圖示時,只需要在元素的宣告陳述句中加入$sprite="xxx"即可,
ContainerDb(CDB_MYSQL, "職位資訊資料庫", "MySQL", "持久化職位資訊",$sprite="mysql")
3.4.6 C4模型靜態元素
Person:系統的用戶,可能是人或者其他系統
System:代表即將建設的系統,通常渲染為藍色方塊,
System_Ext:代表已存在的系統,通常渲染為灰色方塊,
System_Boundary:某系統展開為容器時,則將System改為System_Boundary,代表系統的邊界,內部放置容器元素,通常渲染為虛線框,
Container:待建設的容器,通常渲染為藍色方塊,
Container_Ext:已建設容器,通常渲染為灰色方塊,
Container_Boundary:某容器展開為組件之后,則將Container改為Container_Boundary,代表容器的邊界,內部放置組件元素,通常渲染為虛線框,
ContainerDb:待建設資料庫,通常渲染為藍色圓柱,
ContainerQueue:待建設訊息佇列,通常渲染為水平放置的藍色圓柱,
Component:待建設組件,通常渲染為藍色方塊,
Component_Ext:已建設組件,通常渲染為灰色方塊,
靜態元素的語法為:
Container(alias, "label", "technology", "description")
alias:是圖內元素的唯一ID,其他地方可以通過alias進行參考,比如在Rel中參考
label:代表元素的顯示名稱
technology:代表元素采用的核心技術,包括但不限于開發語言、框架、通信協議等
description:代表元素的簡單描述

對于System_Boundary和Container_Boundary,則只需要alias和label,大括號內是該元素邊界內的子元素,
Container_Boundary(alias, "label"){
}
3.4.7 C4模型的關系元素
Rel代表兩個元素之間的關系,其語法為:
Rel(from_alias, to_alias, "label", "technology")
from_alias是起點元素的別名,to_alias是終點元素的別名,label則用來說明這個關聯關系,technology代表采用的技術、通信協議,例如:
Rel(C_IOS, C_GATEWAY, "請求服務端","HTTPS")
代表iOS客戶端通過請求網關介面訪問服務端資源,采用HTTPS的通信方式,
建議在繪制Rel時標注出technology,
3.4.8 C4-PlantUML布局
C4-PlantUML提供了多種自動布局方案,我們可以根據實際需要進行選擇,
- LAYOUT_TOP_DOWN():從上往下布局,默認采用該布局,如下圖:

- LAYOUT_LEFT_RIGHT():從左到右,即橫向放置元素,
left to right direction是PlantUML的語法,也可以直接用,
3.4.9 圖例
通過SHOW_LEGEND()添加圖例,

轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/552573.html
標籤:其他
下一篇:返回列表
