好多年前章姓,同事徐昊說過的一句話給了我很大啟發(fā)佳遣,他說“紙上的不是架構(gòu)炭序,每個人腦子里的才是”。這句話告訴我們苍日,即便是天天工作在一個團隊里的人惭聂,對架構(gòu)的認識也可能是不一樣的。每個人嘴上說的是類似的話相恃,但心里想象的畫面仍然是不一樣的辜纲。在多年的工作中,我越來越認可這句話所揭示出的道理拦耐。軟件開發(fā)是一個團隊協(xié)作的工作耕腾,混亂的理解會造成架構(gòu)的無意義腐化、技術(shù)債的無意識積累杀糯、維護成本的無價值上升扫俺。
最近聽到一句話,“那些精妙的方案之所以落不了地固翰,是因為沒有在設(shè)計上兼容人類的愚蠢”狼纬。話糙理不糙,雖然最終人們選擇的方案的思想都是在十年前甚至幾十年前就已經(jīng)存在的骂际,然而在技術(shù)升級到足以“兼容”人類的愚蠢之前疗琉,這些思想只能在學(xué)術(shù)的故紙堆里睡大覺。當(dāng)然話糙確實也會有一個問題歉铝,將一個思想性問題轉(zhuǎn)化成了情緒性問題盈简。人們?nèi)菀装岩恍┰阈牡氖虑闅w因到人類的愚蠢,在宣泄完不滿情緒后就停止思考了太示。作為知識工作者柠贤,我們的思維不能停步,我們需要思考到底人類有哪些愚蠢类缤,分別用什么方法去避免或者“兼容”臼勉。
可以肯定彼此明明對自己開發(fā)的軟件有不一樣的認識卻天天在一起討論問題并試圖把軟件做好是一件愚蠢的事情,為了兼容這種愚蠢我們需要采用可視化的方法呀非。
為什么需要可視化呢坚俗,主要還是語言不靠譜镜盯。人類語言真的是太隨意了岸裙,只要你想,你可以說你見過一個方形的圓速缆,并為此與別人辯論降允。但是無論如何你也畫不出來一個方形的圓,這就是我們需要可視化的原因艺糜。
今天我們介紹一個工具剧董,叫做C4 model幢尚,這是我近幾年見到的一個比較難得跟我的認知有大量共鳴的工具。
該工具的作者在多年的咨詢中經(jīng)常發(fā)現(xiàn)翅楼,很多個人畫出來的架構(gòu)圖都是不一樣的尉剩,但也不是說誰畫錯了,而是每個人的抽象層次不一樣毅臊。抽象層次這種東西理茎,說起來好像存在,但真要說清楚還挺難管嬉,于是作者類比地圖皂林,提出了縮放的概念。(兩年前我在教學(xué)生的時候提過同樣的概念)如下圖:
上面的四張地圖就是想說明蚯撩,當(dāng)我們看待真實世界的“架構(gòu)圖”時候础倍,也是要不停的縮放,在每一個層次刻意忽略一些細節(jié)才能表達好當(dāng)前抽象層次的信息胎挎。所以他類比著把架構(gòu)也提出了四個抽象層次:
從上到下依次是系統(tǒng)System沟启、容器Container、組件Component和代碼Code犹菇。(咦美浦,那為什么叫C4呢,因為系統(tǒng)的圖叫System Context项栏,系統(tǒng)上下文圖浦辨。為了湊四個C也是夠拼的。)
基于這四個層次的抽象沼沈,C4模型由4張核心圖和3張附屬圖組成流酬,分別用于描述不同的場景,下面我們一一介紹一下列另。
四張核心圖
系統(tǒng)上下文圖
如上圖所示芽腾,這個圖表達的是你所開發(fā)的系統(tǒng)和它的用戶以及它所依賴的系統(tǒng)之間的關(guān)系。從這個圖上我們已經(jīng)看出來C4圖形的幾個關(guān)鍵圖形:
C4說穿了就是幾個要素:關(guān)系——帶箭頭的線页衙、元素——方塊和角色摊滔、關(guān)系描述——線上的文字、元素的描述——方塊和角色里的文字店乐、元素的標(biāo)記——方塊和角色的顏色艰躺、虛線框(在C4里面虛線框的表達力被極大的限制了,我覺得可以給虛線框更大的擴展空間)眨八。
通過在不同的抽象層次上腺兴,重新定義方塊和虛線框的含義來將我們的表達限制在一個抽象層次上,從而避免在表達的時候產(chǎn)生抽象層次混亂的問題廉侧。
那么在系統(tǒng)上下文圖里页响,方塊指代的是軟件系統(tǒng)篓足,藍色表示我們聚焦的系統(tǒng),也就是我開發(fā)的系統(tǒng)(也可能是我分析的系統(tǒng)闰蚕,取決于我是誰)栈拖,灰色表示我們直接依賴的系統(tǒng),虛線框表示的是企業(yè)的邊界没陡。通過這些圖形化的元素表達我們可以看出來各個系統(tǒng)彼此之間的關(guān)系辱魁。
容器圖
當(dāng)我們放大一個系統(tǒng),就會看到容器诗鸭,如上圖所示染簇,C4模型認為系統(tǒng)是由容器組成的。我個人認為强岸,容器是C4模型最大的創(chuàng)舉锻弓,尤其是在這個單體架構(gòu)快速崩塌的時代。所謂容器蝌箍,既不是Docker的容器青灼,也不是JavaEE里的容器,而是借用了進程模型妓盲,代指有自己獨立進程空間的一種存在杂拨。不管是在服務(wù)器上的單獨進程空間,還是在瀏覽器里的單獨進程空間悯衬,只要是單獨的進程空間就可以看作一個容器弹沽。當(dāng)然如果你容器化做得好,Docker的Container和這個Container可以一一對應(yīng)筋粗。有了這個概念的存在我們就可以更清晰的去表達我們的架構(gòu)策橘,而不是總是用一些模糊的東西。
組件圖
當(dāng)我們放大一個容器娜亿,我們就會看到組件丽已,如上圖所示。組件在這里面很好的把接口和它的實現(xiàn)類打包成一個概念來表達關(guān)系买决。我個人覺得有時候一些存在于代碼中沛婴,但又不是接口的某些東西,比如Service督赤、Controller嘁灯、Repository之類也可以用組件圖來表達,如果你學(xué)了一些沒有明確抽象層次的架構(gòu)知識或者一些單體時代的遺留經(jīng)驗的時候够挂,你可以畫出來一些組件圖旁仿,來印證自己的理解藕夫,如下圖孽糖,是我畫的自己對DDD戰(zhàn)術(shù)設(shè)計里面的一些概念的理解:
比起模糊的堆砌在一起的文字枯冈,這種表達要清晰的很多,哪怕我的理解是不對的办悟,也容易指出和討論尘奏。
代碼圖
代碼圖沒什么可說的,就是UML里的類圖之類很細節(jié)的圖病蛉。一般是不畫的炫加,都是代碼生成出來。除非非常重要的且還沒有寫出代碼的組件才畫代碼圖铺然。
以上就是C4的核心圖俗孝,我們可以看到四種不同的抽象層次的定義會讓我們更容易固定住我們討論的層次,這點上我覺得C4是非常有價值的魄健。
三張擴展圖
架構(gòu)設(shè)計設(shè)計要考慮的維度很多赋铝,僅四張核心圖是不夠的,所以作者又提供了三張擴展圖沽瘦,可以讓我們關(guān)注更多的維度革骨。
系統(tǒng)景觀圖
看得出來,系統(tǒng)景觀圖是比上下文圖更豐富的系統(tǒng)級別的表達析恋。不像上下文圖只關(guān)注聚焦系統(tǒng)和它的直接關(guān)系良哲,連一些間接相關(guān)的系統(tǒng)都會標(biāo)示出來,那些系統(tǒng)的用戶以及用戶之間的關(guān)系也會標(biāo)示出來助隧,只是內(nèi)部的用戶會用灰色標(biāo)記筑凫。
這個圖有什么用呢?在我們分析一個企業(yè)的時候并村,我們需要一個工具幫助我們把一家公司給挖個底掉漏健,做到完全窮盡,才能看到企業(yè)的全景圖橘霎,從而理解局部的正確定位以做好局部設(shè)計為全局優(yōu)化服務(wù)蔫浆。之前我試過以四色建模的紅卡、事件風(fēng)暴的事件兩種工具來教人掌握這種能力姐叁,一般來說瓦盛,程序員學(xué)員都無法快速掌握這種順藤摸瓜的分析技巧,畢竟跟程序員的思維還是有些差異的外潜。但是用了系統(tǒng)景觀圖之后原环,學(xué)員就毫不費力的掌握了這種分析能力,所以我后來都是用這個圖來教程序員探索企業(yè)的數(shù)字化全景圖处窥,效果極好嘱吗,推薦給大家。
動態(tài)圖
動態(tài)圖不同于其他表達靜態(tài)關(guān)系的圖,它是用來表達動態(tài)關(guān)系的谒麦,也就是不同的元素之間是如何調(diào)用來完成一個業(yè)務(wù)的俄讹。所以動態(tài)圖不僅僅適用于一個層面上,它在系統(tǒng)級绕德、容器級和組件級都可以畫患膛,表達的目標(biāo)是不一樣的。
我之前曾經(jīng)寫過名為《像機器一樣思考》的一系列文章耻蛇,在文中也發(fā)明了類似的圖踪蹬,不同于本文中關(guān)系線上標(biāo)注的是調(diào)用的方法、函數(shù)臣咖,我更關(guān)注的是數(shù)據(jù)跃捣,使用效果也很好。
什么時候用動態(tài)圖呢夺蛇?舉個小例子枝缔,我之前做一個內(nèi)部的小系統(tǒng),團隊中只有一個有經(jīng)驗的工程師帶著十多個畢業(yè)生蚊惯,我便要求他們在開始工作之前都畫出動態(tài)圖來愿卸,交由有經(jīng)驗的工程師去評估他們的思路是否正確,如果有問題截型,就在開始之前就扼殺掉爛設(shè)計趴荸。不管是畢業(yè)生還是初級工程師,改代碼的能力都比寫代碼的能力要差很多宦焦,所以將爛設(shè)計扼殺在實現(xiàn)之前還是有幫助的发钝。
部署圖
前面的幾張圖都是站在開發(fā)的角度思考,但是一個沒有充分思考過部署的架構(gòu)很容易變成一個運維的災(zāi)難波闹。所以作者提供了一個部署圖酝豪。考慮到DevOps運動如火如荼精堕,這個圖可以變成很好的Dev和Ops之間溝通的橋梁孵淘。我們在實操中發(fā)現(xiàn),Dev和Ops關(guān)注點的不同歹篓、語言的不一致瘫证,在這張圖上表現(xiàn)得非常清楚。
圖上最大的的實線框不同于虛線框庄撮,它表達的是數(shù)據(jù)中心背捌,當(dāng)你開始考慮異地載備的時候它就有了意義。數(shù)據(jù)的同步洞斯、實例的數(shù)量都會影響部署圖的內(nèi)容毡庆。部署圖基本都是容器級的,它能很好的表達出來容器到底部署了幾個實例,部署在什么樣的操作系統(tǒng)上么抗,一個節(jié)點部署了幾個容器之類毅否,我們在實際使用中,發(fā)現(xiàn)需要考慮的信息太多乖坠,自己就抽象出了類似于亞馬遜上實例規(guī)格的Small搀突、Large之類的術(shù)語來表達機器配置刀闷,增進了開發(fā)和運維之間的交流準(zhǔn)確性熊泵。
為什么C4值得推薦
夠直觀,對于程序員來說容易理解甸昏,容易使用顽分。
我們在開頭的時候說過,只有每個人腦子里的才是架構(gòu)圖施蜜,如果我們使用一個本身就很難達成一致理解的工具卒蘸,那成員就會陷入理解的死循環(huán)。經(jīng)過嘗試教授不同工具翻默,發(fā)現(xiàn)C4模型是最容易理解缸沃、最容易使用的工具⌒扌担可能它的概念是復(fù)用了程序員已有的一些認知模型趾牧,程序員在學(xué)習(xí)后都可以迅速的使用起來,并問出一些高質(zhì)量的問題肯污。
總結(jié)
在思維的世界里翘单,我們都是盲人,很多東西我們以為自己知道蹦渣,實際上畫出來之后哄芜,才發(fā)現(xiàn)很多東西沒想到,或者想的是亂的柬唯,同時別人也才可以給我們反饋认臊。
有了上面的這個工具,我們就可以開始可視化的架構(gòu)設(shè)計之路了锄奢,但路上還有一個心魔需要戰(zhàn)勝美尸。在我們的文化里,出錯是一件很丟人的事情斟薇,所以我們喜歡用一些模糊的描述避免被別人挑戰(zhàn)师坎,而可視化是讓我們精確的描述出自己的理解,來歡迎別人的挑戰(zhàn)堪滨。這一個坎不太容易跨過去胯陋,但是一旦跨過去、大家形成正向的互動之后,我們的進步速度會變得很快遏乔,從而把封閉的人遠遠的甩在后面义矛,獲得組織級的成長推力。我自己就在跟別人的交流之后獲得了更深入的洞見盟萨,本文已經(jīng)分享了一些凉翻,還有一些內(nèi)容后續(xù)再跟大家分享。
注:文中圖片均來自:https://c4model.com/
文/ThoughtWorks 仝鍵