做者 | 楚衡ios
前言
「架構製圖」這詞乍一聽彷佛有些晦澀,但若是提起「工程製圖」,相信絕大部分工科背景的程序員們都不會陌生,甚至還能共同感慨下那些年一塊兒伏在宿舍左手圓規,右手直尺,徒手做圖到深夜的日子。git
軟件工程也是工程,所以傳統工程製圖的一些基本理論,在軟件行業一樣適用。但另外一方面,軟件與實體制造業之間仍是有着本質區別,因此在製圖方面的需求和方式也截然不同,沒法直接套用。做爲軟件行業的從業者,你能夠徹底不懂工程製圖,但你不得不懂架構製圖 —— 這是任何程序員職業生涯的的必修課。程序員
本文在後半段將介紹如何用圖去描述(describe)和傳達(communicate)你的架構設計。值得強調的是,本文並不會側重於單一的方法和工具,而是更但願關注那些優秀方法背後的通用方法論,即架構製圖的本質、共性和最佳實踐。但願本文能起到引子做用,激發你們對本身平常工做中關於架構和製圖部分的關注、審視與思考;若是還真能幫助你們提高一點點製圖效率和效果,那就更好不過了。github
什麼是軟件架構?
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」之間的關係,就跟它們與邵佳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):即便用軟件系統的用戶,例如一個在線商城系統的消費者、運營小2、系統管理員等;
-
軟件系統(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 等技術領域、聚焦雲原生流行技術趨勢、雲原生大規模的落地實踐,作最懂雲原生開發者的公衆號。」