分塊云計(jì)算簡(jiǎn)介
這篇文章沒有什么新奇觀點(diǎn),只是將我的思考與觀察做一個(gè)概括。
多年忽視分塊
即使過了16年,我依然清楚記得[Booch OOAD]書中討論如何使用分層與分塊(有的讀者可能更偏好"模塊"這個(gè)同義詞)。那時(shí)候我開班講授一門面向?qū)ο蠓治雠c設(shè)計(jì)的課程,這本書是教材。我感覺討論分層很容易,因?yàn)楫?dāng)時(shí)接觸甚多(后來仍然深受影響,下一節(jié)會(huì)談及),但要討論分塊就有點(diǎn)難。
在我參與的實(shí)際項(xiàng)目中,我們確實(shí)一直采取分塊的做法,但講授的時(shí)候很難用短小的例子示范分塊。而且就我記憶所及,我們采取分塊只是出于技術(shù)上的限制,并不像分層那樣是自然而然地發(fā)生的。.
分塊沒能“物盡其用”的感覺一直伴隨著我,我也就聽之任之。
濫用分層
2001年寫第一本書[Nilsson NED]的時(shí)候,我對(duì)分層的盲目溺愛到達(dá)頂峰。圖1的分層示意圖已經(jīng)是簡(jiǎn)化過的版本。
圖1. 過去的典型分層(簡(jiǎn)化版本)
圖1可見,中間層包括了Fa?ade層、業(yè)務(wù)邏輯層和數(shù)據(jù)訪問層。在數(shù)據(jù)層還有公共存儲(chǔ)過程(sproc)層、私有存儲(chǔ)過程層,有時(shí)候數(shù)據(jù)表之上還有視圖層……(UI部分也是分層的,可想而知……)。
我把這種分層方案稱為我的“默認(rèn)架構(gòu)”,顧名思義,我每次著手新項(xiàng)目都以此作為出發(fā)點(diǎn)。當(dāng)然具體的架構(gòu)形態(tài)隨著時(shí)間會(huì)有所變化,但重點(diǎn)是我先入為主地認(rèn)為項(xiàng)目都離不開這種嚴(yán)格的分層方案?!∪绱艘粊?,我不用再拘泥嚴(yán)格的分層方案,轉(zhuǎn)而把精力集中于尋找恰當(dāng)?shù)姆謮K。又由于整個(gè)解決方案被分為若干小塊,從而每一個(gè)分塊的分層形式可以更加靈活,因?yàn)橐?guī)模更小了。
按技術(shù)拆分團(tuán)隊(duì)
寫上面一節(jié)的時(shí)候,我想起了2005年在挪威Lillehammer舉行的軟件架構(gòu)研討會(huì)[Fowler LayeringPrinciples]。當(dāng)時(shí)我們?cè)跁?huì)上討論如何把大的團(tuán)隊(duì)拆分成若干小團(tuán)隊(duì)。
無論那次會(huì)議之前或之后,我都有拆分團(tuán)隊(duì)的經(jīng)驗(yàn),多次拆分中既有按技術(shù)拆分的,也有按功能拆分的。我尤其記得一個(gè)項(xiàng)目,對(duì)其中一名團(tuán)隊(duì)成員來說,按功能拆分是失敗的,因?yàn)樗麤]有什么經(jīng)驗(yàn),所以幾乎每一個(gè)方面他都不得不苦苦掙扎。.
在另一個(gè)項(xiàng)目中,按技術(shù)拆分看起來非常成功,不過那個(gè)項(xiàng)目的成員都很有經(jīng)驗(yàn)。即使在這個(gè)成功項(xiàng)目里,也有很多情況如果按功能拆分會(huì)取得更高的效率。比如跨單元的小改動(dòng),牽涉到的人可以更少。
總而言之,我偏向按功能拆分團(tuán)隊(duì)。每個(gè)人肯定有自己特別擅長(zhǎng)的部分,但如果不用協(xié)調(diào)及等待其他人完成相應(yīng)的工作,那么大部分工作都可以更快地完成。
企業(yè)領(lǐng)域模型
前些年很流行建立整個(gè)企業(yè)“一統(tǒng)天下”的數(shù)據(jù)模型。背后的想法是如果一朝找到并描述出這樣的數(shù)據(jù)模型,就能從中創(chuàng)造出巨大的業(yè)務(wù)價(jià)值。于是傳達(dá)給業(yè)務(wù)人員的是這樣的信息:
“現(xiàn)在給我們兩年時(shí)間不受干擾,到時(shí)候我們會(huì)交給你一個(gè)定義好的模型,你想要的一切都能不費(fèi)吹灰之力就創(chuàng)造出來?!?/P>
依我之見,“企業(yè)數(shù)據(jù)模型”是大大失敗了。原因肯定不少,但下面這幾點(diǎn)可能在最重要之列:
即便是中等規(guī)模的企業(yè),數(shù)據(jù)模型的規(guī)模也過于龐大。
數(shù)據(jù)模型試圖用靜態(tài)的方法描繪一個(gè)動(dòng)態(tài)的目標(biāo)。而且描繪一個(gè)龐大的目標(biāo)比小的目標(biāo)要困難得多。 大模型或多或少要作一般化的處理,并因此失去上下文信息。
我個(gè)人強(qiáng)烈相信大的任務(wù)要一口一口地啃,而上下文是王道。
A前面說過,我認(rèn)為建立企業(yè)數(shù)據(jù)模型的嘗試常常以失敗告終?,F(xiàn)在我又發(fā)現(xiàn)一種有點(diǎn)諷刺的情形——還有項(xiàng)目幾乎在重復(fù)同樣的嘗試,只不過這一次換成了“企業(yè)領(lǐng)域模型”。論據(jù)沒變,我想結(jié)果和造成結(jié)果的原因也不會(huì)變……
公平來說,更常見的情況倒不是真的追逐“企業(yè)領(lǐng)域模型”,而是想建立單一的大型領(lǐng)域模型。此外,團(tuán)隊(duì)不時(shí)發(fā)現(xiàn)有需要切分大的領(lǐng)域模型,但又發(fā)現(xiàn)不容易找到滿意的方案。
無論如何,我都強(qiáng)烈建議當(dāng)領(lǐng)域模型出現(xiàn)增大跡象的時(shí)候,將它分塊。還有別忘了模型是有上下文的。
很有趣,我還聽聞一些非常大的SOA項(xiàng)目采取的第一個(gè)步驟就是打算建立一套“企業(yè)文檔模型”。它會(huì)比企業(yè)數(shù)據(jù)/領(lǐng)域模型更成功嗎?要是打賭的話,我寧愿下注在另一邊。
整合數(shù)據(jù)庫(kù)
就算有意避免巨型的單一領(lǐng)域模型,把模型隔離成幾個(gè)部分,每一個(gè)部分還是有可能膨脹到相當(dāng)規(guī)模。發(fā)生這種情況的時(shí)候,往往會(huì)發(fā)現(xiàn)數(shù)據(jù)庫(kù)并沒有分塊。各個(gè)領(lǐng)域模型置于同一個(gè)數(shù)據(jù)庫(kù)之上,也就是共用一個(gè)整合的數(shù)據(jù)庫(kù),見圖3。
圖3. 分塊的領(lǐng)域模型,使用整合數(shù)據(jù)庫(kù)
把多個(gè)領(lǐng)域模型置于單一數(shù)據(jù)庫(kù)之上,只是整合數(shù)據(jù)庫(kù)的其中一種情形。實(shí)際上跟多個(gè)獨(dú)立應(yīng)用共享同一個(gè)數(shù)據(jù)庫(kù)是一樣的。類似情況可謂屢見不鮮。
很不幸這樣的安排給維護(hù)造成了極大的負(fù)擔(dān)。任何影響到數(shù)據(jù)庫(kù)Schema的改動(dòng)都必須同步修改相應(yīng)Schema的所有消費(fèi)者。消費(fèi)者越多,情況越糟。往往造成改動(dòng)被限制到最低程度,很可能進(jìn)而導(dǎo)致從代碼中榨取的業(yè)務(wù)價(jià)值大大減少。
大膽地說一句,如今在我眼中,整合數(shù)據(jù)庫(kù)是一種反模式。啊,總算說出來了,感覺真好。
那么,有什么別的辦法呢?我認(rèn)為領(lǐng)域模型的分塊應(yīng)該一直延續(xù)到數(shù)據(jù)庫(kù),讓數(shù)據(jù)庫(kù)也遵循同樣的分塊方案。這種與整合數(shù)據(jù)庫(kù)[Fowler IntegrationDatabase]相反的模式稱為單應(yīng)用數(shù)據(jù)庫(kù)[Fowler ApplicationDatabase],見圖4。
圖4. 分塊的領(lǐng)域模型,使用各自的單應(yīng)用數(shù)據(jù)庫(kù)
分塊之間的通信是通過領(lǐng)域模型之上的服務(wù)完成的,不允許抄捷徑直接訪問其他領(lǐng)域模型的應(yīng)用數(shù)據(jù)庫(kù)。這意味著可以(也通常會(huì))有效地將不同的應(yīng)用數(shù)據(jù)庫(kù)部署到不同的服務(wù)器上(或者部署到云中)。
一般認(rèn)為報(bào)表是整合數(shù)據(jù)庫(kù)的優(yōu)勢(shì)所在。要是換一種方式去處理報(bào)表,可以把它看成一個(gè)獨(dú)立的應(yīng)用,有著自己的數(shù)據(jù)存儲(chǔ)。數(shù)據(jù)從其他分塊搜集而來。其中一種辦法是將每個(gè)分塊都看作一個(gè)提供事件源的應(yīng)用[Fowler Events],讓那些事件源都吐出報(bào)表應(yīng)用感興趣的事件就可以了。
順便一提,上面的討論令我記起曾經(jīng)為ADDDP[Nilsson ADDDP]寫過一段文字[Nilsson Bricks](不過最終沒有放進(jìn)書里),介紹另一種應(yīng)用數(shù)據(jù)庫(kù)的用法。不過當(dāng)時(shí)寫作的重點(diǎn)落在性能,而非可維護(hù)性。文中我介紹了如何根據(jù)系統(tǒng)不同部分的特點(diǎn),讓系統(tǒng)發(fā)揮最大的功效。
再順便一提,一定要讀一讀Greg Young寫的DDDD系列文章[Greg Young],他的精彩作品也可以歸到這個(gè)主題之下。他建議嚴(yán)格切分讀和寫,籍此取得非常高的可伸縮性等等成效。
整合的UI
論點(diǎn)其實(shí)差不多,只不過用到UI上沒有整合數(shù)據(jù)庫(kù)vs.應(yīng)用數(shù)據(jù)庫(kù)那么有力。與其用一個(gè)UI套上幾個(gè)服務(wù),何不讓每個(gè)服務(wù)都有自己的UI,然后將不同的UI用一個(gè)UI容器框架集成起來?見圖5。
圖5. UI也分塊
這樣一來,某個(gè)分塊的開發(fā)者可以全方位地處理問題,從UI一直到存儲(chǔ),不必與其它團(tuán)隊(duì)同步。對(duì)實(shí)際生產(chǎn)率的潛在影響是巨大的。
巨型的團(tuán)隊(duì)
經(jīng)常有人向我們求助,抱怨說他們100人的大團(tuán)隊(duì)沒辦法達(dá)到期望的生產(chǎn)效率。
每一次,我都得到同樣的結(jié)論。不要那樣做!100名開發(fā)者在同一個(gè)團(tuán)隊(duì)里,太可怕了,失敗風(fēng)險(xiǎn)太大了。即使你再加20個(gè)人!
雖然已經(jīng)出版了30年,讀過《人月神話》[Brooks MMM]的人還是少得出奇。真糟糕。(書名“人月神話”的意思是,向一個(gè)進(jìn)度落后的項(xiàng)目增加更多開發(fā)者,只會(huì)讓它更落后。書里還闡述了很多重要的思想。)
所以,就算退一步說你真的有一個(gè)規(guī)模龐大的問題要解決,你也真的需要100名開發(fā)者。請(qǐng)一定要小心謹(jǐn)慎地將大團(tuán)隊(duì)分成若干個(gè)小規(guī)模的、盡可能相互隔離的團(tuán)隊(duì),以便每個(gè)團(tuán)隊(duì)能夠全速運(yùn)行。
但是當(dāng)你把大團(tuán)隊(duì)分成比如說100個(gè)新團(tuán)隊(duì)的時(shí)候,顯然不會(huì)因此就消滅了復(fù)雜性。例子里面分成10-20個(gè)團(tuán)隊(duì)比只有1個(gè)團(tuán)隊(duì)好,并不表示分成100個(gè)會(huì)更好。請(qǐng)注意平衡。
SOA與松散耦合
說到平衡,兩年前我曾經(jīng)很不理解SOA的一些說法,還寫了博客帖子[Nilsson SOA-Qs]請(qǐng)教答案。
我不理解的其中一點(diǎn)是為什么要極端的細(xì)粒度。為什么不用“定界上下文(Bounded Context)” [Evans DDD]的思維來看待服務(wù)呢,為什么需要粒度細(xì)到只有一行代碼的服務(wù)……
Jim Webber在一篇文章里[Webber Anemic Service Model]討論過這個(gè)問題,我認(rèn)為他說得很有道理。對(duì)松散耦合的關(guān)注成了唯一的決定因素,以至于忘了搭配上它的好朋友——高內(nèi)聚,才導(dǎo)致出現(xiàn)令我困惑不解的奇怪說法。
所以,我把前面討論的分塊看作是“做對(duì)了的SOA”。
強(qiáng)迫一種風(fēng)格
最初我把標(biāo)題定為“強(qiáng)迫一種信仰”,但又顧慮到Google帶來的很多人會(huì)失望。我在這里談的風(fēng)格/信仰,是指我們當(dāng)中有很多人喜歡思考和討論TDD、DDD、BDD、模式、重構(gòu)、干凈的代碼等等。但世上還有更多開發(fā)者并不同意我們所說的是“唯一的道路”。
有時(shí)候會(huì)采取的解決辦法是完全不理會(huì)實(shí)際情況,強(qiáng)迫所有的開發(fā)者都用同一種風(fēng)格。會(huì)發(fā)生什么事呢?我猜下面這幾種情況會(huì)很常見:
有的開發(fā)者會(huì)非常低效。
低效的開發(fā)者還會(huì)很不開心。
最后整個(gè)團(tuán)隊(duì)圍繞的風(fēng)格是所有成員的“最小公分母”。
于是當(dāng)初贊同強(qiáng)迫推行那種風(fēng)格的開發(fā)者,現(xiàn)在也變得低效和不開心。
能保持一致是好的,但不能不惜代價(jià)去保持一致。實(shí)際上我覺得很多時(shí)候讓不同的分塊用不同的風(fēng)格開發(fā),反而有好處。不同開發(fā)者之間的技能差異是其中一個(gè)原因。還有另一個(gè)經(jīng)常被忽視的原因,不同的分塊當(dāng)然是有差異的,所以相應(yīng)地采取不同的風(fēng)格反而有利。比如有的分塊從領(lǐng)域模型方式中肯定得不到什么好處,那么不采取領(lǐng)域模型的路線也沒關(guān)系,實(shí)際上也建議不要那么做!
即使放寬了對(duì)分塊內(nèi)部的約束,你還是可以(也應(yīng)該)對(duì)外部表現(xiàn)設(shè)立嚴(yán)格的要求,比如要保證自動(dòng)化測(cè)試成功。
我意識(shí)到以上做法違反了集體代碼所有制的原則,因?yàn)槿藗兌既υ谧约旱姆謮K里。在分塊內(nèi)部,(如果該分塊選擇了集體所有的風(fēng)格)肯定是代碼集體所有的。
對(duì)了,在單個(gè)分塊內(nèi),我認(rèn)為應(yīng)該強(qiáng)迫一種風(fēng)格。
變化率差異
這件事情你可能覺得顯而易見,不過我還是要特別指出來:不同分塊的變化率可能有極大的差異。在數(shù)據(jù)庫(kù)驅(qū)動(dòng)的項(xiàng)目里,有句話在項(xiàng)目前期的會(huì)議上經(jīng)常聽到,我也常常拿來開玩笑:
“我們已經(jīng)定好了數(shù)據(jù)庫(kù)Schema,現(xiàn)在可以開始干活了!”
沒有取笑誰的意思,我自己也說過這樣的話。
雖然我有些猶豫要不要說出來,不過有的分塊也許的確能用那樣的方式取得很好的結(jié)果,定好數(shù)據(jù)庫(kù)Schema,以后就不再改了。
而同時(shí)其他的分塊可以采用DDD項(xiàng)目的典型風(fēng)格:
“好吧,我們現(xiàn)在了解得還不深,不過讓我們先按目前的理解來做,隨著我們了解加深,領(lǐng)域模型可以天天改,也一定會(huì)天天改!”
現(xiàn)在兩種風(fēng)格可以愉快地并存。以前肯定也有并存的情況,只不過現(xiàn)在明確了界限,成功機(jī)會(huì)提高了。
名字的來歷
有人說任何值得討論的事物都應(yīng)該賦予一個(gè)名稱,我當(dāng)然不希望這種架構(gòu)風(fēng)格僅僅因?yàn)闆]有名稱就失去討論的資格。
那么“分塊云計(jì)算(Chunk Cloud Computing)”是個(gè)好名稱嗎?爭(zhēng)議肯定是少不了的,先放在一邊,聽我說一下來歷吧。
在本屆歐洲軟件架構(gòu)研討會(huì)上,Christoffer Skjoldborg提了一個(gè)叫做“Chunk Cloud”的論題。“Chunk”就是一小片(分塊),“Cloud”是現(xiàn)在的炒作題材。他的描述很接近我近來觀察到的一種應(yīng)用架構(gòu)方式。(本文就是努力在描述這種架構(gòu)方式?!皬?qiáng)迫一種風(fēng)格”小節(jié)尤其得自Chris的啟發(fā)。)Chris描述的時(shí)候說得有點(diǎn)極端,不過我想主要是為了讓他的觀點(diǎn)流傳開。
最后的“Computing”是研討會(huì)上Nicklas Andersson
最佳實(shí)踐?
不知道你怎么樣,我聽到“最佳實(shí)踐”的時(shí)候會(huì)警覺起來??赡苁怯捎谀切┡cDreyfus模型[Dreyfus model of skill acquisition]相關(guān)的討論,還由于見識(shí)到一些無視上下文的“最佳實(shí)踐”……
我不認(rèn)為“塊云計(jì)算”是一種最佳實(shí)踐。我只認(rèn)為它是一種架構(gòu)風(fēng)格,而我經(jīng)常發(fā)現(xiàn)適用這種風(fēng)格的場(chǎng)合。但別忘了,要看情況。
新問題?
當(dāng)然有了!可是你不覺得老問題沒意思么?我知道這種風(fēng)格有很多新問題,以后還會(huì)冒出更多(肯定的)。最多人提出來的兩個(gè)問題是同樣的數(shù)據(jù)出現(xiàn)在好幾個(gè)地方,以及不同的分塊之間有數(shù)據(jù)不一致的風(fēng)險(xiǎn)。這兩個(gè)問題都必須解決,但請(qǐng)容我放到另一篇文章里。
還有一個(gè)經(jīng)常提出的問題是“怎么做”,尤其是怎么將領(lǐng)域模型拆成幾個(gè)小塊。我會(huì)再找時(shí)間詳談。
更進(jìn)一步的觀察對(duì)此方向是肯定還是否定?
穩(wěn)妥地說,兩方面的觀察(及觀點(diǎn))都有,我也期盼著看到您的想法!
評(píng)論
查看更多