得先理解什麼是架構

首先,本文不是想介紹架構設計一步一步如何做,細節的技術手段,完整的理論框架這些問題。這些問題在一篇文章中也不可能覆蓋。本文更多時候是想給很多從細節設計中走過來,對什麼是架構設計只有過一些模糊的,不成形想法的工程師,建立一些基本的認識,理解架構設計的必要性,以及如何看待很多具體的技術對這種必要性的幫助。

從信息論的角度,本文不是要提供新的信息,而是要幫助讀者已經擁有的信息。這恰恰也是架構設計的作用:架構設計不是要取代設計,而是在整理設計的組織,讓設計的力量最終指向目標。

以我個人的經驗,剛剛開始進入架構設計的工程師,常常對架構設計的整個認識都是錯誤的,這些錯誤的認識會讓他們越走越遠,甚至最終破壞架構。這是本文希望提供的幫助。我希望通過這些思路上的幫助,讓我們身邊的工程師更多從架構的角度考慮問題,因爲沒有這樣的文化氛圍,我們很難真正合作起來,也無法讓我們多個技術可以持續發展和積累下去,更無法面對未來的挑戰。

我在架構上的很多經驗,源自對自己設計過程的反思,以及對後進的工程師的指導,所以在介紹的過程中不免流露一些 “好爲人師” 的感覺,我並非覺得自己就比聽衆們高明,只是如果我不用這樣的描述方法,我的講述就會變成一些經典教材那樣——它裏面說的東西都是對的,但聽衆沒有從中獲益。這更非我的本意。

什麼是架構設計

架構設計是一個非常抽象的概念,從不同的角度有不同的理解。我們先從一個比較高的角度來抽象一下這個問題。我們用畫畫來做個類比,這樣比較直觀。在畫畫的時候,如果我們要畫一個人,我們不會一開始就把眼睛的全部細節畫出來:

因爲這樣不一定能和我們要畫的整個人對得上:

如果我們要畫的整個人的姿態是下面這幅圖的樣子的,上面那個眼睛整個都是錯的,因爲角度就不對。

軟件和硬件的設計同樣存在這樣的問題,一個軟件,一個硬件,或者一個包含軟件硬件的產品,包含非常多的細節,如果我們一開始就開始 “畫眼睛”,那麼很可能我們經過一個很長的開發週期,最後發現我們做錯了。

比如你花了無數的功夫對每個模塊進行存儲優化,把運行內存的需求壓縮到只有 1M,結果最後發現內存在這個設備中的成本只佔 0.1%,你這些工作就白乾了。這還只是浪費工作量,可能你設計一個複雜的加密手段,但加密後你的設備就不能運行用戶自己的軟件了,你這個產品也就廢了。

畫家可以從一個細節看到一個整體,比如,專業的畫家可能從上面那個眼睛,就能意識到這個人是正面對着觀察者的視角的,但不一定是坐着還是站着,說不定他還能從眼睛的放鬆程度,能知道這個人不是躺着。

一個系統架構師也能從一個產品的特定細節看到這個產品的全體。比如一個芯片構架師可以從系統總線協議猜到芯片的加工可能用到的製程,進而猜到這個芯片可以實現的最大內存帶寬。一個軟件架構師可以從某個 API 產生了對 “設備” 這個概念的關聯,從而知道使用這個 API 的帶寬會被限制在一個設備之內,無法被 Scaling。

所以,構架設計工作是一種 “形而上” 的工作。架構師用細節控制整體。好比畫家用線條控制整個人。架構的描述語言並非它表面表述的嚴格意思,它是用這個細節去反映某個整體的打算。當架構師說某個 API 應該是什麼樣的,和具體實現的工程師眼中的這個 API 本身是什麼樣的,兩人的着眼點是不同的,具體實現的工程師僅僅是爲了解決這一層面把參數傳遞過去的問題。而架構師設計一個 API,他的目的是在這個位置上設計一個 “約束”,導致其他細節設計在這個位置上被限制住,最終不會偏離整個設計目標。

架構上說某個 API 是 get(int),我們可能不在乎實施的時候變成 get(int, int) 或者增加一個 get2(int, void *),因爲實施這些修改的成本不高(後面我們講關聯的時候再來討論這個問題),我們說 get(int) 只是保證這個地方會有一個 “接口層”,具體一兩個變化,並不重要。

但如果這個設計上下文是在關注一組已經交付的二進制軟件,這個就是大的變化,因爲這時任何一點變化,都會導致整個接口和原來不一樣。這就是形而上設計的特徵,它不再具有形而下那種 “器” 的特點,在器這個角度覺得重要的東西,在它這裏不一定重要,反過來,在器這個層面覺得不重要的東西,在它這裏可以很重要。因爲兩者指向的設計目標是不同的。

深入一點說,這就是《道德經》中說的名和道的區別。“道”是包含全部細節的一個整體,而 “名” 是我們抽象出來的一個特徵。“名”永遠都不會包含 “道” 的全部細節。我們設定一個約束,我們說 XXX(...)都可以,這表示了無數的變數,最後我們就沒法交流了。所以我們用了一個 “名”,一個形而下的器,一個“具體情形”,來描述這個東西“大致” 是這樣的,你把它理解爲 “器”,非要認爲它“就是這樣” 的,這樣就把自由度都做沒了,你就失去做架構的作用的。

很多管理者希望把架構工作做成工具,或者把架構過程做成 “條條框框”,“最佳實踐”。但架構工作恰恰就是不能這樣乾的,因爲架構本來就是發明條條框框的方法,是發現某個具體情形下,能否設定,如何設定條條框框的一個過程。

在架構設計的過程中,新的約束不斷被發現和發明,主要矛盾會變成次要矛盾,架構提取的 “名” 也會隨之不同,進而策略也要跟隨變化,跟隨變化就是架構這個工作存在的原因。如果你希望在架構設計之前就設定固定的方法,那麼架構就無法發揮我們引入架構設計這個工作原本想起到的作用了。

也就是說,架構師和具體實現工程師設計的東西看起來很可能是完全一樣的,但他們的設計目標可以是完全不同的。就如同上面的兩幅素描,可能架構師和實現工程師都會畫 “眼睛”,但架構師關心的是 “整個人是什麼樣的,眼睛的位置和角度是在這個地方”,實現工程師關心的是 “知道眼睛在這個地方和這個人的年齡和心理狀態後,眼睛的睫毛如何表達,深度,陰影如何刻畫”。而且,在實現工程師具體去設計以後,架構圖上的那些線,是要逐步消隱的。

說起來,我這裏寫的這個提綱,也是一種 “架構”:我的演講 90 分鐘,包含更多的細節,但我怎麼保證我的演講可以聚焦,並完整傳遞一個邏輯給聽衆?我就需要寫一個更短的邏輯,在這個短邏輯中保證我的表述是自洽的。否則我可能絮絮叨叨 90 分鐘,其實什麼東西都沒有傳遞出去。而有了這個框架,我中間借題發揮,舉很多的例子,深入講某個例子的細節,都不會偏離我要講述的主題。

從架構這個角度說,我的描述如果不能對準同一個主題,這個 “產品” 整體就不呈現有效的“功能”。

具體對於每個架構設計,對於不同層次的架構設計,我們可能有不同的方法來 “繪製”(這個整體總結),但基礎原理都是這樣的:用粗線條先勾勒總體邏輯。

作爲 “形而上” 的設計,架構設計的給人的感覺沒有那麼瓷實,但架構設計仍是一種設計,它不是脫離邏輯而存在的。我在很多的架構評審或者分析會上,會聽到這樣的說法:這個地方說得不清楚,我們後面有詳細介紹,如果您關心,我們跳到後面去給您講?

這樣說就是不懂設計了,用上面那張人體架構圖來說,我跟你說你這個人的框架沒有設計好,你說我們來看看眼睛?——我不看眼睛,我就要在這層抽象上看到邏輯通了——這纔是設計。設計就必須有邏輯鏈。否則架構設計就沒有意義了,我們還不如直接設計細節。

架構設計是下圖示意的一個連續的過程:

本節小結:理解架構是一種形而上的邏輯非常重要,因爲架構語言中說的一個東西不是那個東西本來的意思,而是對細節的預判和無數經驗的總結。所以我們必須理解,沒有足夠的細節經驗,是不能成爲架構師的。這種經驗甚至不一定是某種細節設計的經驗,而是對細節反饋的經驗。

約束,關聯和邏輯自洽

作爲形而上的設計,我們要理解架構,就需要有足夠高的抽象思維能力。這一點能力,在座的各位,應該都是有的。因爲我們這麼多年的教育,本來就是在教這個能力,所以每位大學生畢業生都應該有這個能力。我要提出這一點,是要避免各位在我們後面討論抽象邏輯的時候覺得我說得太玄,或者覺得自己還沒有這部分知識,要先去 “學習” 一下才開始深入思考我討論的問題,這樣我就無法把我的觀點傳遞給你們了。

如果各位(unlikely)是混文憑出來的,我沒有什麼辦法。但我想大部分的人,可能僅僅學了很多具體的推理方法,沒有有意識去這些推理可以被 “抽象” 爲形而上的邏輯。我想提醒各位的是:不要被這些抽象的概念嚇住了,其實這些東西你本來就懂的。

從形而上的角度來說,我們通過 “邏輯” 進行預判和交流。所有的 “邏輯”,本質上是約束的引入。比如,我們說“你肯定餓壞了,來,喫點麪包”。這個邏輯設定了一個判斷上的約束:“你餓了”。如果這一點不成立,這整個邏輯就不成立。你認定了“你餓了” 這個約束,你的“設計”——“喫點麪包”——纔是成立的。設計需要有約束才能進行設計。

我們做任何一個設計,都必然來自一個約束。就算你寫一個 “Hello World”,你都引入了一個 “約束”:在我運行這個程序的時候,在屏幕上出現點有規律的東西,證明我們能控制這個系統。

我們在白紙上畫一個人,它也有一個約束:“畫個人”。畫個人是我們後面做所有的事情的基礎,我們不是畫貓畫狗,不是畫正弦曲線和座標系。有些約束我們甚至不一定會注意它:比如我們是用筆來畫它的,不是用刀子來刻它的。但這個無法深究,因爲我們關注的東西總是有限的。我們關注的是,我們建起一個邏輯鏈,可以說:“因爲要這樣,所以我這樣了”,我們這裏提到的 “要這樣” 是什麼。

“畫個人”是我們的約束,這個人坐着還是站在,是我們的 “自由”,但我們選擇了一個“自由”,我們就增加一個約束了:如果我們決定讓這個人坐着,這個人的是手和腳的距離就被約束了。整個“畫人” 的過程,本質上是不斷增加約束的過程,當這個 “人” 被畫好了,所有的約束就變成了“事實”,不可改變了。

在我們這個討論空間中,它是 “最高約束”,因爲你也不能改變它了。架構設計,是管理這個約束加入的過程,因爲先引入的約束,會控制我們後面引入的約束。由於整個實施的時間線很長,我們要避免不受控制的約束增加過程,導致後面我們怎麼都無法加入剩下的邏輯,最後這個目標就達不到了。

這裏理念從 “函數式編程” 的角度特別好理解,參考:https://zhuanlan.zhihu.com/p/173631835。架構設計就是函數帶參時的情形,細節設計就是 Curry 化的過程,每個細化就是消除一個參數維度,收窄整個自由空間。

f 本身是對自由度的一個約束(圖中曲面的範圍),當我們收窄它其中一個維度(比如把 z 收縮爲 4,甚至可以是某個範圍),剩下的邏輯就會簡單,但自由度也就更低了。

用畫人來類比的話,我們先約束整個人的 “姿態” 和環境光源的特點(點光源還是面光源等)和位置,我們就決定了眼睛,手腳的姿態,透視和光影了,這樣畫眼睛和手腳的時候,我們知道如何刻畫細節。但如果我們先畫眼睛和手腳,各自有自己的姿態和對光源的理解,這個眼睛和手腳放到一起,這就不像是個人了,這個 “畫人” 的目標就永遠不能達成了。

這種一個約束,控制了其他約束的情形,在架構的語言中,就稱爲 “關聯”。關聯就是說,如果我修改了一個邏輯的 “約束”,其他邏輯的約束也會跟着更改,那麼,這兩個邏輯,就存在 “關聯”。否則,我們就認爲他們沒有 “關聯”。

關聯不是我們一般工程師想象的那樣,互相有函數調用,有消息通訊就叫關聯(這些只是關聯的一種)。關聯是個哲學的概念,常常出現在語義上的,比如提升速度的要求,導致應用方法的改變,介質層和會話層也有關聯。我們關注某些東西有沒有關聯,我們關注的是在我們討論的那個邏輯角度,我們是否在乎它們的 “共同修改”。

協議分層,就是一種典型的分離關聯的方法。比如 TCP/IP 的網絡(IP)和鏈路(link)層,IP 層只知道 IP 地址,反正我告訴你我要發到這個 IP 地址去,其他東西我一概不知,所以你用令牌環還是 Ethernet 層我的邏輯都是通的(約束是 IP 層接口),無論你是 UDP 還是 TCP 通訊,都和 MAC 地址無關,我也不知道你在傳輸數據的時候需要有一個 Token 在介質上分發。

但丟開這些信息不管,只要你能在 link 層上向我保證每個數據報是無損的(但可丟失),基於這個約束,我就有足夠的 “依賴”(其實就是約束的別名)來建立我的邏輯了,我可以和對端用端口區分應用,可以用滑動窗口來保序來防丟失,可以用特定的原語進行連接建立。這都是看我要把某些約束放在我這一層,還是放在別人那一層。而決定這一點的,是有哪些重疊的約束,我們通過分解多個獨立的邏輯鏈,保證每個邏輯鏈的約束都不多,這樣我們保證這個邏輯鏈的自洽的成本最低。

分層以後,下層多一個 “路由” 的概念,不會改變高層原來那些 “握手”,“鑑權” 這些概念,下層和高層在各自的 “約束” 和“依賴”中可以獨立構成完整的邏輯,而不需要每次都把邏輯細分下去。

架構設計本質是對約束和關聯的控制,讓不同的 “目標” 承載在不同的邏輯上,減少跨邏輯的關聯。比如你當然可以把 “低功耗控制” 這個目標放到 TCP 層,但耗電多少這個約束是在物理層手上的,你要建立這個邏輯鏈,就要從物理層拿到這個約束,TCP 和物理層的 “關聯” 就加重了。

但如果你完全把低功耗放在物理層,TCP 的流被分散在每個 SerDes 鏈路上的,物理層對此無能爲力,它也沒法把功耗降下來。這樣,我們就可能需要一個 Channel 的抽象(我這裏只是比喻,不是現實),讓 IP“僅” 知道合併一些數據流有助於功耗的降低……

這個整個設計過程,脫離具體的具象就架構設計談架構設計,根本沒有結果,我們之所以這樣分解模塊、約束和關聯,完全看我們面對的具體約束是什麼。這裏,起關鍵作用的,是我們的 “目標”,也就是那個“畫人” 的根本約束。除了這個根本約束,其他的約束都是設計者自己引入的。我們要避免作繭自縛,就必須不斷對比這個“目標”,看看什麼真的來自這個“目標”,哪些只是我們圖建邏輯的方便,自己強行引入的。所以,如果你沒有學會其他深入的架構方法,那就保證你學會兩點:

前面說過,我們架構設計的作用,就是降低每個獨立設計邏輯的依賴和難度。而這個難度,就在這裏這個 “邏輯自洽” 上。你基於 IP 這個抽象做 TCP 這個協議,下面到底是 Token Ring 還是 CSMA/CD,你完全不用管,你的邏輯鏈要窮舉所有的可能性就是比較容易的,否則你根本無法保證你的邏輯鏈是嚴密的,因爲要窮舉的可能性太多了。

如果再考慮技術發展(比如現在 SSD 存儲很貴,明年技術進步,整個成本變了呢?),工程師的能力逐步提升,開發階段和銷售階段的要求不同,行業,政策等態勢的變化,你就會發現,做一個 “嚴密” 的邏輯鏈,是非常非常困難的事情。我們只是在降低風險,不是在找一種“必然”,但沒有這種基本的降風險設計,說要做成一個產品,完全是瞎扯蛋。

本節總結:我們要保證一個設計是設計,必須首先保證這兩點:對準目標,邏輯自洽。不能保證這兩點,你的所謂設計就只是夢遊,還不如直接進行形而下的具體設計。而且,這還不僅僅是浪費時間,而是引入無效約束以後,完全限制了整個構架的的發展。

DFD/STD 建模原理

DFD/STD 方法是軟件發展早期,存量約束很少的時代的產物,現在用它的人已經比較少了。我們可以不用,但它包含的原理其實是非常重要的,對於我們建立構架思想,或者在做具體的模塊級的設計仍是必須掌握的基礎能力。

前面說過,構架設計本質上是找到核心約束(目標),然後基於這個目標引入後續的約束。那麼,對於計算機系統,它的核心約束是什麼呢?

答案是:把一種形態的信息,轉化爲另一種形態的信息。

這是計算機作爲一種 “信息系統” 的唯一作用。

除此以外,沒有其他核心的控制要素。

電影編碼一定要 H.264 嗎?一定要 VC-1 嗎?對用戶來說不關心,關鍵是能把視頻數據轉化爲圖像。圖像一定要用電視嗎?一定要用液晶屏嗎?也不是核心約束,你可以再選。唯有把視頻變成看得見的東西,纔是核心約束。

客戶習慣學習用戶的購買信息需要用網絡傳輸嗎?還是直接把硬盤連過來拷貝?還是到了晚上夜深人靜的是時候 InfiniBand 同步?這都是自由度,不自由的是你總得把客戶看過的商品,看了多久,用的 IP 地址或者 ClientID 給我,這我才能從中提出這個興趣出來。

這是 DFD 方法的核心。DFD 方法是從這個角度來設計約束的:用戶要我把什麼轉化爲什麼?我有足夠的數據進行這種轉化嗎?不夠的時候,我從哪裏補上這些數據?這種轉化的邏輯,可以分成多少個獨立的邏輯?這些邏輯可以分別留在哪些層次、模塊裏面獨立管理?

這就會產生 DFD 圖,所有數據邏輯都通了,剩下的邏輯就都是 “我擁有這幾個數據,如何轉化爲他們要的那幾個數據” 的問題了,這整個就是個數學問題。

應該說,我們大部分時候做架構最好的進展,就是能把一個問題變成一個數學問題,因爲這樣這個問題就可以做到最嚴密了。比如下面提到的狀態機問題,就是典型的數據問題提取,如果我們能建立這個模型,基本上我們就不怕有什麼錯了。但真正讓人害怕的是比如指令集,虛擬化這種設計,狀態和條件無數,幾乎就沒有數學方法來完整判斷我們做的是不是就真的沒有破綻了。

而狀態機方法是 DFD 方法之外一個完全獨立的方法。一般用來處理接口破綻的:DFD 建模完成後,你就要設計外部接口,而外部接口是否可靠呢?你只分析了你這樣提供功能是可以給用戶返回正確的結果的?但是否有情形導致你的輸出是不對的?用 STD 方法你可以窮舉所有可能的輸入和你當時所處的狀態,這樣你對你的邏輯鏈是否有效就比較有把握了。

DFD 和 STD 是脫離所有進一步 “自由” 之外的核心約束。它和你用什麼語言啦,怎麼分模塊啦,接口是消息還是調用啦,這些人爲約束沒有任何關係,你愛怎麼設計就怎麼設計。

這種在現在這個 “後軟件時代” 是不太合適的,現在的軟件太完善了,你決定選擇用 MySQL 來存數據,你就得接受用一個 X Protocol 來連接它,選定了 X Protocol,你就要選語言,就得選 OS 平臺,然後你的輸入就得滿足關係數據庫來描述你的持久化數據…… 在系統層面,現在你的依賴都是成片成片的。這個時候,你還紙上談兵地說 “我的核心依賴是……” 就很假了,你的物理依賴其實一開始就已經被決定了,這時自由度更高的 4+1 視圖方法就更容易被接受了。

但即使我們有 4+1 視圖方法,我們仍有必要好好去學習一下 DFD/STD 方法。因爲這是 4+1 方法的基礎,它仍是我們整個信息系統真正的核心約束的提取方法,比如前面這個問題,MySQL 真的不滿足我們的需要,我們可以換掉 MySQL,換掉關係型數據庫,換掉 OS 的,這是左右我們創新的基礎,4+1 是下一層的方法,它接受了 “人爲約束” 是約束,不考慮打破這個約束,但 DFD 方法是真正在控制一個“期望”(用戶需求)如果被自由設計的時候,可以如何創新,如何改變現在的約束。

4+1 視圖建模原理

4+1 視圖是後軟件時代的產物,就是軟件已經極度豐富了,你隨便做點什麼,都是在已有的軟件的基礎上做的,而且常常你還不能一次想好怎麼做,都是見一步,走一步的。這需要另一種控制架構的方法。

4+1 視圖是把最關鍵 4 個全局控制拿出來,然後一個功能,一個功能拿上去推演,看約束和邏輯會不會衝突。所以它不叫 “五大視圖”,因爲 Use Case 不算一個完整的邏輯。Use Case 只是一個持續補充的,不完整的“需求列表”。我們用這些單個的需求去試試,我們的引入的設計邏輯,是否是可以完整自洽的。這個“完整自洽” 是要落實在另外那四個視圖上的。

4 大視圖在關注設計的哪些方面呢?首先,邏輯視圖,我又把它稱爲概念空間建模,這其實關注的是用戶接口。所以我有個建議:如果你的邏輯抽象能力不那麼強,就先別去學那麼多複雜的方法,你直接試試寫用戶手冊。

你想辦法用真心服務客戶的態度,給使用者說明怎麼用你這個系統。真心服務客戶的態度不是讓你學電商那些機器人一樣的客服,態度一流,就是不給你解決問題。真心服務客戶是把客戶當戰友,戰友的陣地守不住,你也一樣死。這樣你纔會深怕他聽不懂,而不是故意用你那些專業術語在他面前裝逼。

概念空間建模很多時候不需要詳細到用戶手冊這個層次,比如我這裏這個文檔也是概念空間建模:https://zhuanlan.zhihu.com/p/150489110

我重點抓住的是一個異構的程序在原來 Linux 對同構的程序在進程線程管理,內存佔用,異常和中斷處理,調試等問題上是否還有原來的意思。這如果你還分不出哪些概念纔是左右發展的,那些是細節,那麼用戶手冊是最容易實施的控制概念空間的方法。

你要介紹一個數據庫,什麼是用戶,密碼,連接,數據庫,表,行,列,條件,index…… 你自然是要說清楚的,這個東西不通,你的代碼怎麼可能可以通?

你要介紹一個加速器,什麼是設備,虛擬設備,上下文,通道,引擎,請求,響應,同步,異步…… 這些你不用心說清楚,你怎麼可能說得明白請求你一個虛擬設備復位,會影響多少個應用程序?

這個設計是躲不過去的。如果你這個邏輯沒有說清楚,直接就做設備初始化,軟件上下文分配,中斷處理,等你把這些功能都細化起來,你跟我說你能保證邏輯不衝突?你開玩笑吧?

第二個我們關注的視圖是開發視圖,這是開發和維護的組織。最基礎的一個模型是部件分解。前幾天我評審了一個硬件設計,要求在總線上設計一個 “地址分配器”,我問,你這個分配器工作在哪裏?他說,可以在總線交換機上,也可以在其中一個服務器上。

我就說,這就是兩個交付了:在總線交換機上,這你要求總線交換機有一個 CPU,可以跑這個程序,這個系統的 OS 應該是 RTOS,我們就要做 RTOS 的選型,這個分配器必須和這個 RTOS 綁定升級,而在每個節點上那個,必須是一個節點應用,很可能是一個服務器 OS 的 Daemon 或者內核模塊。後者我們有自由度可以頻繁升級,前者不行。兩個都支持就要用短板做約束,這個地址分配算法必須相對穩定…… 開發視圖就是抓這種邏輯的。

但部件分配僅僅是開發視圖最容易的部分。現代大型商業軟件這個部分最難的是這些部件的升級和組合關係:一個系統包含多個部件,把維護時間拉長到幾年,每個部件都會發生升級,升級以後是否可以互相匹配?版本數量減少,用戶升級自由度降低,版本數量增加,維護成本大力增加,修改一個 Bug,要測試 120 種可能組合,每個測試先要加載 12 個小時網絡才能運行起來,你怎麼玩?

這個問題常常是我在架構設計中工作量最大的部分,很多架構師碰到這個問題就退了,就開始 “抽象” 了,忽略版本,用一條虛僞的線和抽象的框框來代表這些變體,實際情形就是到時誰要得急就做誰的,等到最後展開無數組合的時候發現搞不定了,就只能解釋 “就是這樣的” 了。所以你看到很多產品只能撐住 POC,爲了性能可以換個 kernel,換個編譯器,換個庫,“性能提升 30%,支持 A 功能,B 功能……”,其實這種市場轉眼就會丟失,根本沒法維護。覆盤的時候說:“都是因爲用戶不肯用我某個版本……”,扯吧,你整個交付邏輯就不通。

比如這種:

這種圖形是市場部用來和小白客戶溝通的,你拿來當 “設計”?你設計什麼了?爲了讓市場人員可以吹這個牛,架構師是要把所有可能的版本組合全部推演出來,變成開發部的工作量的。市場吹一句話,是開發部幾百人月的投入,你架構師也他麼只吹一句話?那怎麼可能可以處理這些組合呢?結果肯定是隻能有一個組合可以用,其他組合都純 YY 麼。

這種把市場吹的分層邏輯,變成一組版本和版本直接的配套關係,就是開發視圖要解決的關鍵問題。

第三個視圖是處理視圖。這個模型一般用來分析並行化,一個業務邏輯,有些邏輯是必然串行的,你加 CPU,加節點,加加速器是沒有用的。這種東西,你總得合併在一個流中。還有些業務不是這樣的,你如何分解邏輯?哪部分分解到什麼節點上?

這是個純算法問題,我這裏倒沒有什麼可以補充的。但可以看到,它其實也是一個比較核心的抽象邏輯,和需求強相關,受人爲引入約束的關係也是比較有限的(當然沒有 DFD 那種約束那麼硬,因爲它不是個功能問題,而是個性能問題)

這個視圖一般沒有什麼工具,我自己做出來大部分時候都是 ER 圖(ER 圖其實可以畫成對象圖的)和大批的文字說明。

最後一個視圖是部署視圖。我個人對這個視圖用得不多,因爲一般前面三個模型已經完全限制這個視圖的選擇了,這其實沒有設計的必要。當然,這完全看你進程做的是什麼設計,對於比如 “數據中心建設” 這樣設計來說,部署視圖的價值就會大於開發視圖。

可以看到,4+1 視圖方法其實是一種學術上不那麼嚴格的實用方法,但它卻是我們進行一個大型系統需要考慮問題的最基本約束考量。否則,想想你可以如何規整和邏輯完整地考量你一個設計到底缺少了哪一環?怎麼能確定你的系統可以持續用下去?

對於每個具體的設計,可以你會使用其中一部分視圖,或者你會引入其他視圖,比如可靠性設計,安全性設計,這些都需要額外的視圖來表達的。視圖本質是一個獨立的角度,保證我們最開始要解決的問題:某些問題,一開始進入細節,我們必然會走偏,會留下巨大的破綻(安全性是最典型的情況)。

總結

架構的目的是在混沌中製造規律,使我們可以控制龐大複雜的系統,自然發展的東西總是混沌而沒有規律的,好比一個樹林,肯定是看不到一點平地的,而人控制自然,就會磨平這種複雜性,會製造平直的地面,見方見圓的房子,這樣人的腦子可以對它們有很簡單的預期。簡單是設計的目的,複雜是 “專業” 的無可奈何。這時很多從設計進入架構的工程師意識不到的問題。

在本文中,我們初步爲讀者點出架構設計的關注重點是什麼,這一點我認爲比掌握一些具體的工具使用方法重要得多。作爲形而上的設計,方向錯了,完全起的就是反作用。我希望通過本文,能讓更多的工程師感受到架構設計的重要性,在進行設計的時候,總從架構的角度做一些建模。

如果你實在覺得頭緒太多,那就從用戶手冊開始,至少先抽象出來,你在一個什麼上下文中中,對外的依賴是什麼,你提供了什麼功能…… 你看到了整體,你才能看得到你的細節,否則你總在你的細節中出不來,這終究是走不遠的。

這個前提,首先其實你是的心確實是在這個設計上,而不是給你的同事,領導 “證明” 你不差,你很厲害,不是你的錯誤,你沒有功勞也有苦勞…… 這些小聰明,能幫你一時,終究不能幫你做成真正的難事。人生苦短,去日苦多,你終究會後悔的。

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/HCXYyjf6IhqDBw9HMJjUzw