簡介:軟體工程也是工程,因此傳統工程制圖的一些基本理論,在軟體行業同樣適用,但另一方面,軟體與物體制造業之間還是有著本質區別,所以在制圖方面的需求和方式也大相徑庭,無法直接套用,作為軟體行業的從業者,你可以完全不懂工程制圖,但你不得不懂架構制圖 —— 這是任何程式員職業生涯的的必修課,

作者 | 楚衡
前言
“架構制圖”這詞乍一聽似乎有些晦澀,但如果提起“工程制圖”,相信絕大部分工科背景的程式員們都不會陌生,甚至還能共同感慨下那些年一起伏在宿舍左手圓規,右手直尺,徒手作圖到深夜的日子,
軟體工程也是工程,因此傳統工程制圖的一些基本理論,在軟體行業同樣適用,但另一方面,軟體與物體制造業之間還是有著本質區別,所以在制圖方面的需求和方式也大相徑庭,無法直接套用,作為軟體行業的從業者,你可以完全不懂工程制圖,但你不得不懂架構制圖 —— 這是任何程式員職業生涯的的必修課,
本文在后半段將介紹如何用圖去描述(describe)和傳達(communicate)你的架構設計,值得強調的是,本文并不會側重于單一的方法和工具,而是更希望關注那些優秀方法背后的通用方法論,即架構制圖的本質、共性和最佳實踐,希望本文能起到引子作用,激發大家對自己日常作業中關于架構和制圖部分的關注、審視與思考;如果還真能幫助大家提升一點點制圖效率和效果,那就更好不過了,

什么是軟體架構?
1. 軟體架構定義

IEEE 給出的定義:架構是環境中該系統的一組基礎概念(concepts)和屬性(properties),具體表現就是它的元素(elements)、關系(relationships),以及設計與演進的基本原則(principles),
CMU 軟體工程研究院的定義:架構是用于推演出該系統的一組結構(structures),具體是由軟體元素(elements)、元素之間的關系(relationships),以及各自的屬性(properties)共同組成,
Uncle Bob 在 Clean Architecture 一書中給出的定義:架構是創建者給予該系統的形態(shape),這個形態的具體形式來源于對系統組件(components)的劃分和排列,以及這些組件之間互相通訊的方式,
2. 架構核心要素

綜合上述各種權威定義,軟體系統的架構通常需要包含如下四類核心要素:
- 元素(elements):將系統拆分為一組元素 - 模塊、組件、結構體、子系統;
- 關系(relationships):不同元素之間的關系 - 互動、依賴 、繼承、組合、聚合;
- 屬性(properties):每個元素具備的屬性 - 名稱、職責、介面、實作限制等;
- 原理(principles):為什么這么設計 - 拆分依據、設計原則、決策原因等,
為什么架構很重要?
1. 架構是系統實作的藍圖

最近有部很火的網劇叫《摩天大樓》,講述了一段匪夷所思的懸疑故事,為什么扯這個呢?因為我想借用這個劇的標題來問個問題:摩天大樓是由誰建起來的?也許你心里會默念:廢話,不就是建筑工人們一磚一瓦堆起來的嘛,仔細再想想?背后是不是還有一堆操碎了心的建筑設計師(比如劇中帥氣的林大森)和土木工程師們?他們雖然不搬磚也不扛水泥,但如果沒有他們產出的那些繁瑣嚴謹的設計圖紙,摩天大樓是是不可能像農村自建房一樣僅憑工人們各自的經驗與想象力就能快速平穩地豎立起來的,
正是靠著這些圖紙所描繪出來的工程藍圖(blueprints),才讓成百上千工人們的分工合作和驗收標準有了依據:大家只需要照著藍圖,按部就班地把自己所負責的那些磚瓦添上去就行了;只要藍圖正確,且施工程序也沒有偏差,最終順利完工只是個時間問題,
與建筑、汽車或者任何其他工程行業一樣,軟體在落地實作(編碼)之前也需要先有藍圖;而其中最重要的一份藍圖,就是架構設計,沒有架構,僅憑程式員自己腦子里的模糊設想,也許你可以像傳統手藝人一樣獨自創造出一些美好有用的小東西(比如 Linux 0.01 版本),但不太可能以工程的方式協同一個團隊共同建造起一個與摩天大樓規模類似的復雜軟體系統(比如現代的 Linux 系統),一方面,人類的思維能力終歸有限,必須依靠架構這種高度抽象和簡化的藍圖,才能讓復雜系統的創造、理解、分析和治理變得可行;另一方面,量級達到一定程度的大型系統,也只能依靠多人分工合作才能完成,而架構也正是多人溝通協作的重要基礎,
2. 架構是溝通協作的基礎


軟體專案的最終價值產出就是軟體系統,而架構作為軟體系統的靈魂和骨架,可以起到如下作用:
- 理解對齊:所有軟體系統的目的都是為了實作用戶需求,但實作的途徑有無限種可能性(相比傳統工程行業,軟體的靈活性更大、知識迭代更快),架構設計就是去選擇其中一條最合適的實作途徑,因此其中會涉及非常多關鍵的選路決策(為什么要這么拆分?為什么選擇 A 技術而不是 B?),這些重要的技術決策需要通過架構描述這種形式被記錄和同步,才能讓專案組所有成員對整個系統的理解對齊,形成共識,
- 作業量化:專案管理最重要的步驟之一就是工時評估,它是確定專案排期和里程碑的直接依據,顯然,只通過 PRD / 互動圖是無法科學量化出專案作業量的,因為很難直觀判斷出一句簡短需求或一個簡單頁面背后,究竟要寫多少代碼、實作起來難度有多大,有了清晰明確的架構之后,理論上絕大部分開發作業都能做到可見、可預測和可拆解,自然而然也就能夠被更準確地量化,當然,精準的作業量評估在 IT 行業內也一直是個未解之謎,實際的工期會受太多未知因素影響,包括程式員的技能熟練度、心情好不好、有沒有吃飽等,
- 標準術語:編程作為一種具有創造力的作業,從某種角度看跟寫科幻小說是類似的,好的科幻小說都喜歡造概念,比如三體中的智子,如果沒看過小說肯定不知道這是個啥玩意兒,軟體系統在造概念這一點上,相比科幻小說只有過之而無不及,畢竟小說里的世界通常還是以現實為背景,而軟體中的世界就全憑造物者(程式員)的想象(建模)了,稍微復雜一點的軟體系統,都會引入一些領域特定甚至全新創作的概念,為了避免在專案程序中出現雞同鴨講的溝通障礙和理解歧義,就必須對描述這些概念的術語進行統一,而架構的一個重要目的,就是定義和解釋清楚系統中涉及的所有關鍵概念,并在整個架構設計和描述程序中使用標準和一致的術語,真正做到讓大家的溝通都在一個頻道上,
- 言之有物:就跟討論產品互動時需要對著原型圖、討論代碼細節時需要直接看代碼一樣,架構是在討論一些較高維技術問題時的必要實物(具體的實物化形式就是所謂架構描述),否則,要么一堆人對著空氣談(紙上談兵都說不上),要么每次溝通時都重新找塊白板畫一畫(費時費力且容易遺落資訊,顯然不是長久之計),
- 知識沉淀 & 新人培訓:架構應該被作為與代碼同等重要的檔案資產持續沉淀和維護,同時也是專案新人快速理解和上手系統的重要依據,不要讓你的系統跟公司內某些祖傳遺留系統一樣 —— 只有代碼遺留了下來,架構檔案卻沒有;只能靠一些口口相傳的殘留設計記憶,苦苦維系著專案的生命延續,
3. 架構決定了產品質量

如何衡量一個軟體產品的質量?上圖是 ISO/IEC 25010 標準定義的軟體產品質量模型,包括以下 8 個大類:
- 功能適合性:功能完整度、功能正確性和功能恰當性;
- 性能效率:時間表現(e.g. 回應時間)、資源利用和容量;
- 兼容性:共存能力(e.g. 多版本組件共存)和互操作性;
- 可用性:可學習性、可運維性、用戶錯誤保護(e.g. 自動糾錯)、UI 美觀度、可訪問性;
- 可靠性:成熟度、可用性、容錯性、可恢復性;
- 安全性:機密性、完整性、不可偽造性、權威性和可審計;
- 可維護性:模塊度、可復用性、可分析性、可修改性、可測驗性;
- 可移植性:可適配性、可安裝性、可替代性,
上述質量模型中列出的所有點,都是架構設計需要著重考慮的,其中除了功能適合性以外,其他所有點都屬于非功能需求的范疇,這也是區分架構好壞的真正分水嶺 —— 好的架構設計,不會停留在僅滿足功能需求這一最基本的需求層次上(最壞的架構設計也同樣能做到),更重要且更難以應對的是其他眾多的非功能需求,

當然,魚與熊掌不可兼得,架構與人生一樣,也是一場權衡的游戲,弄不好就跟第八季的龍母一樣的下場:既要又要還要,最后反而什么都得不到,好的架構師更應該像雪諾同志學習,表面上“know nothing”,實際上“know everthing”:清楚系統所有利益相關者(stakeholders),努力挖掘各方的主要述求(concerns),相應平衡自己的架構決策(decisions),最終實作你好我好大家好的終極架構目標,
4. 我還能說出更多理由

要不是篇幅所限,這一頁 PPT 顯然不夠裝:
- 架構包含系統所有最重要的早期決策,這些決策會進而影響后續所有大大小小的技術決策,因此,早期的架構設計需要非常嚴謹和慎重,要盡可能“一次做對”(雖然很難),否則越往后糾錯的成本越高;
- 架構在組織內具有非常高的復用價值,因為同一組織內的產品之間一定會具備很多共性(需求、限制、環境等),很適合在架構層面進行最大化復用,避免重復解決相似的問題;
- 康威定律指出,軟體架構反映了組織結構,這個結論反過來也成立:好的架構也會讓組織結構變得更高效;
- 越龐大和復雜的系統,架構越重要,因為只有好的架構才能有效控制、管理和降低系統復雜度;
- 是不是越聽越糊涂,仿佛架構有無數種詮釋和意義?不必過于糾結,按照GoF的設計模式所述:Architecture is about the important stuff. Whatever that is. 對,管它是啥,記住架構很重要就夠了,
如何設計一個好的架構?
理解了架構的概念和重要性后,真正的架構師修煉之路才剛剛開始,如何設計一個好的架構?這顯然是一個非常博大精深的主題,但并不是本文的重點,因此這里只簡單列舉了一些基本思想(原則)和經典套路(模式),當然,架構設計更接近一門經驗學科,僅停留在能脫口而出一些玄乎而高大上的理論概念肯定是不夠的,需要結合實際作業內容和業務場景多多實踐和揣摩才行,否則只能算是徘徊在架構的門外,連入門都談不,
1. 架構原則(principles)

SOLID 原則是一套比較經典且流行的架構原則(主要還是名字起得好):
- 單一職責:與 Unix 哲學所倡導的“Do one thing and do it well”不謀而合;
- 開閉原則:用新增(擴展)來取代修改(破壞現有封裝),這與函式式的 immutable 思想也有異曲同工之妙;
- 里式替換:父類能夠出現的地方子類一定能夠出現,這樣它們之間才算是具備繼承的“Is-A”關系;
- 介面隔離:不要讓一個類依賴另一個類中用不到的介面,簡單說就是最小化組件之間的介面依賴和耦合;
- 依賴反轉:依賴抽象類與介面,而不是具體實作;讓低層次模塊依賴高層次模塊的穩定抽象,實作解耦,
此外,我們做架構設計時也會盡量遵循如下一些原則(與上述 SOLID 原則在本質上也是相通的):
- 正交性:架構同一層次拆分出的各組件之間,應該盡量保持正交,即彼此職責獨立,邊界清晰,沒有重疊;
- 高內聚:同一組件內部應該是高度內聚的(cohesive),像是一個不可分割的整體(否則就應該拆開);
- 低耦合:不同組件之間應該盡量減少耦合(coupling),既降低相互的變化影響,也能增強組件可復用性;
- 隔離變化:許多架構原則與模式的本質都是在隔離變化 —— 將預期可能變化的部分都隔離到一塊,減少發生變化時受影響(需要修改代碼、重新測驗或產生故障隱患)的其他穩定部分,
2. 架構模式(patterns)

架構模式(architectural patterns)與我們常討論的設計模式(design patterns)并不是一碼事,但如果僅從“模式”這個角度去解讀,兩者的理念都是一致的:針對給定背景關系中經常出現的問題的通用、可復用的解決方案,最主要的區別在于,架構模式會更高維抽象和偏全域整體(畢竟是運用在架構設計層面),
常見的架構模式,既包括一些傳統模式(e.g. 分層、C/S、MVC、事件驅動),也包括一些新興玩法(e.g. 云原生、微服務、Serverless),不同模式有不同的適用場景,沒有哪一種模式能通殺所有需求,成熟的架構師應該像一個冷靜到冒得感情的殺手,永遠只會客觀地評估和選擇最適合當下的解決手段,即使那么做會顯得簡單乏味;相反,不成熟的架構師,一心總想著搞事情(e.g. 強行套用微服務架構),而不是真正搞定問題,
怎么描述你的架構設計?
有了良好的架構設計,萬里長征之路就已經走了一大半,就像是青年導演第一次遇上好劇本,心潮澎湃兩眼放光,仿佛已經預見了電影上映后的票房盛況,當然,剩下的一小半路,并不會如想象中那么平坦 —— 同樣的劇本,不同導演拍出來會有質一樣的區別,好的“最佳導演”,即使面對不是“最佳劇本”的劇本,也有能力拍出“最佳影片”,同樣,好的架構師,也應該有能力描述好一個不錯的架構設計;即使做不到為精彩的內容加分,也不應該因為形式上沒描述好而丟分,否則就會像高考作文丟了卷面分一樣憋屈和心酸,
1. 架構描述的意義

為什么要描述架構?讓它只存在我深深的腦海里不行嗎?西方人有句諺語:好記性不如爛筆頭,任何沒有持久化的東西都是易失的(volatile),就跟記憶體一樣,另一方面,就如前文所述,架構是溝通協作的基礎,不通過架構描述(Architecture Description)沉淀下來讓所有專案干系人都能看到,那就失去了溝通和傳播的唯一載體,
根據個人觀察,大家對“架構需要描述”這一點都沒異議,所以絕大部分專案都或多或少會產出一些有模有樣的架構描述檔案,但“有架構描述”和“有好的架構描述”,這之間的鴻溝是巨大的,甚至比“沒有”和“有”之間的差別還大,如果你也跟我一樣,飽經滄桑閱盡無數架構檔案,曾拍手叫好心懷感激過,也曾拍著大腿憤怒不已過,應該也能感同身受,
2. 架構描述的方式

對于同一件事物,作家會選擇用文字來敘述,而畫家卻會用圖畫,盡管兩者想要傳達的資訊是一致的,但描述方式的不同也會帶來效果上的巨大差異,架構描述也分文字(Text)和圖(Diagram)兩種形式,兩者各有千秋:
- 文字的背后是由一套嚴謹和完備的語言作為支撐,因此其描述可以做到非常精準和詳盡,而且撰寫起來也很方便,隨便打開個記事本軟體都能寫;此外,就跟寫代碼一樣,文字很易于做版本管理,借助簡單的文本 diff 工具就能一目了然地對比出不同版本之間的細節差異;
- 相比而言,圖并不具備以上文字所獨有的特點,但也有自己的獨特優勢:圖是直觀而形象的,順應了人類與生俱來的視覺識別本能;圖的表達能力更強,很多時候一小張圖所能傳達出的資訊(比如空間位置關系、顏色分類、圖示形狀),也許用一千行字也不足以完整準確地描述出來,即所謂“一圖勝千言”,
聰明的你冷笑了一聲:哼,又不是小孩子非得做選擇題,難道不可以文字與圖都要嗎?當然可以,理想的架構描述一定是圖文并茂的,但現實世界顯然比理想殘酷,實際軟體專案中很難給你留足時間先憋出一篇完美的架構檔案,如果以成年人的思維去考慮投入產出比(ROI),那么你一定會優先選擇畫圖,
3. 為什么你應該優先畫圖?

敏捷軟體開發宣言中提到:相比詳盡的檔案,可運作的軟體更加重要(Working software over comprehensive documentation),這么說當然不代表就不用寫檔案了,只是提倡沒必要寫過于詳盡的檔案,為什么?因為詳盡的檔案需要耗費大量的撰寫和維護成本,不符合敏捷開發的小步迭代和快速回應變化等原則,
那么,在如今這個全面敏捷開發的時代,如何也順應潮流更加敏捷地撰寫架構檔案呢?ROI is your friend —— 不求多,但求精,盡量用最少的筆墨表達出最核心的內容,從內容上來說,ROI 高的部分一般是偏頂層的整體架構或最核心的關鍵鏈路,這點在后文的 C4 模型理念中也有體現,而從形式上來說,圖在文字面前具有無與倫比的表達力優勢,顯然是 ROI 更高的選擇,
4. 為什么你需要學習畫圖?

多畫圖是沒錯,但有必要專門學習嗎?又不是素描彩筆水墨畫,只是畫一堆條條框框而已,稍微有點工程常識的都能上,畫的有點丑?那沒關系,頂多再動用點與生俱來的藝術美感,把這幾條線對對齊那幾個框擺擺正,再整點五彩斑斕的背景色啥的,不就顯得很專業了嘛?
看到這里,螢屏前的你又輕蔑一笑:哼,顯然沒這么簡單,確實,道理說出來大家都懂,架構制圖與工程制圖一樣,都是一件需要下功夫認真嚴謹對待的事情,但現實中大部分人還真沒這工夫去下那功夫,比如上面貼的兩幅很常見的架構圖,第一張圖不用多說,這種草圖自己涂涂抹抹挺好,但拿出來見人就是你的不對了,那第二張圖呢,看上去似憾訓挺像那么回事的?并不是,如果你更仔細地去揣摩,就能發現這張圖底下所隱藏的很多模糊和不嚴謹之處(可參考這張圖的來源文章:The Art of Crafting Architectural Diagrams),
所以,能畫圖并不代表能畫好圖;要想制得一手既漂亮又可讀的好圖,還是需要經過持續學習與刻意練習的,很難僅憑直覺和悟性就能掌握其中的關鍵要領,此外,錯誤的圖往往比沒有圖還要糟糕,即使你只是抱著“有圖就行,差不多那個意思得了”的心態,也至少應該理解一些科學制圖的關鍵要素,避免給本來就已經很復雜難做的專案又蒙上一層模糊濾鏡,甚至起到混淆和誤導的反作用,
5. 架構制圖的目標

討論具體的制圖方法和工具前,我們需要先豎立清晰的制圖目標,工具是人類進化的階梯,但如果理解和利用不當,則很容易反過來被工具所限制甚至奴役,忘了最初發明和使用工具的初心,對于架構制圖而言,已經有那么多形形色色的方法與工具,使用它們的初心是什么呢?我認為本質上都是想把制圖這個程序從一門自由的手藝變成一項科學的工程:系統、嚴謹、完整、標準化,同時能做到可重復、可持續和高效,
P.S:當時做 PPT 太趕,所以從這個章節開始的配圖,只能被迫走極簡路線了,還請見諒,,,
架構制圖方法與工具
經過前面幾個章節的“簡短”鋪墊,相信大家對架構制圖的背景知識都已經產生了足夠的認知,本章節將會具體列舉和描述一些典型的架構制圖方法與工具,其中有常見的也有罕見的,重點是希望能通過各種方法的橫向對比,加深大家對制圖方法本質的理解,
1. 方法一:UML

UML 應該是大部分人最熟悉的制圖方法了,最新的 UML 2.x 版本由以下兩大類圖組成:
- 結構圖(Structural Diagrams):通過物件、屬性、操作和關系等方式,強調系統的靜態結構,其中最常見的型別包括類圖(Class Diagram)、組件圖(Component Diagram)和部署圖(Deployment Diagram);
- 行為圖(Behavioral Diagrams):通過展示物件之間的協作關系以及物件內部的狀態改變,強調系統的動態行為,其中最常見的型別包括用例圖(Use Case Diagram)、活動圖(Activity Diagram)、時序圖(Sequence Diagram)和狀態機圖(State Machine Diagram),
作為通用的“統一建模語言”,UML 總共包含了 14 種不同型別的圖,可以全面覆寫軟體設計領域各種制圖需求,當然也包括了架構制圖,同時,也正是因為 UML 把自己當成了一門語言,因此其各種記號(notion)和語意(sematics)都有非常嚴謹的定義,不會出現模糊或者歧義問題,最后,UML 經過幾十年的發展和推廣,也早已成為世界范圍內廣泛使用的標準規范,其所帶來的的隱性價值就是:在團隊內使用 UML 進行溝通的成本是比較低的,因為可以假定絕大部分技術人員都能理解UML的含義和用法,
然而,UML 也非萬能(雖然歷史上曾一度把它當成軟體設計的銀彈),它最被人詬病的缺點就是過于復雜,這也不能怪 UML,畢竟它就是要被設計為足夠通用、嚴謹和強大的,這些目標都與“簡單”背道而馳,并讓它一步步演化到了今天這個復雜刻板的龐然大物模樣,雖然上面我們自信地假定了技術人員大多都懂 UML,但這個“懂”如果帶上一個程度量詞,我覺得平均能到 20% 就不錯了 —— 絕大部分也就能認識幾個常見的類圖、時序圖,估計都很難準確說出類圖中各種箭頭的含義,
無論怎么說,UML依然應該是每個程式員的制圖工具箱中最常用和必備的工具之一,當然,也不應該是唯一,因為下面也還有些不能錯過的好東西,
2. 方法二:4+1 View Model

“4+1”是啥?不知道沒關系,聽過“6+1”嗎?對,就是那個小時候常看的“非常6+1”節目,它跟“4+1”之間的關系,就跟它們與邵佳一、張嘉譯和沈佳宜之間的關系一樣,除了趕巧共用了同一個后綴發音以外,八竿子打不著,
所以,“4+1”到底是指什么?讓我們來 Wiki 一下:“4+1”是一種視圖模型(view model),可以通過多種共存的視圖描述軟體密集型系統的架構,這些視圖基于不同專案干系人(利益相關者)的視點(viewpoint),例如:終端用戶、開發者、系統工程師和專案經理,“4+1”由 4 種基礎視圖和一些經過挑選的用例或場景(即額外的“+1”視圖)組成,各自的具體含義如下:
- 邏輯視圖(Logical view):描述系統為終端用戶提供的功能,一般會通過UML中的類圖和狀態圖來表示;
- 程序視圖(Process view):描述系統的動態行為,包括流程和互動等,一般會通過 UML 中的時序圖、活動圖和通訊圖來表示;
- 開發視圖(Development view):從程式員的視角來闡述系統,也被稱為“實作視圖”,一般會通過 UML 中的組件圖和包圖來表示;
- 物理視圖(Physical view):從系統工程師的角度來描述系統,包括系統組件的物理拓撲、各組件之間的物理連接,也被稱為“部署視圖”,一般會通過 UML 中的部署圖來表示;
- 場景(Scenarios):通過一小組用例或場景來描述架構,包括系統中各種物件和行程之間的互動時序,也被稱為“用例視圖”,這些場景會被用于識別架構元素(architectural elements)以及闡述和驗證整個架構設計,也可以被作為架構原型的測驗起點,
雖然上面提到“4+1”的各種視圖一般都是用UML圖來表示,但實際上“4+1”本身是一種通用的視圖模型,并沒有限制繪圖的記號和工具,對于工程師而言,這種偏學院派的方法可能這輩子都不會直接用到,但其中蘊含的一個關鍵架構制圖思想非常有價值:架構需要通過多種視圖來描述,而這些視圖是來源于不同專案干系人的視點(角度);只有這樣才能產生一整套全面、立體且客觀的架構描述,
3. 方法三:C4 Model
C4 模型是一種“抽象優先”(abstraction-first)的架構制圖方法,它也是受前面的 UML 和“4+1”視圖模型所啟發,但相對而言要更加簡單和輕量,只包含少量的一組抽象和圖表,很易于學習和使用,
1)定義、理念與關鍵思想

C4 模型通過容器、組件、代碼以及人這幾個抽象來描述一個軟體系統的靜態結構,它的核心理念是希望像 Google Map 一樣,通過不同層次的細節,為代碼建立一種可以放大和縮小的導覽圖,它最關鍵的思想就是自頂向下對系統的靜態結構進行逐級拆分,依次描述各層次物件的職責、關系和外部依賴,除了核心的層次化靜態結構視圖,它還可以包含動態視圖、部署視圖等補充視圖,

上面的左圖展示了 C4 模型中各層次抽象之間的映射關系:1 個軟體系統由 1~N 個容器組成,1 個容器由 1~N 個組件組成,1 個組件由 1~N 個代碼結構組成,右圖是以簡單的 Spring PetClinic 專案為例,演示了一個真實軟體系統在 C4 模型下的層次結構:最上層就是 PetClinic 軟體系統,它可以拆分為資料庫、Web 應用等幾個容器;Web 應用又可以進一步拆分出 ClinicService 這個組件,而這個組件下又包含了 ClinicService 介面類、ClinicServiceImple 實作類、Owner / Pet / Visit 等領域物件類,
使用 C4 模型進行架構制圖,本質上就是對上述幾種抽象進行可視化,具體的做法是依次建立如下幾類從粗到細的結構圖:Context、Container、Component 和 Code(可選),這也是 C4 模型名稱的來歷,
2)Level 1:System Context diagram

系統背景關系圖作為第一級(L1),提供了一個展示系統全貌的頂層大圖(big picture)視角,包括最中心的軟體系統、周邊的用戶以及其他有互動的系統,其中最關鍵的兩個概念分別是:
- 人(Person):即使用軟體系統的用戶,例如一個在線商城系統的消費者、運營小二、系統管理員等;
- 軟體系統(Software System):作為最高層次抽象,描述了給用戶創造價值的軟體制品;既包括當前正在設計的軟體系統,也包括該系統所依賴(或被依賴)的其他軟體系統,一個軟體系統通常是由單個軟體開發團隊所負責,
在繪制系統背景關系圖時,不需要關心諸如技術堆疊、協議等任何底層細節,這類圖的受眾是最廣的,因為任何人都可以理解并從中獲取到足夠的資訊,包括技術人員和非技術人員,也包括團隊內成員和團隊外成員,
3)Level 2:Container diagram

通過 L1 的背景關系圖理解了系統在整個 IT 環境中的定位后,下一步就是把系統這個框框放大,詳細看下其中包含了哪些“容器”(Container,注意不要跟 Docker 容器搞混了噢!),C4 模型中的容器是指單個應用或資料存盤,通常可以獨立部署和運行(有獨立的行程空間,通過 IPC 機制互相通訊),例如:SpringBoot 微服務、React SPA、移動 App、資料庫、Serverlss 函式、Shell 腳本,
L2 的容器圖不僅展示了系統的進一步職責拆分,還包括了主要的技術選型、容器之間的通訊方式等關鍵架構資訊,這類圖可以面向全部的技術人員,既包括架構師、開發者,也包括運維人員、技術支持等,
4)Level 3:Component diagram

繼續前面的套路,下一步就是把系統中各個容器再分別進行區域放大,將每個容器進一步拆分成多個組件(Component),在 C4 模型中,組件是指一組通過良好介面定義封裝在一起的相關功能(通常運行在同一個行程空間內),例如:Spring 里的一個Controller(不只包括定義了 REST 介面的 Controller 主類,也包括背后所有相關聯的實作類,如 Service/Repository 等),
與容器圖類似,L3 的組件圖也不只包含了容器的組件劃分,還包括各個組件的職責定義、技術與實作細節等,隨著層次的下沉和細節的增多,組件圖的受眾范圍進一步縮窄,一般只適用于軟體架構師和開發者(其他角色沒必要理解,一般也理解不了),
5)Level 4:Code(可選)

再繼續對組件進行放大,所能看到的最底層和細節的資訊,就是 L4 的代碼(Code)了,當然,這里所謂的“代碼”還是以圖的形式(e.g. UML 類圖、資料庫 E/R 圖)展示類或檔案粒度的代碼結構,并不是真正的代碼本身,即便如此,代碼圖在 99% 的架構描述場景下也依然過于詳盡,一方面數量龐大,繪制成本很高;另一方面易于變化,維護成本也非常高,因此,一般只有非常重要和復雜的組件才需要用到這一層級進行描述,如果確實需要繪制,也應該優先考慮自動化的方式,比如很多 IDE 就支持自動生成 UML 類圖,
6)補充圖:Landscape / Dynamic / Deployment Diagram

除了上述各個層次的靜態結構圖,C4 模型還提出了一系列的補充圖(Supplementary diagrams),包括:
- 系統全景圖(System Landscape diagram):全景圖與系統背景關系圖的繪制方法類似,區別在于它是從企業或組織角度全景地展示出所有軟體系統(包括與當前系統沒有直接關聯的)以及相關的用戶和系統互動,即進一步放大架構圖的 scope;
- 動態圖(Dynamic diagram):由于結構圖天生只能描述出系統的靜態結構屬性,因此 C4 模型中推薦使用 UML 中的通訊圖、時序圖等,對系統中關鍵鏈路的動態行為進行補充描述,即“動靜結合”;
- 部署圖(Deployment diagram):除了缺失動態屬性,上述結構圖還有一個局限性:只描述了系統的抽象邏輯架構,并沒有描述出系統實際部署時的具體物理架構,因此,C4 模型推薦再使用 UML 的部署圖,對系統邏輯節點(一般是 L2 的“容器”粒度)與物理節點(e.g. 物理機 / 虛擬機 / Docker 容器 / 應用 Runtime)之間的映射關系進行補充描述,即“虛實結合”,
結合了這些補充圖后的 C4 模型,才是可以全面與立體地描述出軟體架構方方面面的完全體架構制圖方法,
4. 方法四:arc42

嚴格來說,arc42 并不是一種架構制圖方法,而是一個架構檔案模板,雖然如前文所說,在架構描述中“圖”是比“文字”更高優的選擇,但實際專案程序中你終究還是需要產出一份相對完整、有圖有文字的架構檔案,arc42 就是專門用于幫助大家更好地撰寫架構檔案;而作為架構檔案中最重要的架構圖,顯然 arc42 也不會放過 —— 其中多個核心章節都與架構圖有關,且詳細描述了相應的制圖方法,這里不會詳細展開介紹 arc42(不能搶了下一篇文章的飯碗),只會簡單介紹下 arc42 中制圖方法與 C4 模型的異同,
偉大的思想都是相似的,arc42 也不例外,上方左圖的右側部分,概括了 arc42 模板中與制圖相關的幾個核心章節,分別是:
- 第 3 章 - Context:該章節用于介紹系統的背景和背景關系,因此其制圖思路幾乎等同于 C4 模型中的 L1(系統背景關系圖);
- 第 5 章 - Building block view:該章節用于介紹系統的基本構成要素,按照官方指導思想也與 C4 模型中的自頂向下層次化拆分思想無異,唯一區是 arc42 并沒有規定拆分的具體層次,只要有需要可以按照“黑盒 -> 白盒”的套路一直拆到底;
- 第 6 章 - Runtime view:看名字就無需解釋了,就等同于 C4 模型中補充的運行時視圖;
- 第 7 章 - Deployment view:同樣地,這里也等同于 C4 模型中補充的部署視圖;但有一點,arc42 強調部署視圖也可以類似結構視圖一樣做自頂向下的層次化拆分(對于較為復雜的部署架構,層次化確實很有必要),
因此,本質上 arc42 中提倡的制圖方法與C4模型是等價和兼容的,完全可以配合使用:以 arc42 作為架構檔案框架,其中的架構制圖采用更具體的 C4 模型,這也是目前我們專案中實際采用的方法,
5. 其他方法 & 制圖工具

除了上述幾種方法以外,在軟體行業蓬勃發展的數十年間也涌現出過很多其他的優秀架構制圖方法,其中既包括一些通用方法,如:SysML、AADL、ArchiMate,也包括一些領域特定方法,比如在企業中后臺業務建模場景中很常見的 BPMN,再詳細地展開描述各個方法,顯然會讓本文又臭又長(雖然寫到這里時似乎就已經注定了),有興趣的讀者可以自行檢索和探索,
到這里為止,本章節介紹的都是架構制圖的各種方法;而實際從方法到落地的程序中,還有一個繞不開的環節:選用什么樣的工具去制圖?總不能真的跟寫工程制圖作業一樣用紙和筆吧?作為數字化改革的推動者,程式員們當然要全面擁抱數字化工具;大家日常作業中必然也已經積累了很多順手的畫圖工具,因此這里我只推薦兩個自己用得比較多的:
- draw.io:這是一個開源的在線繪圖軟體,相信很多人都有用過,考慮到資料安全問題,推薦大家用完全離線的桌面版,作為一個程式員友好的繪圖工具,draw.io 的最大優點就是支持三方插件,比如這個開源的 c4-draw.io 插件,可以幫助你更方便地在 draw.io 中繪制 C4 模型架構圖;
- PlantUML:作為文本制圖的代表性工具,PlantUML 可以用于繪制各種型別的UML圖,以及其他一些適用于文本制圖場景的圖(比如這個開源的 C4-PlantUML 擴展),在這些場景下,文本制圖具有可視化制圖所無法比擬的優勢:輕量、高效、版本化、自動化、一致性、易于復用等,雖然文本制圖工具誕生已久(比如應用廣泛的 [Graphviz](),最早發行于 1991 年),但相信隨著現代各種 XXX as Code 的意識覺醒,這類 Diagram as Code 工具也會獲得更多青睞(btw,語雀檔案早已支持內嵌 PlantUML 制圖),
架構制圖方法論總結
古有云:授人以魚,不如授人以漁,推而廣之:授人以方法,也不如授人以方法論,什么是方法論?雖然這個詞在公司里已經用爛了,但確實有它的價值和意義:方法論(methodology)是對方法的更高維度抽象,由它可以推匯出解決問題的具體方法(method),理解了方法論,才能融會貫通,掌握解決問題的本質要點;你也不會再受限于單一的具體方法,因為使用任何方法都能快速上手和靈活運用,并得到差不多的同等效果,
因此,本文最后這一章節將對各種架構制圖方法進行歸納總結,并嘗試提煉出一個通用的架構制圖方法論,期望能幫助大家更好地理解架構制圖背后的原理和思想,即便現在所熟知的各種方法與工具侄訓過時,也依然能風輕云淡地看待它們的新老交替:過去是 UML,現在是 C4,未來是什么呢?這并不關鍵,因為即使方法過時了,背后的方法論也不會過時,
所以,那些茫茫多的方法背后,究竟是什么樣的核心方法論在支撐著呢?經過作者嘔心瀝血冥思苦想了近 15 秒鐘,終于總結出了如下這套經典方法論(p.s:就是湊數的,不要太當真~ ),由于其中包含了 5 個環環相扣的要點,我們姑且稱它為:五環理論,

1. 理解制圖目標

架構制圖的第一要點,是需要先深刻理解制圖目標,正所謂“以始為終”,有了目標我們才能清晰地前行;否則漫無目的地亂竄,往往會多走不少彎路,甚至南轅北轍,架構制圖的目標是什么?其實前文已經提到過很多,這里再簡單總結下:
- 準確(accurate):錯的圖比沒有圖還糟糕;即使一開始是準確的,后面也需要定期更新校對;
- 完整(complete):需要覆寫架構的核心要素和關鍵資訊,為受眾呈現一個沒有殘缺的完整架構設計;
- 清晰(clear):制圖時最好帶上圖例(形狀、顏色、線型、箭頭);用圖描述不清的地方,還可以加上文字標注做補充;
- 一致(consistent):比如同一型別的圖,最好使用相同的記號風格,以降低受眾的理解成本;不一致往往還會帶來混淆;
- 簡潔(consise):在滿足以上 4 點基礎之上,還需要讓圖更加簡潔,一方面是更容易被人接受(沒人讀 = 沒寫),另一方面更新維護成本也更低,
2. 找準受眾和關注點

架構制圖的第二要點,是要找準你制圖的受眾(audience)以及他們各自的關注點(concern),找不準的話,要么效果大打折扣(不是他們想聽的),要么猶如對牛彈琴(他們根本就聽不懂),常見的一些受眾和關注點可包括:
- 研發:一般會關注很多實作相關細節,比如技術選型、實作可行性、可維護性等,畢竟他們是架構的最直接消費者;
- 運維:不太關心應用內的具體技術實作(當成黑盒),但很關心各個應用實體的物理部署方式、網路連通性、可運維性等;
- 安全:只關注系統是否有安全風險,例如是否可能被注入惡意代碼、是否有權限漏洞等;如果經歷過安全評審,應該很有體感;
- 產品:大部分情況下只關心專案能否按期上線,其他方面...可能表面上表示些許關心,實際上要么并不在乎要么真的不懂,
3. 自頂向下逐層描述

架構制圖的第三要點,是合理運用層次化(hierarchical)的套路,自頂向下逐層描述,無論是 C4 模型還是 arc42 模板,背后都深刻運用并顯著強調了這一點,為什么一定要這么做?其中蘊含了兩個普適的原理:
- 分而治之:軟體領域中,分而治之是控制和應對復雜系統的最有效方法,而層次化拆分,本質上就是一種分而治之手段:將系統按照從粗到細的粒度,一級一級地拆分成多個相對獨立和低耦合的元素(子系統、應用、組件等);
- 金字塔原理:這本書的核心觀點就是,按照自頂向下的方式,先拋出主觀點再依次用各個子觀點去論證,這樣的溝通方式更符合人類的思維邏輯,也更容易讓讀者接受,簡單來說,就是要“先說重點”,幫助讀者做歸納總結和劃重點,而不是先拋出一大堆細枝末節的零散東西讓讀者自己去消化和推演,
4. 使用多種架構視圖

架構制圖的第四要點,是在向傳統的工程制圖方法論致敬:使用多種架構視圖來描述你的架構,在工程制圖的世界里,任何立體的制品,大到機床小到零件,都至少需要通過三種視圖(主視圖、俯視圖、左視圖)來描述,作為現實世界的映射,軟體系統也是多維和立體的,只用單一視圖不可能覆寫所有關鍵的架構資訊;即使強行把這些資訊都塞在一張圖里,那也一定會復雜到讓人無法理解,
在架構設計領域,架構視圖(architectural view)有專門的定義:針對系統架構某一個方面(aspect)的一種描述;每個視圖都會覆寫專案干系人的一種或多種關注點,從上述定義可以看出來,不同的架構視圖會有不同的側重點,同時在描述自己所專注的方面時也會略去與當前視圖無關的其他細節 —— 這其實也是一種與層次化拆分類似的分而治之思想,只不過這里是針對完整系統的維度分解,而層次化則是針對某一具體視圖再做自頂向下的垂直下鉆(drill-down);兩者是正交且可以相互配合的,例如前面說到的結構視圖、部署視圖甚至動態視圖,都可以分別再進行層次化拆分,
5. 遵循規范和最佳實踐

架構制圖的第五要點,其實只是一句正確的廢話:遵循規范和最佳實踐,這一點已經不限于架構制圖,而是上升到了工程實踐領域的通用方法論層面,正如前面章節所說,“學習架構制圖的目標,就是要把它從一門手藝變成一項工程”,因此架構制圖的“施工”程序也理所應當符合工程化思維:
- 一方面,制圖需要遵循明確的規范,在理論層面進行約束和指引,確保程序和產物的高質量與標準化;
- 另一方面,制圖還需要遵循業界最佳實踐,在實踐層面持續吸取優秀經驗,不斷精進自己和團隊的制圖技能,
附:架構描述標準化概念模型
國際上對架構描述其實建立了專門的標準(ISO / IEC / IEEE 42010:2011),其中的很多概念詞匯在本文中都有提到(e.g. Stakeholder、Concern、View、Viewpoint),有興趣的同學可以進一步研究下,

結語
如果你從頭到尾耐著性子看到了這里,那么不用懷疑,你一定就是我們團隊要找的那種能成大事兒的人:
歡迎各位技術同路人加入阿里云云原生應用研發平臺EMAS團隊,我們專注于廣泛的云原生技術(Backend as a Service、Serverless、DevOps、低代碼平臺等),致力于為企業、開發者提供一站式的應用研發管理服務,內推直達郵箱:pengqun.pq # alibaba-inc.com,有信必回,
“阿里巴巴云原生關注微服務、Serverless、容器、Service Mesh 等技術領域、聚焦云原生流行技術趨勢、云原生大規模的落地實踐,做最懂云原生開發者的公眾號,”
原文鏈接:https://developer.aliyun.com/article/774446?
著作權宣告:本文內容由阿里云實名注冊用戶自發貢獻,著作權歸原作者所有,阿里云開發者社區不擁有其著作權,亦不承擔相應法律責任,具體規則請查看《阿里云開發者社區用戶服務協議》和《阿里云開發者社區知識產權保護指引》,如果您發現本社區中有涉嫌抄襲的內容,填寫侵權投訴表單進行舉報,一經查實,本社區將立刻洗掉涉嫌侵權內容,
轉載請註明出處,本文鏈接:https://www.uj5u.com/qianduan/144712.html
標籤:其他
上一篇:離開華為換種生活,它不香嗎?
