架構思惟

優秀架構師必須掌握的架構思惟

 介紹

架構的本質是管理複雜性,抽象、分層、分治和演化思惟是咱們工程師/架構師應對和管理複雜性的四種最基本武器。程序員

最近團隊來了一些新人,有些有必定工做經驗,是以高級工程師/架構師身份進來的,但我發現他們大部分人思惟偏應用和細節,抽象能力弱。因此做爲團隊技術培訓的一部分,我整理了這篇文章,但願對他們樹立正確的架構設計思惟有幫助。我認爲,對思惟習慣和思考能力的培養,其重要性遠遠大於對實際技術工具的掌握。web

因爲文章內容較長,因此我把它分紅兩篇小文章,在第一篇《優秀架構師必須掌握的架構思惟》中,我會先介紹抽象、分層、分治和演化這四種應對複雜性的基本思惟。在第二篇《四個架構設計案例及其思惟方式》中,我會經過四個案例,講解如何綜合運用這些思惟,分別對小型系統,中型系統,基礎架構,甚至是組織技術體系進行架構和設計。面試

在進入正文以前,順便推薦一下我在極客時間開設的《微服務架構實戰 160 講》視頻課程,微服務是架構師必須掌握的核心技能,本週五是課程的最後一天優惠期,想訂閱的同窗請抓緊最後的優惠機會。算法

掃碼或點擊圖片下方圖片便可訂閱。編程

1、抽象思惟

若是要問軟件研發/系統架構中最重要的能力是什麼,我會絕不猶豫回答是抽象能力。抽象(abstraction)這個詞你們常常聽到,可是真正理解和能講清楚什麼是抽象的人少之又少。抽象實際上是這樣定義的:canvas

對某種事物進行簡化表示或描述的過程,抽象讓咱們關注要素,隱藏額外細節。數據結構

舉一個例子,見下圖:架構

你看到什麼?你看到的是一扇門,對不對?你看到的不是木頭,也不是碳原子,這個門就是抽象,而木頭或者碳原子是細節。另外你能夠看到門上有個門把手,你看到的不是鐵,也不是鐵原子,門把手就是抽象,鐵和鐵原子是細節。框架

在系統架構和設計中,抽象幫助咱們從大處着眼(get our mind about big picture),隱藏細節(temporarily hide details)。抽象能力的強弱,直接決定咱們所能解決問題的複雜性和規模大小。數據結構和算法

下圖是咱們小時候玩的積木,我發現小時候喜歡玩搭積木的,而且搭得快和好的小朋友,通常抽象能力都比較強。

上圖右邊的積木城堡就是抽象,這個城堡若是你細看的話,它其實仍是由若干個子模塊組成,這些模塊是子抽象單元,左邊的各類形狀的積木是細節。搭積木的時候,小朋友腦殼裏頭先有一個城堡的大圖(抽象),而後他/她大腦裏頭會有一個初步的子模塊分解(潛意識中完成),然用利用積木搭建每個子模塊,最終拼裝出最後的城堡。這裏頭有一個自頂向下的分治設計,而後自底向上的組合過程,這個分治思惟很是重要,咱們後面會講。

我認爲軟件系統架構設計和小朋友搭積木無本質差別,只是解決的問題域和規模不一樣罷了。架構師先要在大腦中造成抽象概念,而後是子模塊分解,而後是依次實現子模塊,最後將子模塊拼裝組合起來,造成最後系統。因此我常說編程和架構設計就是搭積木,優秀的架構師受職業習慣影響,眼睛裏看到的世界都是模塊化拼裝組合式的。

抽象能力不只對軟件系統架構設計重要,對建築、商業、管理等人類其它領域活動一樣很是重要。其實能夠這樣認爲,咱們生存的世界都是在抽象的基礎上構建起來的,離開抽象人類將步履維艱。

這裏順便提一下抽象層次跳躍問題,這個在開發中是蠻廣泛的。有經驗的程序員寫代碼會保持抽象層次的一致性,代碼讀起來像講故事,比較清晰易於理解;而沒有經驗的程序員會有明顯的抽象層次跳躍問題,代碼讀起來就比較累,這個是抽象能力不足形成。舉個例子:

一個電商網站在處理訂單時,通常會走這樣一個流程:

  1. 更新庫存(InventoryUpdate)
  2. 打折計算(Discounting)
  3. 支付卡校驗(PaycardVerification)
  4. 支付(Pay)
  5. 送貨(Shipping)

上述流程中的抽象是在同一個層次上的,比較清晰易於理解,可是沒有經驗的程序員在實現這個流程的時候,代碼層次會跳,比方說主流程到支付卡校驗一塊,他的代碼會忽然跳出一行某銀行API遠程調用,這個就是抽象跳躍,銀行API調用是細節,應該封裝在PaycardVerification這個抽象裏頭。

2、分層思惟

除了抽象,分層也是咱們應對和管理複雜性的基本思惟武器,以下圖,爲了構建一套複雜系統,咱們把整個系統劃分紅若干個層次,每一層專一解決某個領域的問題,並向上提供服務。有些層次是縱向的,它貫穿全部其它層次,稱爲共享層。分層也能夠認爲是抽象的一種方式,將系統抽象分解成若干層次化的模塊。

分層架構的案例不少,一箇中小型的Spring Web應用程序,咱們通常會設計成三層架構:

操做系統是經典的分層架構,以下圖:

TCP/IP協議棧也是經典的分層架構,以下圖:

若是你關注人類文明演化史,你會發現今天的人類世界也是以分層方式一層層搭建和演化出來的。今天的互聯網系統能夠認爲是現代文明的一個層次,其上是基於互聯網的現代商業,其下是現代電子工業基礎設施,諸如此類。

3、分治思惟

分而治之(divide and combine或者split and merge)也是應對和管理複雜性的通常性方法,下圖展現一個分治的思惟流程:

對於一個沒法一次解決的大問題,咱們會先把大問題分解成若干個子問題,若是子問題還沒法直接解決,則繼續分解成子子問題,直到能夠直接解決的程度,這個是分解(divide)的過程;而後將子子問題的解組合拼裝成子問題的解,再將子問題的解組合拼裝成原問題的解,這個是組合(combine)的過程。

面試時爲了考察候選人的分治思惟,我常常會面一個分治題:給你一臺8G內存/500G磁盤空間的普通電腦,如何對一個100G的大文件進行排序?假定文件中都是字符串記錄,一行約100個字符。

這是一個典型的分治問題,100G的大文件確定沒法一次加載到內存直接排序,因此須要先切分紅若干小問題來解決。那麼8G內存的計算機一次大概能排多大的數據量,能夠在有限的時間內排完呢?也就是100G的大文件要怎麼切法,切成多少份比較合適?這個是考察候選人的時間空間複雜度估算能力,須要必定的計算機組織和算法功底,也須要必定實戰經驗和sense。實際上8G內存的話,操做系統要用掉一部分,若是用Java開發排序程序,大體JVM可用2~4G內存,基於通常的經驗值,一次排1G左右的數據應該沒有問題(我實際在計算機上幹過1G數據的排序,是OK的)。因此100G的文件須要先切分紅100份,每份1G,這樣每一個子文件能夠直接加載到內存進行排序。對於1G數據量的字符串排序,採用Java裏頭提供的快速排序算法是比較合適的。

好,通過有限時間的排序(取決於計算機性能,快的一天內能排完),假定100個1G的文件都已經排好了,至關於如今硬盤上有100個已經排好序的文件,可是咱們最終須要的是一個排好序的文件,下面該怎麼作?這個時候咱們須要把已經解決的子問題組合起來,合併成咱們須要的最終結果文件。這個時候該採用什麼算法呢?這裏考察候選人對外排序和歸併排序算法的掌握程度,咱們能夠將100個排好序的文件進行兩兩歸併排序,這樣不斷重複,咱們就會獲得50個排好序的文件,每一個大小是2G。而後再兩兩歸併,不斷重複,直到最後兩個文件歸併成目標文件,這個文件就是100G而且是排好序的。由於是外排序+歸併排序,每次只須要讀取當前索引指向的文件記錄到內存,進行比較,小的那個輸出到目標文件,內存佔用極少。另外,上面的算法是兩路歸併,也能夠採用多路歸併,甚至是採用堆排序進行優化,可是整體分治思路沒有變化。

整體上這是一個很是好的面試題,除了考察候選人的分治思惟以外,還考察對各類排序算法(快排,外排序,歸併排序,堆排序)的理解,計算的時間空間複雜度估算,計算機的內外存特性和組織,文件操做等等。實際上能徹底回答清楚這個問題的候選人極少,若是有幸被我面到一個,我會如獲至寶,由於這我的有成長爲優秀架構師的潛質。

另外,遞歸也是一種特殊的分治技術,掌握遞歸技術的開發人員,至關於掌握了一種強大的編程武器,能夠解決一些通常開發人員沒法解決的問題。比方說最近個人團隊在研發一款新的服務框架,其中包括契約解析器(parser),代碼生產器(code generator),序列化器(serializer)等組件,裏頭大量須要用到遞歸的思惟和技術,沒有這個思惟的開發人員就幹不了這個事情。因此我在面試候選人的時候,通常都會出遞歸相關的編程題,考察候選人的遞歸思惟。

大天然中遞歸結構比比皆是,以下圖,你們有興趣不妨思考,大天然經過遞歸給咱們人類何種啓示?

4、演化思惟

社區裏頭常常有人在討論:架構是設計出來的?仍是演化出來的?我我的基於十多年的經驗認爲,架構既是設計出來的,同時也是演化出來的,對於互聯網系統,基本上能夠說是三分設計,七分演化,並且是在設計中演化,在演化中設計,一個不斷迭代的過程。

在互聯網軟件系統的整個生命週期過程當中,前期的設計和開發大體只佔三分,在後面的七分時間裏,架構師須要根據用戶的反饋對架構進行不斷的調整。我認爲架構師除了要利用自身的架構設計能力,同時也要學會藉助用戶反饋和進化的力量,推進架構的持續演進,這個就是演化式架構思惟。

固然一開始的架構設計很是重要,架構定系統基本就成型了,不容馬虎。同時,優秀的架構師深知,可以不斷應對環境變化的系統,纔是有生命力的系統,架構的好壞,很大部分取決於它應對變化的靈活性。因此具備演化式思惟的架構師,可以在一開始設計時就考慮到後續架構的演化特性,而且將靈活應對變化的能力做爲架構設計的主要考量。

當前,社區正在興起一種新的架構方法學~演化式架構,微服務架構就是一種典型的演化式架構,它可以快速響應市場用戶需求的變化,而單塊架構就缺少這種靈活性。馬丁·福樂曾經在其博客上給出過一張微服務架構的演化路線圖[附錄8.2],能夠用來解釋設計式思惟和演化式思惟的差別,以下圖所示:

上面的路線是一開始就直奔微服務架構,其實背後體現的是設計式架構的思惟,認爲架構師能夠徹底設計整個系統和它的演化方向。馬丁認爲這種作法風險很是高,一個是成本高昂,另一個是剛開始架構師對業務域理解不深,沒法清晰劃分領域邊界,開發出來的系統極可能沒法知足用戶需求。

下面的路線是從單塊架構開始,隨着架構師對業務域理解的不斷深刻,也隨着業務和團隊規模的不斷擴大,漸進式地把單塊架構拆分紅微服務架構的思路,這就是演化式架構的思惟。若是你觀察現實世界中一些互聯網公司(例如eBay,阿里,Netflix等等)的系統架構,大部分走得都是演化式架構的路線。

下圖是建築的演化史,在每一個階段,你能夠看到設計的影子,但若是時間線拉得足夠長,演化的特性就出來了。

5、如何培養架構設計思惟

良好的架構設計思惟的培養,離不開工做中大量高質量項目的實戰鍛鍊,而後是平時的學習、思考和提煉總結。

另外,基本的架構設計思惟,其實在咱們大學計算機課程(好比數據結構和算法)中能夠找到影子,只不過當時以學習爲主,問題域比較小和理想化。因此大學教育其實很是重要,基本的架構設計思惟在那個時候就已經埋下種子,後面工程實踐中進一步消化和應用,隨着經驗的積累,咱們可以解決的問題域複雜性和規模逐漸變大,但基本的武器仍是抽象、分層和分治等思惟。

我認爲一個架構師的成長高度和他大學期間的思惟習慣的養成關係密切。我所知道世界一流的互聯網公司,例如谷歌等,招聘工程師新人時,對數據結構和算法的要求能夠用苛刻來形容,這個能夠理解,谷歌級別公司要解決的問題都是超級複雜的,基本思惟功底薄弱根本沒法應對。

對於工做經驗<5年的工程師新手,若是你大學時代是屬於荒廢型的,建議工做之餘把相關課程再好好自學一把。我的推薦參考美國Berkeley大學的數據結構課程CS61B[附錄8.1]進行學習,對創建抽象編程思惟很是有幫助,我本人在研究生階段自學過這門課程,如今回想起來確實受益不淺,注意該課程中的全部Lab/Homework/Project都要實際動手作一遍,纔有好的效果。

我當年自學的是CS61B 2006秋季版的課程,上圖是課程Logo

對於演化設計思惟,當前的大學教育其實培養不多,相反,當前大學教育大都採用脫離現實場景的簡化理想模型,有些仍是固定答案的應試教學,這種方式會形成學生思惟肯定化,不利於培養演化式設計思惟。我我的的體會,演化式設計思惟更多在實際工做中經過實戰鍛鍊和培養。

結論

  1. 架構的本質是管理複雜性,抽象、分層、分治和演化思惟是架構師征服複雜性的四種根本性武器。
  2. 掌握了抽象、分層、分治和演化這四種基本的武器,你能夠設計小到一個類,一個模塊,一個子系統,或者一箇中型的系統,也能夠大到一個公司的基礎平臺架構,微服務架構,技術體系架構,甚至是組織架構,業務架構等等。
  3. 架構設計不是靜態的,而是動態演化的。只有可以不斷應對環境變化的系統,纔是有生命力的系統。因此即便你掌握了抽象、分層和分治這三種基本思惟,仍然須要演化式思惟,在設計的同時,藉助反饋和進化的力量推進架構的持續演進。
  4. 架構師在關注技術,開發應用的同時,須要按期梳理本身的架構設計思惟,積累時間長了,你看待世界事物的方式會發生根本性變化,你會發現咱們生活其中的世界,其實也是在抽象、分層、分治和演化的基礎上構建起來的。另外架構設計思惟的造成,會對你的系統架構設計能力產生重大影響。能夠說對抽象、分層、分治和演化掌握的深度和靈活應用的水平,直接決定架構師所能解決問題域的複雜性和規模大小,是區分普通應用型架構師和平臺型/系統型架構師的一個分水嶺。
相關文章
相關標籤/搜索