介紹
架構(gòu)的本質(zhì)是管理復(fù)雜性,抽象埃碱、分層、分治和演化思維是我們工程師/架構(gòu)師應(yīng)對和管理復(fù)雜性的四種最基本武器酥泞。
最近團(tuán)隊(duì)來了一些新人砚殿,有些有一定工作經(jīng)驗(yàn),是以高級工程師/架構(gòu)師身份進(jìn)來的婶博,但我發(fā)現(xiàn)他們大部分人思維偏應(yīng)用和細(xì)節(jié)瓮具,抽象能力弱。所以作為團(tuán)隊(duì)技術(shù)培訓(xùn)的一部分凡人,我整理了這篇文章名党,希望對他們樹立正確的架構(gòu)設(shè)計(jì)思維有幫助。我認(rèn)為挠轴,對思維習(xí)慣和思考能力的培養(yǎng)传睹,其重要性遠(yuǎn)遠(yuǎn)大于對實(shí)際技術(shù)工具的掌握。
由于文章內(nèi)容較長岸晦,所以我把它分成兩篇小文章欧啤,在第一篇《優(yōu)秀架構(gòu)師必須掌握的架構(gòu)思維》中,我會先介紹抽象启上、分層邢隧、分治和演化這四種應(yīng)對復(fù)雜性的基本思維。在第二篇《四個架構(gòu)設(shè)計(jì)案例及其思維方式》中冈在,我會通過四個案例倒慧,講解如何綜合運(yùn)用這些思維,分別對小型系統(tǒng)包券,中型系統(tǒng)纫谅,基礎(chǔ)架構(gòu),甚至是組織技術(shù)體系進(jìn)行架構(gòu)和設(shè)計(jì)溅固。
在進(jìn)入正文之前付秕,順便給大家推薦一個架構(gòu)方面的交流學(xué)習(xí)群:650385180,里面會分享一些資深架構(gòu)師錄制的視頻錄像:有Spring侍郭,MyBatis询吴,Netty源碼分析,高并發(fā)亮元、高性能汰寓、分布式、微服務(wù)架構(gòu)的原理苹粟,JVM性能優(yōu)化這些成為架構(gòu)師必備的知識體系。相信對于已經(jīng)工作和遇到技術(shù)瓶頸的同學(xué)跃闹,在這個群里會有你需要的內(nèi)容嵌削。有需要的同學(xué)請抓緊時間加入進(jìn)來毛好。
一、抽象思維
如果要問軟件研發(fā)/系統(tǒng)架構(gòu)中最重要的能力是什么苛秕,我會毫不猶豫回答是抽象能力肌访。抽象(abstraction)這個詞大家經(jīng)常聽到,但是真正理解和能講清楚什么是抽象的人少之又少艇劫。抽象其實(shí)是這樣定義的:
對某種事物進(jìn)行簡化表示或描述的過程吼驶,抽象讓我們關(guān)注要素,隱藏額外細(xì)節(jié)店煞。
舉一個例子蟹演,見下圖:
你看到什么?你看到的是一扇門顷蟀,對不對酒请?你看到的不是木頭,也不是碳原子鸣个,這個門就是抽象羞反,而木頭或者碳原子是細(xì)節(jié)。另外你可以看到門上有個門把手囤萤,你看到的不是鐵昼窗,也不是鐵原子,門把手就是抽象涛舍,鐵和鐵原子是細(xì)節(jié)澄惊。
在系統(tǒng)架構(gòu)和設(shè)計(jì)中,抽象幫助我們從大處著眼(get our mind about big picture)做盅,隱藏細(xì)節(jié)(temporarily hide details)缤削。抽象能力的強(qiáng)弱,直接決定我們所能解決問題的復(fù)雜性和規(guī)模大小吹榴。
下圖是我們小時候玩的積木亭敢,我發(fā)現(xiàn)小時候喜歡玩搭積木的,并且搭得快和好的小朋友图筹,一般抽象能力都比較強(qiáng)帅刀。
上圖右邊的積木城堡就是抽象,這個城堡如果你細(xì)看的話远剩,它其實(shí)還是由若干個子模塊組成扣溺,這些模塊是子抽象單元,左邊的各種形狀的積木是細(xì)節(jié)瓜晤。搭積木的時候锥余,小朋友腦袋里頭先有一個城堡的大圖(抽象),然后他/她大腦里頭會有一個初步的子模塊分解(潛意識中完成)痢掠,然用利用積木搭建每一個子模塊驱犹,最終拼裝出最后的城堡嘲恍。這里頭有一個自頂向下的分治設(shè)計(jì),然后自底向上的組合過程雄驹,這個分治思維非常重要佃牛,我們后面會講。
我認(rèn)為軟件系統(tǒng)架構(gòu)設(shè)計(jì)和小朋友搭積木無本質(zhì)差異医舆,只是解決的問題域和規(guī)模不同罷了俘侠。架構(gòu)師先要在大腦中形成抽象概念,然后是子模塊分解蔬将,然后是依次實(shí)現(xiàn)子模塊爷速,最后將子模塊拼裝組合起來,形成最后系統(tǒng)娃胆。所以我常說編程和架構(gòu)設(shè)計(jì)就是搭積木遍希,優(yōu)秀的架構(gòu)師受職業(yè)習(xí)慣影響,眼睛里看到的世界都是模塊化拼裝組合式的里烦。
抽象能力不僅對軟件系統(tǒng)架構(gòu)設(shè)計(jì)重要凿蒜,對建筑、商業(yè)胁黑、管理等人類其它領(lǐng)域活動同樣非常重要废封。其實(shí)可以這樣認(rèn)為,我們生存的世界都是在抽象的基礎(chǔ)上構(gòu)建起來的丧蘸,離開抽象人類將寸步難行漂洋。
這里順便提一下抽象層次跳躍問題,這個在開發(fā)中是蠻普遍的力喷。有經(jīng)驗(yàn)的程序員寫代碼會保持抽象層次的一致性刽漂,代碼讀起來像講故事,比較清晰易于理解弟孟;而沒有經(jīng)驗(yàn)的程序員會有明顯的抽象層次跳躍問題贝咙,代碼讀起來就比較累,這個是抽象能力不足造成拂募。舉個例子:
一個電商網(wǎng)站在處理訂單時庭猩,一般會走這樣一個流程:
更新庫存(InventoryUpdate)
打折計(jì)算(Discounting)
支付卡校驗(yàn)(PaycardVerification)
支付(Pay)
送貨(Shipping)
上述流程中的抽象是在同一個層次上的,比較清晰易于理解陈症,但是沒有經(jīng)驗(yàn)的程序員在實(shí)現(xiàn)這個流程的時候蔼水,代碼層次會跳,比方說主流程到支付卡校驗(yàn)一塊录肯,他的代碼會突然跳出一行某銀行API遠(yuǎn)程調(diào)用趴腋,這個就是抽象跳躍,銀行API調(diào)用是細(xì)節(jié),應(yīng)該封裝在PaycardVerification這個抽象里頭优炬。
二疏叨、分層思維
除了抽象,分層也是我們應(yīng)對和管理復(fù)雜性的基本思維武器穿剖,如下圖,為了構(gòu)建一套復(fù)雜系統(tǒng)卦溢,我們把整個系統(tǒng)劃分成若干個層次糊余,每一層專注解決某個領(lǐng)域的問題,并向上提供服務(wù)单寂。有些層次是縱向的贬芥,它貫穿所有其它層次,稱為共享層宣决。分層也可以認(rèn)為是抽象的一種方式蘸劈,將系統(tǒng)抽象分解成若干層次化的模塊。
分層架構(gòu)的案例很多尊沸,一個中小型的Spring Web應(yīng)用程序威沫,我們一般會設(shè)計(jì)成三層架構(gòu):
操作系統(tǒng)是經(jīng)典的分層架構(gòu),如下圖:
TCP/IP協(xié)議棧也是經(jīng)典的分層架構(gòu)洼专,如下圖:
如果你關(guān)注人類文明演化史棒掠,你會發(fā)現(xiàn)今天的人類世界也是以分層方式一層層搭建和演化出來的。今天的互聯(lián)網(wǎng)系統(tǒng)可以認(rèn)為是現(xiàn)代文明的一個層次屁商,其上是基于互聯(lián)網(wǎng)的現(xiàn)代商業(yè)烟很,其下是現(xiàn)代電子工業(yè)基礎(chǔ)設(shè)施,諸如此類蜡镶。
三雾袱、分治思維
分而治之(divide and combine或者split and merge)也是應(yīng)對和管理復(fù)雜性的一般性方法,下圖展示一個分治的思維流程:
對于一個無法一次解決的大問題官还,我們會先把大問題分解成若干個子問題芹橡,如果子問題還無法直接解決,則繼續(xù)分解成子子問題妻枕,直到可以直接解決的程度僻族,這個是分解(divide)的過程;然后將子子問題的解組合拼裝成子問題的解屡谐,再將子問題的解組合拼裝成原問題的解述么,這個是組合(combine)的過程。
面試時為了考察候選人的分治思維愕掏,我經(jīng)常會面一個分治題:給你一臺8G內(nèi)存/500G磁盤空間的普通電腦度秘,如何對一個100G的大文件進(jìn)行排序?假定文件中都是字符串記錄,一行約100個字符剑梳。
這是一個典型的分治問題唆貌,100G的大文件肯定無法一次加載到內(nèi)存直接排序,所以需要先切分成若干小問題來解決垢乙。那么8G內(nèi)存的計(jì)算機(jī)一次大概能排多大的數(shù)據(jù)量锨咙,可以在有限的時間內(nèi)排完呢?也就是100G的大文件要怎么切法追逮,切成多少份比較合適酪刀?這個是考察候選人的時間空間復(fù)雜度估算能力,需要一定的計(jì)算機(jī)組織和算法功底钮孵,也需要一定實(shí)戰(zhàn)經(jīng)驗(yàn)和sense骂倘。實(shí)際上8G內(nèi)存的話,操作系統(tǒng)要用掉一部分巴席,如果用Java開發(fā)排序程序历涝,大致JVM可用2~4G內(nèi)存,基于一般的經(jīng)驗(yàn)值漾唉,一次排1G左右的數(shù)據(jù)應(yīng)該沒有問題(我實(shí)際在計(jì)算機(jī)上干過1G數(shù)據(jù)的排序荧库,是OK的)。所以100G的文件需要先切分成100份毡证,每份1G电爹,這樣每個子文件可以直接加載到內(nèi)存進(jìn)行排序。對于1G數(shù)據(jù)量的字符串排序料睛,采用Java里頭提供的快速排序算法是比較合適的丐箩。
好,經(jīng)過有限時間的排序(取決于計(jì)算機(jī)性能恤煞,快的一天內(nèi)能排完)屎勘,假定100個1G的文件都已經(jīng)排好了,相當(dāng)于現(xiàn)在硬盤上有100個已經(jīng)排好序的文件居扒,但是我們最終需要的是一個排好序的文件概漱,下面該怎么做?這個時候我們需要把已經(jīng)解決的子問題組合起來喜喂,合并成我們需要的最終結(jié)果文件瓤摧。這個時候該采用什么算法呢?這里考察候選人對外排序和歸并排序算法的掌握程度玉吁,我們可以將100個排好序的文件進(jìn)行兩兩歸并排序照弥,這樣不斷重復(fù),我們就會得到50個排好序的文件进副,每個大小是2G这揣。然后再兩兩歸并,不斷重復(fù),直到最后兩個文件歸并成目標(biāo)文件给赞,這個文件就是100G并且是排好序的机打。因?yàn)槭峭馀判?歸并排序,每次只需要讀取當(dāng)前索引指向的文件記錄到內(nèi)存片迅,進(jìn)行比較残邀,小的那個輸出到目標(biāo)文件,內(nèi)存占用極少柑蛇。另外罐旗,上面的算法是兩路歸并,也可以采用多路歸并唯蝶,甚至是采用堆排序進(jìn)行優(yōu)化,但是總體分治思路沒有變化遗嗽。
總體上這是一個非常好的面試題粘我,除了考察候選人的分治思維之外,還考察對各種排序算法(快排征字,外排序娇豫,歸并排序匙姜,堆排序)的理解冯痢,計(jì)算的時間空間復(fù)雜度估算氮昧,計(jì)算機(jī)的內(nèi)外存特性和組織,文件操作等等袖肥。實(shí)際上能完全回答清楚這個問題的候選人極少振劳,如果有幸被我面到一個椎组,我會如獲至寶,因?yàn)檫@個人有成長為優(yōu)秀架構(gòu)師的潛質(zhì)历恐。
另外寸癌,遞歸也是一種特殊的分治技術(shù)蒸苇,掌握遞歸技術(shù)的開發(fā)人員哮洽,相當(dāng)于掌握了一種強(qiáng)大的編程武器,可以解決一些一般開發(fā)人員無法解決的問題。比方說最近我的團(tuán)隊(duì)在研發(fā)一款新的服務(wù)框架莺葫,其中包括契約解析器(parser)枪眉,代碼生產(chǎn)器(code generator),序列化器(serializer)等組件贸铜,里頭大量需要用到遞歸的思維和技術(shù),沒有這個思維的開發(fā)人員就干不了這個事情烤镐。所以我在面試候選人的時候棍鳖,一般都會出遞歸相關(guān)的編程題,考察候選人的遞歸思維镜悉。
大自然中遞歸結(jié)構(gòu)比比皆是医瘫,如下圖,大家有興趣不妨思考稼锅,大自然通過遞歸給我們?nèi)祟惡畏N啟示?
四僚纷、演化思維
社區(qū)里頭經(jīng)常有人在討論:架構(gòu)是設(shè)計(jì)出來的?還是演化出來的畔濒?我個人基于十多年的經(jīng)驗(yàn)認(rèn)為,架構(gòu)既是設(shè)計(jì)出來的赞弥,同時也是演化出來的趣兄,對于互聯(lián)網(wǎng)系統(tǒng),基本上可以說是三分設(shè)計(jì)拼窥,七分演化,而且是在設(shè)計(jì)中演化总棵,在演化中設(shè)計(jì)改含,一個不斷迭代的過程。
在互聯(lián)網(wǎng)軟件系統(tǒng)的整個生命周期過程中骤视,前期的設(shè)計(jì)和開發(fā)大致只占三分鹃觉,在后面的七分時間里,架構(gòu)師需要根據(jù)用戶的反饋對架構(gòu)進(jìn)行不斷的調(diào)整笼裳。我認(rèn)為架構(gòu)師除了要利用自身的架構(gòu)設(shè)計(jì)能力粱玲,同時也要學(xué)會借助用戶反饋和進(jìn)化的力量拜轨,推動架構(gòu)的持續(xù)演進(jìn),這個就是演化式架構(gòu)思維卵沉。
當(dāng)然一開始的架構(gòu)設(shè)計(jì)非常重要衷笋,架構(gòu)定系統(tǒng)基本就成型了听想,不容馬虎。同時,優(yōu)秀的架構(gòu)師深知悼瓮,能夠不斷應(yīng)對環(huán)境變化的系統(tǒng)横堡,才是有生命力的系統(tǒng),架構(gòu)的好壞命贴,很大部分取決于它應(yīng)對變化的靈活性。所以具有演化式思維的架構(gòu)師污茵,能夠在一開始設(shè)計(jì)時就考慮到后續(xù)架構(gòu)的演化特性,并且將靈活應(yīng)對變化的能力作為架構(gòu)設(shè)計(jì)的主要考量肃弟。
當(dāng)前零蓉,社區(qū)正在興起一種新的架構(gòu)方法學(xué)~演化式架構(gòu)敌蜂,微服務(wù)架構(gòu)就是一種典型的演化式架構(gòu),它能夠快速響應(yīng)市場用戶需求的變化章喉,而單塊架構(gòu)就缺乏這種靈活性秸脱。馬丁·福樂曾經(jīng)在其博客上給出過一張微服務(wù)架構(gòu)的演化路線圖[附錄8.2],可以用來解釋設(shè)計(jì)式思維和演化式思維的差異摊唇,如下圖所示:
上面的路線是一開始就直奔微服務(wù)架構(gòu)巷查,其實(shí)背后體現(xiàn)的是設(shè)計(jì)式架構(gòu)的思維,認(rèn)為架構(gòu)師可以完全設(shè)計(jì)整個系統(tǒng)和它的演化方向旭寿。馬丁認(rèn)為這種做法風(fēng)險非常高崇败,一個是成本高昂,另外一個是剛開始架構(gòu)師對業(yè)務(wù)域理解不深微渠,無法清晰劃分領(lǐng)域邊界咧擂,開發(fā)出來的系統(tǒng)很可能無法滿足用戶需求。
下面的路線是從單塊架構(gòu)開始云芦,隨著架構(gòu)師對業(yè)務(wù)域理解的不斷深入,也隨著業(yè)務(wù)和團(tuán)隊(duì)規(guī)模的不斷擴(kuò)大桌肴,漸進(jìn)式地把單塊架構(gòu)拆分成微服務(wù)架構(gòu)的思路琉历,這就是演化式架構(gòu)的思維旗笔。如果你觀察現(xiàn)實(shí)世界中一些互聯(lián)網(wǎng)公司(例如eBay,阿里蝇恶,Netflix等等)的系統(tǒng)架構(gòu)撮弧,大部分走得都是演化式架構(gòu)的路線。
下圖是建筑的演化史贿衍,在每個階段贸辈,你可以看到設(shè)計(jì)的影子,但如果時間線拉得足夠長,演化的特性就出來了署浩。
五筋栋、如何培養(yǎng)架構(gòu)設(shè)計(jì)思維
良好的架構(gòu)設(shè)計(jì)思維的培養(yǎng),離不開工作中大量高質(zhì)量項(xiàng)目的實(shí)戰(zhàn)鍛煉抢腐,然后是平時的學(xué)習(xí)襟交、思考和提煉總結(jié)。
另外啼染,基本的架構(gòu)設(shè)計(jì)思維,其實(shí)在我們大學(xué)計(jì)算機(jī)課程(比如數(shù)據(jù)結(jié)構(gòu)和算法)中可以找到影子卦洽,只不過當(dāng)時以學(xué)習(xí)為主斜棚,問題域比較小和理想化。所以大學(xué)教育其實(shí)非常重要蚤霞,基本的架構(gòu)設(shè)計(jì)思維在那個時候就已經(jīng)埋下種子粗梭,后面工程實(shí)踐中進(jìn)一步消化和應(yīng)用,隨著經(jīng)驗(yàn)的積累滞乙,我們能夠解決的問題域復(fù)雜性和規(guī)模逐漸變大鉴嗤,但基本的武器還是抽象、分層和分治等思維兔簇。
我認(rèn)為一個架構(gòu)師的成長高度和他大學(xué)期間的思維習(xí)慣的養(yǎng)成關(guān)系密切硬耍。我所知道世界一流的互聯(lián)網(wǎng)公司经柴,例如谷歌等,招聘工程師新人時坯认,對數(shù)據(jù)結(jié)構(gòu)和算法的要求可以用苛刻來形容牛哺,這個可以理解,谷歌級別公司要解決的問題都是超級復(fù)雜的巩趁,基本思維功底薄弱根本無法應(yīng)對淳附。
對于工作經(jīng)驗(yàn)<5年的工程師新手凰荚,如果你大學(xué)時代是屬于荒廢型的便瑟,建議工作之余把相關(guān)課程再好好自學(xué)一把番川。個人推薦參考美國Berkeley大學(xué)的數(shù)據(jù)結(jié)構(gòu)課程CS61B[附錄8.1]進(jìn)行學(xué)習(xí),對建立抽象編程思維非常有幫助践啄,我本人在研究生階段自學(xué)過這門課程沉御,現(xiàn)在回想起來確實(shí)受益匪淺,注意該課程中的所有Lab/Homework/Project都要實(shí)際動手做一遍伐谈,才有好的效果试疙。
對于演化設(shè)計(jì)思維祝旷,當(dāng)前的大學(xué)教育其實(shí)培養(yǎng)很少,相反距贷,當(dāng)前大學(xué)教育大都采用脫離現(xiàn)實(shí)場景的簡化理想模型吻谋,有些還是固定答案的應(yīng)試教學(xué),這種方式會造成學(xué)生思維確定化什湘,不利于培養(yǎng)演化式設(shè)計(jì)思維晦攒。我個人的體會脯颜,演化式設(shè)計(jì)思維更多在實(shí)際工作中通過實(shí)戰(zhàn)鍛煉和培養(yǎng)贩据。
結(jié)論
架構(gòu)的本質(zhì)是管理復(fù)雜性闸餐,抽象舍沙、分層剔宪、分治和演化思維是架構(gòu)師征服復(fù)雜性的四種根本性武器。
掌握了抽象感帅、分層地淀、分治和演化這四種基本的武器,你可以設(shè)計(jì)小到一個類实苞,一個模塊作箍,一個子系統(tǒng)胞得,或者一個中型的系統(tǒng),也可以大到一個公司的基礎(chǔ)平臺架構(gòu)跃巡,微服務(wù)架構(gòu)牧愁,技術(shù)體系架構(gòu),甚至是組織架構(gòu)兔朦,業(yè)務(wù)架構(gòu)等等磨确。
架構(gòu)設(shè)計(jì)不是靜態(tài)的,而是動態(tài)演化的摆舟。只有能夠不斷應(yīng)對環(huán)境變化的系統(tǒng),才是有生命力的系統(tǒng)媳瞪。所以即使你掌握了抽象照宝、分層和分治這三種基本思維厕鹃,仍然需要演化式思維,在設(shè)計(jì)的同時旨别,借助反饋和進(jìn)化的力量推動架構(gòu)的持續(xù)演進(jìn)汗茄。
架構(gòu)師在關(guān)注技術(shù),開發(fā)應(yīng)用的同時递览,需要定期梳理自己的架構(gòu)設(shè)計(jì)思維瞳腌,積累時間長了嫂侍,你看待世界事物的方式會發(fā)生根本性變化,你會發(fā)現(xiàn)我們生活其中的世界菲盾,其實(shí)也是在抽象各淀、分層、分治和演化的基礎(chǔ)上構(gòu)建起來的临谱。另外架構(gòu)設(shè)計(jì)思維的形成奴璃,會對你的系統(tǒng)架構(gòu)設(shè)計(jì)能力產(chǎn)生重大影響溺健。可以說對抽象剖膳、分層岭辣、分治和演化掌握的深度和靈活應(yīng)用的水平,直接決定架構(gòu)師所能解決問題域的復(fù)雜性和規(guī)模大小仑濒,是區(qū)分普通應(yīng)用型架構(gòu)師和平臺型/系統(tǒng)型架構(gòu)師的一個分水嶺偷遗。
參考
Berkeley CS61Bhttp://datastructur.es/sp17/
單塊優(yōu)先https://www.martinfowler.com/bliki/MonolithFirst.html