軟件和組織架構(gòu)的一致性
先做一個小結(jié),軟件面臨的核心問題是功能擴展時的成本(人力、時間、故障等綜合考慮)。解決的基本思路,其一、引入各種軟件設(shè)計方法來管理復(fù)雜性,過程大體上都可以視為基于抽象的拆分和組合; 其二、分解職責(zé)到不同的人,定義明確的邊界和運作方式,以獲得分工的效率。
正如康威定理指出的,軟件架構(gòu)決定組織架構(gòu)。軟件的復(fù)雜性管理方式和人員職責(zé)拆分及組織架構(gòu)應(yīng)該是同構(gòu)的。換言之,要么組織混亂、多頭管理、大部分人力都是同時進(jìn)行多個任務(wù),同時代碼亂成一團(tuán)。要么組織結(jié)構(gòu)清晰,任務(wù)優(yōu)先級明確,大部分人專注于-兩件事,同時代碼質(zhì)量也還說得過去。不太可能出現(xiàn)一好一壞。其中,軟件架構(gòu)是決定性因素,這是任何研發(fā)組織和官僚組織最核心的區(qū)別。(這里沒有貶低官僚組織的意思,研發(fā)組織和官僚組織的目標(biāo)不同,所以解決方案也不會相同)
基于模型、分層的軟件架構(gòu)
(下述討論,不包括模塊化\組件化、組件間接口管理等問題。這些問題的直接體現(xiàn)業(yè)務(wù)本質(zhì),它們也是架構(gòu)設(shè)計的部分,也有一些拆分的原則,比如業(yè)務(wù)內(nèi)聚,相似的過程、依賴相同的數(shù)據(jù),邊界清晰等等,但不是本文討論的核心。)
什么情況可以不考慮軟件設(shè)計?系統(tǒng)足夠簡單并且看起來不會變得復(fù)雜;已經(jīng)有了針對這個領(lǐng)域的好用的框架和語言。也就是說,要么這個問題太簡單不值得解決,要么這個問題已經(jīng)有了通解,否則就需要考慮設(shè)計問題。
如果一個復(fù)雜系統(tǒng)又使用相對低級(缺乏抽象機制,如C)的語言——通常是某些大型嵌入式系統(tǒng), 異常注重性能硬件資源又沒法擴展——那么設(shè)計問題就會便得生死攸關(guān)。架構(gòu)是頂層設(shè)計,它是業(yè)務(wù)(領(lǐng)域)復(fù)雜性的高度抽象,提供系統(tǒng)拆分和組合的基本方法,并提供機制以使得其他設(shè)計問題可以延遲決策(最后一點是讀<clcanarchitecture>--書想到的,蠻有意思)。
架構(gòu)設(shè)計,第一步做架構(gòu)級建模。
定義系統(tǒng)包含哪些聚合根(哪些核心的實體?)、聚合根之間的關(guān)系,以及哪些東西應(yīng)該作為核心概念顯式的體現(xiàn)在聚合根上。要避免聚合根關(guān)系復(fù)雜化,網(wǎng)狀化,否則系統(tǒng)從起點就已經(jīng)難以維護(hù)了。核心概念實際上是提供給后續(xù)設(shè)計做拆分的尺規(guī)。依據(jù)單一 職責(zé)原則做具體考量時,不同的角色(架構(gòu),業(yè)務(wù)分析,開發(fā)),不同的人之間理解往往相去萬里乃至雞同鴨講。而核心概念就是要提供基本的共識,它們往往是系統(tǒng)的痛點所在,是降解系統(tǒng)復(fù)雜度的樞紐。比如如果一個系統(tǒng)有非常豐富的狀態(tài),且復(fù)雜的依據(jù)狀態(tài)擇路的代碼導(dǎo)致系統(tǒng)難以維護(hù),那么“狀態(tài)”就應(yīng)該抽取出來,作為核心概念顯式的聚合在聚合根上。狀態(tài)可以作為單一職責(zé)的一個標(biāo)準(zhǔn)。比如一個抽象行為有多個實現(xiàn),每個實現(xiàn)只應(yīng)該給為狀態(tài)的一個值服務(wù)。
下來應(yīng)該做分層設(shè)計。
典型的Evans給出一個四層模型, 基礎(chǔ)設(shè)施層,領(lǐng)域?qū)?,?yīng)用層,用戶界面層。基礎(chǔ)設(shè)施必須有,沒有就會重復(fù)造輪子,一個造得比一個崎嶇;有了基礎(chǔ)設(shè)施則需要部署某些控制點,避免團(tuán)隊自行開發(fā)已有的工具。領(lǐng)域?qū)影瑯I(yè)務(wù)的核心知識。應(yīng)用層是關(guān)于領(lǐng)域知識的組合,定義軟件功能,提供具體的服務(wù)。但要分析關(guān)于領(lǐng)域知識的組合是否也是核心的領(lǐng)域知識?如果是的話,領(lǐng)域?qū)涌梢钥紤]分成多個子層,畢竟處理組合和般性的業(yè)務(wù)知識會采用不同的策略。
系統(tǒng)已經(jīng)從聚合根、核心概念(縱向)和分層(橫向)兩個方向拆分完畢了,圖紙已經(jīng)畫好。如何保證按圖索驥就成了問題的關(guān)鍵。靠提升人員能力、價值觀宣貫、編碼規(guī)范、培訓(xùn)、走查、結(jié)對編程...這些都不夠。既不明確,也不穩(wěn)定。
架構(gòu)落地由DSL切入
還是從軟件/架構(gòu)設(shè)計落地 和 人員職責(zé)定義兩個方向考慮。
支持軟件設(shè)計落地。
DSL的語法元素中,應(yīng)該包括架構(gòu)建模中的聚合根和核心概念,并定義它們之間可能的組織和交互形式。這樣系統(tǒng)既能顯式的拆分到我們期望的基本粒度,又能有一致的組合方式,一致很重要。
有時DSL并不會完整的實現(xiàn)系統(tǒng),而只是定義框架中的元素和組織形式,具體的實現(xiàn)形式并不關(guān)心,DSL會生成一組接口來約束需要用宿主語言具體實現(xiàn)的部分,接口的職責(zé)和形式已經(jīng)是明確的了。這意味著分層結(jié)構(gòu)將中有一層與這部分職責(zé)對應(yīng)。好吧,我說的就是涉及復(fù)雜組合的那部分。
可以看出,DSL是一個非常具體的切入點,當(dāng)采取這套方法后,我們已經(jīng)抽象出來的概念和拆分的粒度會被形式化。而不會受個人(或組織)的偏好影響,乃至最終腐化到渣都不剩。而采用DSL后,架構(gòu)的意圖,如我佛所言,所得正覺(架構(gòu)知識),如沙中煉金,一旦煉出,永不復(fù)歸于沙。
人員職責(zé)劃分
至少架構(gòu)師、業(yè)務(wù)分析師(BA)、開發(fā)基于DSL可以各司其職了。
架構(gòu)師的職責(zé)在系統(tǒng)建模、分層之外,增加DSL設(shè)計和維護(hù)的職責(zé),他交出的成果不再只有文檔和PPT,而是具有更強約束性和規(guī)定性的DSL語法。
BA用DSL來描述業(yè)務(wù),他可以輸出DSL文件,這樣對開發(fā)的約束是明確的,成果可以固化,而且BA的意圖更難被扭曲。
開發(fā)依據(jù)DSL生成的接口填空。
會增加一個新的角色,轉(zhuǎn)換器(編譯器)開發(fā)者,無論內(nèi)部或外部DSL,這個職責(zé)都是需要的,原則上架構(gòu)師可以承擔(dān)這個責(zé)任畢竟他最清楚語法的意圖,但很可能一個人做不完。
DSL的其他好處包括
在DSL可以描述的范圍內(nèi)大幅提高開發(fā)效率;
統(tǒng)一風(fēng)格(減少編程實現(xiàn)模式層面選擇困難);
處理性能的非業(yè)務(wù)優(yōu)化(代碼實現(xiàn)方式和內(nèi)存排布導(dǎo)致的優(yōu)化可以由轉(zhuǎn)換器完成);
可以在轉(zhuǎn)換器內(nèi)嵌很多檢查項,保證代碼本身的一致性,而不必要做運行時檢查。
可以想象,在轉(zhuǎn)換器身上能做的文章非常多,規(guī)模越大,這個好處就越明顯。