什么樣的軟件架構(gòu)是好的?
- “All models are wrong, some models are useful” ——George Box
沒有放之四海皆準的好與壞的標準。下面我對于衡量軟件架構(gòu)好壞的AAA原則:
- 可考核(Accountable):好的軟件架構(gòu)讓每個團隊都有自己負責(zé)的業(yè)務(wù)目標
- 可自主(Autonomous):好的軟件架構(gòu)讓每個團隊都一定的自主性可以獨立往前跑,而不總是被其他團隊阻塞
- 可復(fù)用(Amortized):好的軟件架構(gòu)鼓勵對未來投資,使得基礎(chǔ)設(shè)施的成本可以被攤銷
可考核>>可自主>可復(fù)用。在上世紀90年代,代碼復(fù)用是面向?qū)ο笊鐓^(qū)的熱門話題。然后SOA和DDD又來告訴我們“可自主”才是最重要的。但是我發(fā)現(xiàn)實踐中,無論是“可自主”還是“可復(fù)用”都很模棱兩可。很難用這兩個原則去說服其他人,用X的方式來分解問題會比用Y的方式來分解問題更好。但是如果你說,這么分解可以讓每個團隊更可考核,就顯得特別理所當(dāng)然。
開發(fā)者無法估算工作量
“可考核性”是一切的關(guān)鍵。我認為“缺乏可考核性”是現(xiàn)在的軟件開發(fā)模式***的危機,這個問題比”無法管理所謂的復(fù)雜性“還要更嚴重。
開發(fā)者是無法估算工作量在行業(yè)里也不算什么秘密了。這帶來了很多根本性問題:
因為我們無法知道真正多少人才是必須的,所以中層管理總是比著招聘人頭上限,盡可能的加人。為什么會這樣做?很簡單,他們的薪酬和他們所管理的人頭數(shù)是成正比的。
把軟件重構(gòu)得”更可維護“沒有商業(yè)價值。什么叫可維護性?問題如果解決不了,扔更多的人進去總是可以解決的。軟件工程又不是造火箭,能有多難?根本無法證明重構(gòu)可以節(jié)省多少人力,因為就沒有可對標的重構(gòu)前的應(yīng)投入人力。
要解決這個問題,我認為不是去搞明白開發(fā)工作量的評估的魔法。恰恰相反,如果我們和業(yè)務(wù)負責(zé)人是以同一個團隊的方式來工作,我們就壓根不需要去估算工作量。每個軟件開發(fā)團隊都有應(yīng)該有“唯一的一個”對應(yīng)的業(yè)務(wù)團隊,業(yè)務(wù)團隊背什么樣的OKR,技術(shù)團隊就背什么樣的OKR。要讓團隊可考核,最重要的是只對一個業(yè)務(wù)負責(zé)。
上面是一個典型的組織架構(gòu)圖。每個小團隊的OKR,要和其上一級團隊的OKR對齊。OKR里面的關(guān)鍵產(chǎn)出要是可度量的,才能讓每個團隊真正對某個事情負責(zé)。
典型的壞的軟件架構(gòu)是這樣的:有大量的微服務(wù)團隊。業(yè)務(wù)負責(zé)人總是需要直接去找多個微服務(wù)團隊才能達成他的目標。每個需求都需要和多個不同的軟件團隊重復(fù)溝通。每個技術(shù)團隊都沒法清楚地說明白他們以及他們的微服務(wù)負責(zé)的業(yè)務(wù)目標是什么。正因為如此,技術(shù)們無法說清楚自己對業(yè)務(wù)到底有什么價值。
讓我們再強調(diào)一遍:軟件架構(gòu)的“頭號目標”應(yīng)該是讓每個分解出來的團隊都能夠有業(yè)務(wù)目標去負責(zé)。
Bounded Context
在大的尺度上,架構(gòu)就是分解Bounded Contexts(參見領(lǐng)域驅(qū)動開發(fā),DDD)。這就是把業(yè)務(wù)的組織架構(gòu)圖體現(xiàn)到軟件的世界里:
以電商領(lǐng)域為例,業(yè)務(wù)被分解為上面這些Bounded Contexts。沒有一個技術(shù)團隊可以覆蓋橫跨這些Bounded Contexts的業(yè)務(wù)流程的。這并不是啥壞事情,大的問題被分解為了小問題,業(yè)務(wù)和技術(shù)在一個Bounded Context的范圍內(nèi),攜手朝著共同的目標去努力。
虛擬空間和智慧體
一個Bounded Context對于一個團隊來說仍然太大了。至少在微服務(wù)的心智下是這么認為的。如何把它進一步分解為更可管理的小塊呢?我的模型是“虛擬空間和智慧體”。我們做為程序員所做的事情,簡單來說就兩個:
虛擬空間
有點智慧的“機器人”和我們?nèi)祟愐黄鹪谔摂M空間里交互
虛擬空間和我們?nèi)馍硭幍奈锢砜臻g是一樣的,它都是構(gòu)建在因果關(guān)系上的。有兩種法則主導(dǎo)這些因果:
- 自然法則:大自然自身的內(nèi)在規(guī)律
- 社會法則:一個人造的體系,人們通過模仿自然法則創(chuàng)造出類似穩(wěn)定的規(guī)則系統(tǒng)去構(gòu)建穩(wěn)定的社會秩序
比如引力是自然法則。而“借錢要還”是社會法則。兩者的工作方式是類似的,給定某些前因,根據(jù)法則,就必須有某些后果。我們使用C/C++/Java/GO/……等來描述這些法則。從光線跟蹤算法到word文本編輯器到電商交易平臺,從構(gòu)建規(guī)則的角度來說是差不多的。“法則”必須是靜態(tài)的可預(yù)測的,就像用水泥構(gòu)建了我們的真實世界一樣。
在我們構(gòu)建的虛擬空間智商,我們作為人類彼此之間進行交互,例如社交網(wǎng)絡(luò)和交易。由人類扮演的角色正逐步被我們縮寫的人工智能的"機器人”所替代。例如,之前是人工的編輯去挑選內(nèi)容,現(xiàn)在可能是機器人來產(chǎn)生新聞,給你準備每天開屏的首頁。“機器人"正變得越來越復(fù)雜,某天他們會從虛擬空間里出來,直接走向物理空間。
“虛擬空間”和“機器人”這兩種軟件代碼的工作方式差異性是很大的。“虛擬空間”從原因推導(dǎo)出結(jié)果,來維護自然和社會的秩序。“機器人”的工作方式是相反的,它收集事實反推出模型來***化其目標。把智能的部分和系統(tǒng)的其他部分明確地區(qū)分出來至關(guān)重要。我們作為人類希望規(guī)則是靜態(tài)的從而構(gòu)建出穩(wěn)定的預(yù)期。如果“法則”總是不斷在變,“虛擬空間”看起來就像是“魔法空間”,它就變得和我們從真實空間獲得的生活體驗很不一樣了。
軟件開發(fā)中的Model,View,Controller(MVC)的概念可以用來解釋“虛擬空間”。人類和“機器人”是所謂的智慧體。Model根據(jù)自然和社會法則定義的因果去維護數(shù)據(jù)的完整性。View和Controller提供了便捷的接口給人類和“機器人”去交互。
所有權(quán)==著作權(quán)
“虛擬空間”這部分仍然太大了。業(yè)務(wù)流程可能會有很多個步驟,例如:
而且不同的Bounded Context的業(yè)務(wù)流程之間也是有集成關(guān)系的:
可考核性問題的根源是編程語言里缺乏對完整因果鏈的直接描述能力。我們可以在白板上畫一個清楚的業(yè)務(wù)流程圖,但是在寫代碼的時候就不需要切分成很多細碎的服務(wù)和函數(shù)來表達。之所以工作流引擎總是被拿出來考慮,因為它的描述能力和要解決的問題有良好的映射。但是BPMN并不是一種編程語言。
步驟與步驟之間有很強的因果關(guān)系。在產(chǎn)品詳情頁展示的促銷,也應(yīng)該體現(xiàn)在購物車里,也應(yīng)該體現(xiàn)在收銀頁面上,也應(yīng)該體現(xiàn)在最終的收據(jù)里。我們使用的“function”的概念,頂多只能用來描述500ms內(nèi)發(fā)生的事情的因果關(guān)系。對于前面所述的業(yè)務(wù)流程,我們切分成了很多個步驟,同時又按照使用方的不同,切成成了很多個面向用戶的服務(wù)。從而因果關(guān)系就被隱藏在這些龐雜的實現(xiàn)細節(jié)之中了。軟件跑起來就像一場接力賽,一個服務(wù)把職責(zé)接過來,搞一搞之后,又傳遞給另外一個服務(wù)。理想的情況是,代碼本身就應(yīng)該體現(xiàn)流程圖,讀起來就像流程圖。
更糟糕的是,現(xiàn)在的切分方式并沒有明確的劃線的原則。這就頻繁導(dǎo)致了團隊之間關(guān)于誰應(yīng)該負責(zé)什么的爭論。高度政治化的組織氛圍導(dǎo)致了開發(fā)者情緒上的沮喪。同時,具有諷刺意味的是,在大家彼此搶活的同時,又因為職責(zé)切分得太碎,導(dǎo)致又沒有一個團隊能夠?qū)θ重撠?zé)。
對于解決這個問題,目前能夠做到的“***實踐”就是在一堆微服務(wù)團隊上架一個門面團隊。“所有權(quán)==著作權(quán)”,我們只愿意對自己所寫的東西負責(zé)。這個人性,無法改變。為了給這些可憐的家伙具有所有權(quán)的感覺,我們必須允許一層很薄的代理層,或者叫所謂的調(diào)度服務(wù)來把微服務(wù)給“屏蔽"在后面。但是這種代理一層的做法經(jīng)常導(dǎo)致了很低的團隊自主性。
理想的編程語言,應(yīng)該能夠提供“function”一樣的東西去直接描述業(yè)務(wù)流程。業(yè)務(wù)上的同時行進的并發(fā)流程應(yīng)該可以像多線程編程一樣,用消息傳遞的方式來描述。這樣,我們可以給每一個可切分出來的業(yè)務(wù)流,分配一個獨立的軟件團隊去端到端負責(zé)。他們可以對自己負責(zé)的事情100%負責(zé)。這些人和業(yè)務(wù)運營人員,以及編寫出來的“機器人”合在一起作為同一個團隊,共同負責(zé)這個業(yè)務(wù)流的收益和虧損。而不是單獨把技術(shù)摘出來,成為一個共享的成本中心。
協(xié)作單元
除此之外,還有一個事情是有問題的。之前由編程語言提供的模塊化單元,例如assembly/package/class這些,就是我們團隊之間彼此協(xié)作的單元。然而現(xiàn)在不是這樣了。現(xiàn)在越來越多的人,要求軟件模塊有獨立版本,能夠獨立的部署。因為這樣才能支持多個團隊的獨立性。這就導(dǎo)致了大量的微服務(wù)的做法。
但是我們是否“總是”需要用不同的編程語言不同的工具來實現(xiàn)微服務(wù)?語言的差異和彼此割裂的工具導(dǎo)致跨團隊溝通更加困難。你可以擁有你的流程,擁有你的服務(wù),但是這不阻礙你和你的伙伴們用同一門語言啊。一門編程同時扮演了3個角色:它連接了機器,它連接了開發(fā)者,它同時又連接了團隊。今天編程語言更多是僅僅作為一種連接機器和開發(fā)者個體之間的工具,團隊之間宏觀上是彼此割裂的。
解決方案應(yīng)該是把軟件作為一個整體來思考,而不是被狹隘的“操作系統(tǒng)進程”的視角給限制了。構(gòu)建新的微服務(wù)的成本,應(yīng)該和后臺用function啟動一個線程沒有多大區(qū)別。理想的編程語言里,我們有各種各樣的function,但是執(zhí)行機制不同。