橫看成嶺側(cè)成峰,遠(yuǎn)近高低各不同。為了更好地理解軟件系統(tǒng),我們需要借助于多種圖表工具,從不同的視角出發(fā),全方位的理解系統(tǒng)設(shè)計(jì)。以便在設(shè)計(jì)階段足夠充分預(yù)估系統(tǒng)瓶頸,實(shí)施難度,開發(fā)工時(shí)等,在業(yè)務(wù)功能上實(shí)現(xiàn)良好擴(kuò)展性,性能上高可靠,高可用。達(dá)到數(shù)據(jù)絕對(duì)安全,性能足夠優(yōu)異。支撐業(yè)務(wù)需求快速迭代。
軟件系統(tǒng)可以按如下分層
- Iass: 基礎(chǔ)設(shè)施軟件,包括操作系統(tǒng)(網(wǎng)絡(luò),存儲(chǔ),計(jì)算),虛擬機(jī),Docker等基礎(chǔ)軟件。
- Paas 平臺(tái)即服務(wù): 包括我們?nèi)粘5南?,緩存,?shù)據(jù)庫,等中間件。也應(yīng)該包括框架和 類庫。例如ioc,orm,rpc框架; 圖片,特殊文件處理的第三方類庫等
- Saas 軟件即服務(wù): 我們?nèi)粘5囊恍?yīng)用,無論是2B,2C都屬于此。
以下我們將重點(diǎn)分析借助哪些圖表工具 可以分析 應(yīng)用軟件系統(tǒng)(Saas層)。這些圖表的閱讀者 應(yīng)該是開發(fā)者,產(chǎn)品經(jīng)理,業(yè)務(wù)架構(gòu)師,系統(tǒng)架構(gòu)師,技術(shù)管理者等。
用例圖
用例圖是最清晰,最容易理解的圖表,用例圖從用戶角度出發(fā)
要素
- 如何使用我們的系統(tǒng)。如果系統(tǒng)已經(jīng)完成,可以使用簡潔版本的 用戶使用手冊(cè)代替。
- 有哪幾種使用流程,哪些應(yīng)用場景。
- 每種流程需要做哪些事情。
用例圖首先需要分析系統(tǒng)有哪些使用人員,可以借助以下問題分析
- 誰將使用該系統(tǒng)的主要功能。
- 誰 將需要該系統(tǒng)的支持以完成其工作。
- 誰將需要維護(hù)、管理該系統(tǒng),以及保持該系統(tǒng)處于工作狀態(tài)。
例如簡單的用戶修改資料

用例圖因?yàn)槠浜唵沃卑?,容易被系統(tǒng)設(shè)計(jì)者忽略,實(shí)際上 對(duì)于一個(gè)完全未接觸系統(tǒng)的人,用例圖是最友好,最直白的,可以讓小白 快速的了解我們的系統(tǒng) 給哪些人提供了哪些功能。功能之間的聯(lián)系是什么
用例規(guī)約
用例規(guī)約是對(duì)用例的詳細(xì)描述,一般包括簡要說明、主事件流、備選事件流、前置條件、后置條件和優(yōu)先級(jí)等。
用例規(guī)約既關(guān)注主事件流所描述的成功場景,也關(guān)注備選事件流所描述的異常場景,有利于促進(jìn)系統(tǒng)化思維、發(fā)現(xiàn)異常場景、完善系統(tǒng)功能和提高易用性。
后置條件應(yīng)覆蓋所有可能的用例結(jié)束后的狀態(tài)。即后置條件不僅僅是用例成功結(jié)束后的狀態(tài),還應(yīng)該包含用例因發(fā)生錯(cuò)誤而結(jié)束后的狀態(tài)。
示例

一般情況可以只描述重要需求,關(guān)鍵用例的用例規(guī)約。一般需求可以忽略。(PRD里絕對(duì)不能忽略)
用例圖和系統(tǒng)頁面 如果有 更詳細(xì)的使用手冊(cè),則可以更快速的全面理解系統(tǒng)的功能。例如展示一下我們的系統(tǒng)頁面。更加直觀和清晰。
只有更好的了解系統(tǒng)提供了哪些功能,有哪幾種角色,才能理解 系統(tǒng)為什么這么設(shè)計(jì)? 某些人之所以會(huì)覺得用例圖多此一舉, 是因?yàn)槠鋵?duì)系統(tǒng)本身足夠了解。但是他們忽略其他人對(duì)系統(tǒng)還是完全一片陌生。需要借助用例圖,最直白的了解系統(tǒng)
數(shù)據(jù)模型圖
程序=數(shù)據(jù)結(jié)構(gòu)+算法,軟件程序就是對(duì)輸入數(shù)據(jù)進(jìn)行處理,按照一定的算法,輸出特定的數(shù)據(jù)。 數(shù)據(jù)是程序的核心,也是容易變化的部分,例如最常見的變化: 需要增減字段。
此時(shí)需要對(duì)數(shù)據(jù)進(jìn)行建模,梳理模型之間的關(guān)聯(lián)關(guān)系,為的是把關(guān)系最緊密的數(shù)據(jù) 放到一個(gè)模型里,獨(dú)立擴(kuò)展。 數(shù)據(jù)模型圖描述了 模型之間的關(guān)聯(lián)關(guān)系,每個(gè)模型有哪些字段 。 三要素 ● 模型 ● 屬性 ● 模型間關(guān)聯(lián)關(guān)系
數(shù)據(jù)模型圖包括 E-R圖,數(shù)據(jù)庫實(shí)體圖。等。
- E-R圖使用中文,不涉及表結(jié)構(gòu),更簡單。
- 數(shù)據(jù)庫模型層: 描述數(shù)據(jù)庫層面的關(guān)聯(lián)關(guān)系和表設(shè)計(jì), 雖然比ER圖更復(fù)雜, 但是更全面,適用人群都可以看懂。
- 大多數(shù)情況下 我們的設(shè)計(jì)文檔是給產(chǎn)品和研發(fā),技術(shù)管理者看的。使用數(shù)據(jù)庫實(shí)體圖也可以看懂。(看不懂的讓他去學(xué))
個(gè)人認(rèn)為設(shè)計(jì)文檔里可以忽略E-R圖,直接上數(shù)據(jù)庫實(shí)體圖。但是這就要求數(shù)據(jù)庫實(shí)體圖 有充分的文字說明,例如屬性注釋,關(guān)聯(lián)關(guān)系說明等。
E-R 圖示例

數(shù)據(jù)庫實(shí)體圖(數(shù)據(jù)庫 ER 圖)

數(shù)據(jù)庫 ER 圖的梳理過程
數(shù)據(jù)庫 ER 圖,實(shí)體圖或者 領(lǐng)域模型圖的設(shè)計(jì)非常考驗(yàn)設(shè)計(jì)經(jīng)驗(yàn)。需要領(lǐng)域?qū)<腋鶕?jù)用例圖,用例流程圖,反復(fù)的需求溝通。不斷地推敲以下問題
- 業(yè)務(wù)的擴(kuò)展點(diǎn),變化方向 在哪里,未來計(jì)劃的演進(jìn)方向。
- 系統(tǒng)的擴(kuò)展方向是哪里?如何實(shí)現(xiàn)擴(kuò)展性
- 應(yīng)該包括哪幾個(gè) 領(lǐng)域?qū)嶓w。
- 領(lǐng)域模型的邊界 應(yīng)該在哪里。關(guān)聯(lián)關(guān)系是 1V1,還是 1對(duì) N 等等。
數(shù)據(jù)庫 ER 圖的分析過程 可以使用 DDD 等設(shè)計(jì)方法 。
流程圖
系統(tǒng)設(shè)計(jì)階段 只需要覆蓋核心和關(guān)鍵的業(yè)務(wù)流程即可。對(duì)于細(xì)枝末節(jié)的一些簡單流程應(yīng)該忽略。 (有精力和時(shí)間可以覆蓋非核心流程)
管理流程和 用戶流程
以營銷系統(tǒng)為例,分為管理流程 和用戶流程
- 運(yùn)營創(chuàng)建了一個(gè)營銷活動(dòng)。這個(gè)過程是管理流程。這個(gè)流程對(duì)于性能的要求不高。流量入口不同。
- 用戶下單等行為, 觸發(fā)了某些營銷活動(dòng),這個(gè)流程對(duì)于性能要求,安全性要求就很高。
不同流程的關(guān)注點(diǎn)不同。例如dubbo的rpc系統(tǒng),也可以分為 初始化流程 和 方法調(diào)用流程
- rpc provider 接口提供者需要初始化時(shí)注冊(cè)接口。rpc consumer需要在初始化時(shí)監(jiān)聽接口。
- rpc調(diào)用流程 從consumer端到provider 是調(diào)用流程。
流程圖畫法

流程圖的畫法比較靈活。以下是個(gè)人經(jīng)驗(yàn)和習(xí)慣
- 組件思維: 可以描述 組件之間的控制流調(diào)用
- 數(shù)據(jù)思維: 可以描述數(shù)據(jù)之間的數(shù)據(jù)流變化。
一般使用方框表示 組件,連線 表示調(diào)用方法,動(dòng)作 或者數(shù)據(jù)。
組件思維
按照組件思維 設(shè)計(jì)流程圖。要求把系統(tǒng)的組件先抽象出來,每個(gè)組件處理哪個(gè)步驟。淡化了輸入輸出, 是簡化版的 調(diào)用時(shí)序圖。(時(shí)序圖描述方法調(diào)用層次,更加細(xì)化和清晰。)
以下示例是dubbo Provider端 暴露一個(gè)服務(wù)的 組件調(diào)用的控制流變化圖

數(shù)據(jù)思維
按照數(shù)據(jù)流程圖描述,組件之間傳遞的是 數(shù)據(jù),數(shù)據(jù)流描述了 一個(gè)組件或系統(tǒng)的輸入 和輸出 是什么。

其實(shí)大多數(shù)業(yè)務(wù)系統(tǒng),使用數(shù)據(jù)流程圖不太好劃分,因?yàn)?一個(gè)業(yè)務(wù)流程內(nèi)主要是針對(duì)兩三個(gè)模型進(jìn)行處理。組件之間的輸入輸出界限并不明顯 為此可以 將數(shù)據(jù)流程圖和控制圖 合二為一。 方框依然表示 組件,但是連線可以同時(shí)包括動(dòng)作和數(shù)據(jù)

流程圖中的非功能型設(shè)計(jì)
高可靠 高可用 性能瓶頸,流程圖中可以介紹核心讀寫流程的高可用,高可靠設(shè)計(jì); 即數(shù)據(jù)可靠性如何保證,系統(tǒng)可用性如何保證。性能瓶頸在流程中哪個(gè)節(jié)點(diǎn)。如何優(yōu)化等
以下僅供參考
- 數(shù)據(jù)存在哪里,同步/異步寫入,異步寫入的一致性保證
- 并發(fā)操作如何保證一致性(例如庫存?)
- 高并發(fā)場景如何提高系統(tǒng)可用性,讀流程如何優(yōu)化,寫流程如何優(yōu)化
- 是否 Stand-by 設(shè)計(jì)雙活。
- 冪等性,重試策略、負(fù)載均衡策略
時(shí)序圖
時(shí)序圖 是更加詳細(xì)的系統(tǒng)流程圖,一般的系統(tǒng)流程圖覆蓋了關(guān)鍵的系統(tǒng)組件,關(guān)鍵的數(shù)據(jù)處理節(jié)點(diǎn),但不會(huì)具體到哪一個(gè)類,哪一個(gè)方法。 時(shí)序圖要求關(guān)注 程序執(zhí)行時(shí)的 控制流,時(shí)序的展示更好像是 系統(tǒng)執(zhí)行時(shí)的 方法調(diào)用堆棧。
時(shí)序圖要素
- 方法調(diào)用堆棧(核心)
- 分支和循環(huán)描述,
- 方法和入?yún)⒚枋?/li>
- 主要的一些關(guān)鍵節(jié)點(diǎn)注釋
時(shí)序圖示例

可以看到時(shí)序圖 精確到 某個(gè)類 調(diào)用了某個(gè)類的某個(gè)方法,把方法的調(diào)用嵌套的深度 和層次 都能展現(xiàn)出來。 配合 重要的 關(guān)鍵節(jié)點(diǎn)注釋,可以讓讀者即使不讀代碼也可以看到整體的方法調(diào)用體系。 通過時(shí)序圖我們可以得到
- 某個(gè)類在時(shí)序圖的哪個(gè)位置,負(fù)責(zé)的工作是什么
- 在當(dāng)前流程中,某個(gè)類上下游的依賴是什么
類圖
類圖描述了類和類之間的依賴關(guān)系(組合,繼承,接口)
類圖要素
- 繼承、實(shí)現(xiàn)、組合關(guān)聯(lián)關(guān)系
- 類的關(guān)鍵核心方法。(記得加注釋,用以描述本類擴(kuò)展了哪些能力)
下面拿一個(gè)Spring ioc容器的類圖

類圖的箭頭關(guān)系 描述了 兩個(gè)類之間是否依賴,集成/組合/接口實(shí)現(xiàn)。
什么時(shí)候使用類圖?
簡單地業(yè)務(wù)流程不需要類圖
例如一個(gè)接口只有一個(gè)實(shí)現(xiàn)類,沒有復(fù)雜繼承關(guān)系 基本上不用寫類圖。
復(fù)雜的繼承體系需要類圖
類似于 Spring 等極為復(fù)雜的框架,為了實(shí)現(xiàn)最大程度的復(fù)用和可擴(kuò)展性。使用了大量的繼承、接口實(shí)現(xiàn)類 提高高擴(kuò)展性和可復(fù)用性。這個(gè)時(shí)候如果沒有類圖,根本無法全面的了解 一個(gè)接口,一個(gè)類的繼承體系。不清楚某個(gè)類在繼承體系中的位置。
為什么類圖不可以歸到 流程圖里
一般情況下只有流程圖和時(shí)序圖里面能具體精確到某個(gè)類。當(dāng)讀者在流程圖、時(shí)序圖里經(jīng)??吹侥硞€(gè)幾個(gè)類,就會(huì)疑問,這幾個(gè)類有什么關(guān)聯(lián)關(guān)系呢?
此時(shí) 可以擇機(jī)是否需要 梳理一個(gè) 類圖展示依賴關(guān)系。
類圖和設(shè)計(jì)模式
設(shè)計(jì)模式的具體介紹都會(huì)使用類圖展示。例如工廠模式 的類圖

系統(tǒng)架構(gòu)圖
系統(tǒng)架構(gòu)圖為了描述應(yīng)用內(nèi)部的組件,模塊等。一般情況下分為 全系統(tǒng)架構(gòu)圖,單應(yīng)用架構(gòu)圖
全系統(tǒng)架構(gòu)圖
業(yè)務(wù)架構(gòu)圖是從業(yè)務(wù)邏輯的視角出發(fā),整齊地展現(xiàn)出一個(gè)企業(yè)各類系統(tǒng)之間的層次和關(guān)系

單應(yīng)用架構(gòu)圖
單應(yīng)用業(yè)務(wù)架構(gòu)圖按照層次結(jié)構(gòu)可以分為經(jīng)典的三層結(jié)構(gòu):展現(xiàn)層、業(yè)務(wù)邏輯層和數(shù)據(jù)層

應(yīng)用架構(gòu)圖
應(yīng)用架構(gòu)圖的關(guān)注點(diǎn)是 應(yīng)用 在整個(gè)系統(tǒng)的位置。(和上面的全系統(tǒng) 業(yè)務(wù)架構(gòu)圖類似)。應(yīng)用架構(gòu)需要把應(yīng)用在整個(gè)系統(tǒng)的位置描述出來。
以下為優(yōu)惠券系統(tǒng)的 應(yīng)用架構(gòu)圖。基本描述了一個(gè)應(yīng)用服務(wù)在整個(gè)優(yōu)惠券相關(guān)微服務(wù)里 所處于的位置
例如 CouponJob服務(wù) 負(fù)責(zé)發(fā)券,上層會(huì)有各種形式的發(fā)券活動(dòng)關(guān)聯(lián)該服務(wù)。兌換碼,領(lǐng)券頁面領(lǐng)券等等都依賴CouponJob發(fā)券服務(wù)能力。

應(yīng)用間依賴關(guān)系 最理想的情況是單方向依賴,如果上下游的兩個(gè)服務(wù)存在明顯的 循環(huán)依賴,此時(shí)需要考慮,兩個(gè)系統(tǒng)是否耦合嚴(yán)重, 兩個(gè)系統(tǒng)是否實(shí)現(xiàn)了類似的功能呢? 是否需要合并為一個(gè)服務(wù)呢?
是否可以把關(guān)聯(lián)性很強(qiáng)的業(yè)務(wù)模塊放到一個(gè)服務(wù)里比較合適呢?
應(yīng)用架構(gòu)重在描述應(yīng)用之間的依賴關(guān)系,以及應(yīng)用所處在系統(tǒng)的位置。是上層應(yīng)用還是底層應(yīng)用? 設(shè)計(jì)應(yīng)用架構(gòu)圖時(shí) 不建議把 應(yīng)用內(nèi)的模塊劃分也囊括在應(yīng)用架構(gòu)圖中,這樣會(huì)導(dǎo)致架構(gòu)圖過于龐大,不利于理解
一個(gè)架構(gòu)圖只需要描述清楚 一個(gè)視圖即可。(職責(zé)盡量單一)
以下為HBase的應(yīng)用架構(gòu)圖

可以從表中看到
- Zookeeper負(fù)責(zé)存活性監(jiān)測等集群管理任務(wù)。
- master不負(fù)責(zé)數(shù)據(jù)讀寫,只負(fù)責(zé)DDL建表等語句,負(fù)責(zé)RegionServer故障轉(zhuǎn)移流程
- RegionServer負(fù)責(zé)接收客戶端讀寫數(shù)據(jù)
- HDFS 作為分布式存儲(chǔ),接收RS讀寫 (至于RegionServer內(nèi)部有哪些模塊,如何讀寫 自然借助于其他架構(gòu)圖。每種架構(gòu)圖只是從一個(gè)視角描述 系統(tǒng))
部署架構(gòu)圖
部署架構(gòu)圖重在描述應(yīng)用在線上部署的情況
部署架構(gòu)圖核心關(guān)注點(diǎn)
- 流量從管理端還是用戶端過來
- 是否做了鑒權(quán)
- 流量從哪幾個(gè) nginx 過來,公網(wǎng)還是內(nèi)網(wǎng),域名是哪個(gè)(公網(wǎng)內(nèi)網(wǎng),域名不同)
- 應(yīng)用是否做了負(fù)載均衡,策略是什么
- 是否多機(jī)房部署,應(yīng)用部署在了哪幾個(gè)機(jī)房。
- 機(jī)房之間的流量如何路由的; 是否存在跨機(jī)房調(diào)用
- 是否按照用戶維度進(jìn)行了 Set化
- 是否按照地區(qū)維度進(jìn)行了機(jī)房路由
- rpc調(diào)用路由規(guī)則是什么,在哪里管理路由規(guī)則
- 部署機(jī)房 是虛擬機(jī),物理機(jī),還是 Docker。 私有云,公有云,還是混合云架構(gòu)
- 依賴的數(shù)據(jù)庫和應(yīng)用是否同機(jī)房部署?
- 其他MQ,Redis,Es等中間件 機(jī)房部署在哪里。是否跨機(jī)房等。
以下部署架構(gòu)描述了 應(yīng)用在容器上部署,用戶請(qǐng)求經(jīng)過 SLB 負(fù)載均衡。靜態(tài)資源訪問,數(shù)據(jù)庫服務(wù)部署在RDS。

全鏈路調(diào)用 結(jié)構(gòu)圖
以下場景需要梳理全鏈路上下游依賴圖
- 接口參數(shù)需要變更,接口實(shí)現(xiàn)需要變更。確認(rèn)不影響上游(一般具體實(shí)現(xiàn)細(xì)節(jié)對(duì)上游屏蔽。)
- 下掉接口、遷移到新接口
- 限流,熔斷,降級(jí)策略需要通知到上游
當(dāng)出現(xiàn)以上內(nèi)容時(shí),我們需要感知到哪些上游依賴了我們,在什么業(yè)務(wù)場景下依賴,重要性,優(yōu)先級(jí)如何統(tǒng)一的梳理出系統(tǒng) rpc 接口,http接口,mq消費(fèi)者,共享數(shù)據(jù)庫,等 上下游依賴。 可以以表格的形式,例如

對(duì)于項(xiàng)目內(nèi)部的方法調(diào)用,模塊依賴,我們可以快速的梳理清楚上游的依賴。例如使用IDE 的快捷鍵。但是微服務(wù)下,需要獲取調(diào)用鏈路圖,只能依賴于 服務(wù)治理框架和代碼掃描工具 提供的能力,梳理每一個(gè)接口上游的依賴。
梳理后可能發(fā)現(xiàn)需要 對(duì)接口進(jìn)行鑒權(quán),防止任意調(diào)用方可以調(diào)用我們的服務(wù)。至少可以讓我們感知到接口被調(diào)用,防止大流量,不合理的業(yè)務(wù)場景 進(jìn)行調(diào)用。也方便我們?nèi)蘸笊?jí)。
每一種架構(gòu)圖都是一個(gè)獨(dú)特的視角
架構(gòu)圖的視角
- 用例圖: 用戶,產(chǎn)品經(jīng)理,測試人員 可以直觀,清晰的了解我們的系統(tǒng)使用場景,能做什么?
- 數(shù)據(jù)庫實(shí)體圖: 業(yè)務(wù)架構(gòu)師,業(yè)務(wù)專家,產(chǎn)品經(jīng)理 更清晰了解 建模的過程,是否存在領(lǐng)域劃分不清晰,領(lǐng)域耦合問題
- 流程圖: 給開發(fā)工程師,業(yè)務(wù)架構(gòu)師,業(yè)務(wù)專家 更清晰的 了解 核心流程 ,數(shù)據(jù)如何在組件之間流轉(zhuǎn)的,各組件如何調(diào)用的
- 系統(tǒng)架構(gòu)圖: 開發(fā)工程師 可以借助于此快速了解 系統(tǒng)內(nèi) 共哪幾個(gè)模塊,如何進(jìn)行分層的。各層職責(zé)。
- 應(yīng)用架構(gòu)圖: 業(yè)務(wù)架構(gòu)師可以看到 微服務(wù)之間是否存在耦合,是否依賴不合理,界限是否清晰。開發(fā)工程師可以了解負(fù)責(zé)的系統(tǒng)處于 總體架構(gòu)的哪個(gè)位置。
- 應(yīng)用部署架構(gòu): 業(yè)務(wù)架構(gòu)師,開發(fā)工程師 ,以及運(yùn)維工程師 更清晰的了解 服務(wù)部署環(huán)境, 流量入口,負(fù)載均衡策略,路由策略,中間件部署情況等
以上我們分析了設(shè)計(jì)文檔應(yīng)該包括哪些具體的 圖表,此外
設(shè)計(jì)文檔基本原則
設(shè)計(jì)文檔的編寫 應(yīng)該遵循以下基本原則
- 文檔是給人看的。 要給目標(biāo)讀者 講的足夠透徹,每個(gè)讀者的視角都要考慮到
- 可落地。要求文檔具備足夠的設(shè)計(jì)細(xì)節(jié),能準(zhǔn)確預(yù)判技術(shù)難點(diǎn),對(duì)于技術(shù)難點(diǎn)提出明確的解決方案(要覆蓋關(guān)鍵需求和流程)
- 一個(gè)架構(gòu)圖只需要描述清楚 一個(gè)視圖即可。追求大而全的架構(gòu)圖只會(huì)讓人看不懂,自己也無法再修改。(職責(zé)盡量單一)