如何設(shè)計一個復雜的業(yè)務系統(tǒng)?從對領(lǐng)域設(shè)計、云原生、微服務、中臺的理解開始
回想起這幾年做過的一些大型企業(yè)數(shù)字化轉(zhuǎn)型項目,有得有失,最終回歸到本源“如何設(shè)計和實施一個復雜軟件工程”這個問題上,趁著春節(jié)長假,把自己的一些對架構(gòu)設(shè)計思考和學習隨筆寫下來,寫的倉促,希望能引起大家一些啟發(fā)和討論。 當然本文所說的軟件開發(fā)主要業(yè)務應用軟件的開發(fā),而中間件、數(shù)據(jù)庫等技術(shù)組件開發(fā)的關(guān)注點則在其他一些方面,不在這里展開。
01如何解決復雜業(yè)務設(shè)計
Aliware
軟件架構(gòu)設(shè)計本身就是一個復雜的事情,但其實業(yè)界已有一個共識,那就是“通過組件化完成關(guān)注點的分離從而降低局部復雜度”。其實現(xiàn)在我們用的無論是容器、中間件、消息、數(shù)據(jù)庫等,在某種意義上都是組件化的產(chǎn)物。這樣的好處是在不同的系統(tǒng)里可以復用。在云原生興起的今天,以通用的、組件化的服務形式更容易為我們所用,所以說現(xiàn)在如果還不享用云原生技術(shù)紅利,那你就會被時代拋棄。
云原生滿足非功能性質(zhì)量需求
云原生在技術(shù)上能夠最大程度的解決眾多非功能性質(zhì)量和技術(shù)需求(如上圖),那作為一個企業(yè)級應用架構(gòu),自然會把專注點轉(zhuǎn)移到業(yè)務應用功能性設(shè)計本身上來?,F(xiàn)在來說對于一個復雜業(yè)務架構(gòu)進行設(shè)計,我們要想做到又快又好,無非是兩種情況:一是架構(gòu)師本身對業(yè)務理解很深、能力超強、爐火純青;二是原有的業(yè)務系統(tǒng)本身模型清晰,足夠的“高內(nèi)聚低耦合”,可以快速在其基礎(chǔ)之上分析業(yè)務變化形成新的業(yè)務架構(gòu)設(shè)計。我們應該追求的是第二種情況,這也就意味著從一開始的企業(yè)級模型建設(shè),就要對模型設(shè)計、業(yè)務流程仔細對待,只有做到基礎(chǔ)扎實,才能有后面的“快速迭代”。
我們再回到架構(gòu)設(shè)計的本質(zhì),即為什么我們要在代碼實現(xiàn)前做設(shè)計。設(shè)計首先是要解決問題的復雜度。于是有人做了一個架構(gòu),交給了一個團隊去實現(xiàn),很快發(fā)現(xiàn)實現(xiàn)的架構(gòu)和設(shè)計完全是兩回事。當然原因很明確——缺少了交流和溝通;其次是要建立團隊協(xié)作溝通的共識。即使我們做好了一個團隊都達成共識的架構(gòu)設(shè)計,大家都兢兢業(yè)業(yè)把設(shè)計變成了現(xiàn)實,一個長期困擾軟件行業(yè)的問題出現(xiàn)了,需求總是在變化,無論預先設(shè)計如何“精確”,總是發(fā)現(xiàn)下一個坑就在不遠處,結(jié)果往往是情況越來越糟糕,也就是我們常說的架構(gòu)“腐化”了,最后大家不得不接受重寫。這些經(jīng)歷讓我們逐步明確了軟件架構(gòu)設(shè)計的實質(zhì)是通過核心問題的分離降低復雜度,并讓系統(tǒng)能夠更快地響應外界業(yè)務的變化,并且使得系統(tǒng)能夠持續(xù)演進。在遇到變化時不需要從頭開始,保證實現(xiàn)成本得到有效控制。
所以,我覺得從架構(gòu)設(shè)計角度,以下三點是最為關(guān)鍵的:
- 讓我們的模型、組件和業(yè)務劃分盡量靠近變化的本質(zhì),比如對于一般電商系統(tǒng)來說,就是用戶、商品、交易、支付等,這樣的劃分能夠讓我們將變化“隔離”在一定的范圍(業(yè)務模塊)內(nèi),從而幫助我們有效減少改變點。
- 設(shè)計上,業(yè)務模型內(nèi)部是高內(nèi)聚,模型之間是低耦合,即各自完成的業(yè)務是相對獨立的,不會因為一方掉線而牽連另外一方,比如商品推薦功能掛掉了,但是交易和支付業(yè)務應該繼續(xù)正常提供服務,可能提示用戶暫時無法提供推薦服務,或者干脆降級為兜底策略。
- 模型、組件在業(yè)務上盡可能是復用的,正是這樣的復用才成就了今天的互聯(lián)網(wǎng)級架構(gòu),我們不會每做一個電商系統(tǒng)都從零做起。而被“復用”最多的業(yè)務模塊顯然會重點設(shè)計和運營,成為核心業(yè)務模塊。當然架構(gòu)上這樣的電商系統(tǒng)必然也會比較健壯。
上面的三點毫無疑問都指向了業(yè)務,從業(yè)務出發(fā)、面向業(yè)務變化是我們現(xiàn)代架構(gòu)設(shè)計成功的關(guān)鍵,所以說復雜業(yè)務架構(gòu)設(shè)計的核心實質(zhì)是保證面對業(yè)務變化時我們能夠有足夠快的響應能力。
02 領(lǐng)域設(shè)計
Aliware
前面說了業(yè)務軟件開發(fā)的常見病:從一個小的項目不斷開發(fā)演化變成一個大型業(yè)務系統(tǒng),但隨著新需求的不斷增加,最終演變成了開發(fā)團隊的噩夢。而這些噩夢大部分是源于軟件的概念完整性(“概念完整性”一詞來源于軟件工程的經(jīng)典著作《人月神話》)遭到了破壞。這些業(yè)務代碼可能是一代又一代的開發(fā)人員各行其道的堆疊起來的(我們又稱之為“屎山”),而這個過程中沒人有意識的去維護軟件的概念完整性。而 DDD 領(lǐng)域設(shè)計,特別是 DDD 提供的戰(zhàn)略建模層面的概念,是維護軟件概念完整性的良藥。
“技術(shù)服務于業(yè)務、業(yè)務驅(qū)動技術(shù)”是目前大部分人的共識,尤其是對商業(yè)公司而言。而 DDD 領(lǐng)域設(shè)計主張在軟件設(shè)計中把業(yè)務領(lǐng)域本身作為關(guān)注的焦點(換句話說就是軟件開發(fā)人員要懂業(yè)務)非常符合這種思想;并且,DDD 提供了切實可行的面對復雜業(yè)務軟件設(shè)計的解決方法,這也是我非常提倡作為一個架構(gòu)師去深入學習和討論 DDD 領(lǐng)域設(shè)計的相關(guān)知識。
戰(zhàn)略建模
在戰(zhàn)略層面,DDD 非常強調(diào)對業(yè)務問題的分析和分解,通過識別核心問題來降低問題的復雜度。DDD 在戰(zhàn)略層面維護模型的概念完整性的方法,最重要的兩個概念就是界限上下文(Bounded Context)和防腐層(Anti-Corruption Layer)。
- 定義好界限上下文
關(guān)于界限上下文的定義,隨便一本講 DDD 的書上都會詳細講解,這里我只想分享一下自己的一些理解。這時,有人會問:界限上下文多大才能合適呢,劃分上下文有沒有可以遵循的規(guī)則呢?
劃分上下文的規(guī)則,無非就是放之四海而皆準的“高內(nèi)聚、低耦合”,這么說可能還是太虛。其實真正讓大家感到糾結(jié)的是,不知如何切分的那些東西之間所存在的關(guān)聯(lián),有的甚至干脆都納入到一個上下文里。其實,我認為與其關(guān)注上下文的“大小”,不如關(guān)注模型的“質(zhì)量”,關(guān)注概念的完整性是不是容易被破壞。我覺得,判斷大小是不是合適,要結(jié)合應用開發(fā)團隊的能力,看開發(fā)團隊能在多大的一個范圍內(nèi)掌控軟件的概念完整性。只要是開發(fā)團隊沒有問題,這個范圍就算再大也都是可以的。
如果開發(fā)團隊的水平在業(yè)界屬于上游,那么維護上下文的范圍往往是很大的;一些公司開發(fā)團隊的水平參差不齊,所以在項目的實施過程中,可能需要劃分相對小的上下文,盡可能減少“屎山”的不斷堆積。
- 做好防腐層
界限上下文需要時刻保護好自己所維護的邊界,以及邊界內(nèi)概念的完整性,這時需要將某個上下文的概念轉(zhuǎn)化為另一個上下文概念的地方就叫做“防腐層”。防腐層的實現(xiàn)有很多種,典型的比如作為適配器 Adaptor 來實現(xiàn),另外廣義上講,Gateway 也是一個典型性的防腐層組件,當然,防腐層的代碼和其他內(nèi)部業(yè)務模型之間要存在明顯的物理邊界(當然不一定說要把防腐層作為一個個獨立部署的進程),至少我們可以考慮把防腐層作為一個獨立的類庫來進行構(gòu)建和維護,阿里內(nèi)部的比如星環(huán)、其實就是這個思路。
一個典型的防腐層的設(shè)計
戰(zhàn)術(shù)建模
DDD 在戰(zhàn)術(shù)上最核心的概念就是實體和聚合,為了更好的理解什么是聚合、聚合根、聚合內(nèi)部實體,下面舉例說明一下。想象一下一個電商系統(tǒng)的訂單相關(guān)的模型,我們可能會得到訂單 Order、訂單頭 OrderHeader、訂單行項 OrderItem 三個相互關(guān)聯(lián)的概念:
- 一個叫做 Order 的聚合。
- 這個訂單聚合的聚合根是一個叫做 OrderHeader 的實體,實體 OrderHeader 的 ID 叫做 OrderId(訂單號)。
- 通過 OrderHeader 實體,我們可以訪問 OrderItem 實體的一個聚合。OrderItem 這個實體的局部 ID 叫做 ProductId(產(chǎn)品 ID)。因為業(yè)務善變不允許在同一個訂單的不同訂單項內(nèi)出現(xiàn)同一個產(chǎn)品,所以我們可以選擇產(chǎn)品 ID 作為訂單項的局部 ID。
“聚合是數(shù)據(jù)修改的單元”,基于這個原則,我們可以做到“聚合內(nèi)強一致、聚合外最終一致”,比如,我們可以不能接受一個訂單內(nèi)的所有訂單項的金額之和不等于訂單頭的總金額,我們就必須把訂單頭和訂單行項這兩個實體劃分到同一個聚合內(nèi)。
- 設(shè)計聚合的原則
我們不妨先看一下《實現(xiàn)領(lǐng)域驅(qū)動設(shè)計》一書中對聚合設(shè)計原則的描述,原文是有點不太好理解的,我來稍微解釋一下:
- 在一致性邊界內(nèi)建模真正的不變條件。聚合用來封裝真正的不變性,而不是簡單地將對象組合在一起。聚合內(nèi)有一套不變的業(yè)務規(guī)則,各實體和值對象按照統(tǒng)一的業(yè)務規(guī)則運行,實現(xiàn)對象數(shù)據(jù)的一致性,邊界之外的任何東西都與該聚合無關(guān),這就是聚合能實現(xiàn)業(yè)務高內(nèi)聚的原因。
- 盡量設(shè)計小的聚合。如果聚合設(shè)計得過大,聚合會因為包含過多的實體,導致實體之間的管理過于復雜,高頻操作時會出現(xiàn)并發(fā)沖突或者數(shù)據(jù)庫鎖,最終導致系統(tǒng)可用性變差。而小聚合設(shè)計則可以降低由于業(yè)務過大導致聚合重構(gòu)的可能性,讓領(lǐng)域模型更能適應業(yè)務的變化。
- 通過唯一標識引用其它聚合。聚合之間是通過關(guān)聯(lián)外部聚合根 ID 的方式引用,而不是直接對象引用的方式。外部聚合的對象放在聚合邊界內(nèi)管理,容易導致聚合的邊界不清晰,也會增加聚合之間的耦合度。
- 在邊界之外使用最終一致性。聚合內(nèi)數(shù)據(jù)強一致性,而聚合之間數(shù)據(jù)最終一致性。在一次事務中,最多只能更改一個聚合的狀態(tài)。如果一次業(yè)務操作涉及多個聚合狀態(tài)的更改,應采用領(lǐng)域事件的方式異步修改相關(guān)的聚合,實現(xiàn)聚合之間的解耦(相關(guān)內(nèi)容我會在領(lǐng)域事件部分詳解)。
- 通過應用層實現(xiàn)跨聚合的服務調(diào)用。為實現(xiàn)微服務內(nèi)聚合之間的解耦,以及未來以聚合為單位的微服務組合和拆分,應避免跨聚合的領(lǐng)域服務調(diào)用和跨聚合的數(shù)據(jù)庫表關(guān)聯(lián)。
上面的這些原則是 DDD 的一些通用的設(shè)計原則,還是那句話:“適合自己的才是最好的?!痹谙到y(tǒng)設(shè)計過程時,你一定要考慮項目的具體情況,如果面臨使用的便利性、高性能要求、技術(shù)能力缺失和全局事務管理等影響因素,這些原則也并不是不能突破的,總之一切以解決實際問題為出發(fā)點。
- 設(shè)計聚合的步驟
DDD 領(lǐng)域建模通常采用類似事件風暴,一般通過用例分析、場景分析和用戶旅程分析等方法,通過頭腦風暴列出所有可能的業(yè)務行為和事件,然后找出產(chǎn)生這些行為的領(lǐng)域?qū)ο螅⑹崂眍I(lǐng)域?qū)ο笾g的關(guān)系,找出聚合根,找出與聚合根業(yè)務緊密關(guān)聯(lián)的實體和值對象,再將聚合根、實體和值對象組合,構(gòu)建聚合。
電商系統(tǒng)大家都比較熟悉了,而且關(guān)于電商業(yè)務來說有許多比較成熟的模型可以直接借鑒;那下面我們以另外一個場景-保險投保業(yè)務為例,看一下聚合的構(gòu)建過程主要都包括哪些步驟,當然這個例子我是從其他的學習資料里看到的,比較典型,可以當作示例來進行說明:
保險投保業(yè)務簡單示例(From 學習資料)
- 第一步:采用用例分析或事件風暴等方法,根據(jù)業(yè)務行為,梳理出在過程中發(fā)生這些行為的所有的實體和值對象,比如投保單、標的、客戶、被保人等等。
- 第二步:從眾多實體中選出適合作為對象管理者的根實體,也就是聚合根。判斷一個實體是否是聚合根,上一章也說過,你可以結(jié)合以下場景分析:是否有獨立的生命周期?是否有全局唯一 ID?是否可以創(chuàng)建或修改其它對象?是否有專門的模塊來管這個實體。圖中的聚合根分別是投保單和客戶實體。
- 第三步:根據(jù)上一章說的設(shè)計聚合的原則,找出與聚合根關(guān)聯(lián)的所有緊密依賴的實體和值對象。構(gòu)建出一個包含一個聚合根、多個實體和值對象的對象集合,這個集合就是聚合。在圖中我們構(gòu)建了客戶和投保這兩個聚合。
- 第四步:在聚合內(nèi)根據(jù)聚合根、實體和值對象的依賴關(guān)系,畫出對象的引用和依賴模型。這里需要說明一下:投保人和被保人的數(shù)據(jù),是通過關(guān)聯(lián)客戶 ID 從客戶聚合中獲取的,在投保聚合里它們是投保單的值對象,這些值對象的數(shù)據(jù)是客戶的冗余數(shù)據(jù),即使未來客戶聚合的數(shù)據(jù)發(fā)生了變更,也不會影響投保單的值對象數(shù)據(jù)。從圖中我們還可以看出實體之間的引用關(guān)系,比如在投保聚合里投保單聚合根引用了報價單實體,報價單實體則引用了報價規(guī)則子實體。
- 第五步:多個聚合根據(jù)業(yè)務語義和上下文一起劃分到同一個限界上下文內(nèi)。
那以上就是一個聚合誕生的完整過程了。
03 不同場景下的領(lǐng)域建模策略
Aliware
由于企業(yè)內(nèi)情況千差萬別,發(fā)展歷程也不一樣,有遺留單體系統(tǒng)的微服務改造,也有全新未知領(lǐng)域的業(yè)務建模和系統(tǒng)設(shè)計,還有遺留系統(tǒng)局部優(yōu)化的情況。不同場景下,領(lǐng)域建模的策略也會有差異。下面我們就分幾類場景來看看如何進行領(lǐng)域建模。
新建系統(tǒng)
新建系統(tǒng)對于復雜的業(yè)務領(lǐng)域,領(lǐng)域可能需要多級拆分后才能開始領(lǐng)域建模。領(lǐng)域拆分為子域,甚至子域還需要進一步拆分。比如:保險它需要拆分為承保、理賠、收付費和再保等子域,承保子域再拆分為投保、保單管理等子子域。復雜領(lǐng)域如果不做進一步細分,由于問題域太大,領(lǐng)域建模的工程量會非常浩大。你不太容易通過事件風暴,完成一個很大的領(lǐng)域建模,即使勉強完成,效果也不一定好。
對于復雜領(lǐng)域,我們可以分三步來完成領(lǐng)域建模和微服務設(shè)計。
- 拆分子域建立領(lǐng)域模型,根據(jù)業(yè)務領(lǐng)域的特點,參考流程節(jié)點邊界或功能聚合模塊等邊界因素。結(jié)合領(lǐng)域?qū)<液晚椖繄F隊的討論,將領(lǐng)域逐級分解為大小合適的子域,針對子域采用事件風暴,劃分聚合和限界上下文,初步確定子域內(nèi)的領(lǐng)域模型。
- 領(lǐng)域模型微調(diào)梳理領(lǐng)域內(nèi)所有子域的領(lǐng)域模型,對各子域領(lǐng)域模型進行微調(diào)。微調(diào)的過程重點考慮不同領(lǐng)域模型中聚合的重組。同步考慮領(lǐng)域模型和聚合的邊界,服務以及事件之間的依賴關(guān)系,確定最終的領(lǐng)域模型。
- 微服務的設(shè)計和拆分根據(jù)領(lǐng)域模型和微服務拆分原則,完成微服務的拆分和設(shè)計。
單體遺留系統(tǒng)
如果我們面對的是一個單體遺留系統(tǒng),只需要將部分功能獨立為微服務,而其余仍為單體,整體保持不變,比如將面臨性能瓶頸的模塊拆分為微服務。我們只需要將這一特定功能,理解為一個簡單子領(lǐng)域,參考簡單領(lǐng)域建模的方式就可以了。在微服務設(shè)計中,我們還要考慮新老系統(tǒng)之間服務和業(yè)務的兼容,必要時可引入防腐層。
04 云原生時代下的挑戰(zhàn)
Aliware
隨著云原生技術(shù)的興起,現(xiàn)在企業(yè)級架構(gòu)就更加的云化,而云化的架構(gòu)風格有了新的關(guān)注點:彈性邊界。彈性邊界是一個云原生企業(yè)級應用架構(gòu)的核心概念,它指把彈性作為最優(yōu)先的考慮要素而劃定的系統(tǒng)邊界,決定了我們是否能夠充分發(fā)揮云原生平臺的全部能力。于是我們就需要新的方法來彌補以前業(yè)務模型的不足,以滿足新的云原生化的需要?,F(xiàn)在可以說,微服務基本上就是以云原生架構(gòu)作為基礎(chǔ),而在固定彈性的平臺上使用微服務架構(gòu),有極高的實施成本??梢哉f,云原生實際上就應該是微服務的前置條件。
在云原生時代,我們需要將彈性作為首要考慮的因素,納入建模的考量。那么彈性邊界,就是我們劃分系統(tǒng)的重要依據(jù)。而且,我們還需要考慮彈性邊界間的依賴關(guān)系,盡量避免彈性耦合。對于業(yè)務建模來說,為了配合云原生時代的架構(gòu),我覺得要做到如下幾點:
- 確立一種模型結(jié)構(gòu)能夠反映彈性邊界,而這時候需要考慮不同彈性邊界的原則來劃分界限上下文;如果兩個上下文明顯具有不同的彈性訴求,那就應該拆分。而如果具有一致的彈性訴求,可以考慮先不拆。那這個時候拆分微服務到底能多“微”呢?簡單說就是“微”到能夠更好的利用彈性來控制成本的大小。
- 從異步模型的視角,去優(yōu)化業(yè)務邏輯;典型就是 MQ 消息隊列系統(tǒng),由于有 broker,所以生產(chǎn)者和消費者不必在同一時間都保持可用性以及相同的吞吐量,而且生產(chǎn)者也不需要馬上等到回復。
- 位置的松耦合:典型就是服務注冊中心,消費端完全不需要直接知道提供端的具體位置,而都通過注冊中心來查找服務來訪問。
- 在彈性邊界切分業(yè)務上下文時,同一個彈性邊界內(nèi)部維護業(yè)務強一致性。
在異步調(diào)用產(chǎn)生中間態(tài)異常時,需要維護業(yè)務最終一致性。
05 不要忽視組織結(jié)構(gòu)的影響
Aliware
“康威定律”告訴我們,組織結(jié)構(gòu)會決定團隊溝通的結(jié)構(gòu),也會決定產(chǎn)品的結(jié)構(gòu)。對組織結(jié)構(gòu)的梳理,在需求調(diào)研的時候會經(jīng)常做。如果是信息收集而言,業(yè)務架構(gòu)設(shè)計在這里并沒有什么特殊之處。區(qū)別在于,業(yè)務架構(gòu)的目標是企業(yè)級的能力規(guī)劃,希望能夠突破壁壘、形成合力。正是這個原因,組織結(jié)構(gòu)對業(yè)務架構(gòu)設(shè)計的反作用力也是很大的,企業(yè)級數(shù)字化轉(zhuǎn)型方案要與組織結(jié)構(gòu)相匹配,否則落地的時候會困難重重。可以說,部門利益是做企業(yè)級架構(gòu)的最大障礙之一,跨越這個障礙也是對架構(gòu)師的能力的要求之一。當然,有些情況下,沒有更好的解決方案時,不動也是一種選擇。
以我的經(jīng)驗,這種問題沒有特別好的辦法,無非是兩種:一是有超強能力者主導,在最高層的支持下,強力推進這種決策,但是企業(yè)越大,尤其是以業(yè)務為主導地位的企業(yè)中,這種結(jié)構(gòu)就愈難形成;二是加強企業(yè)內(nèi)部的業(yè)務架構(gòu)人員的能力和數(shù)量(最好各個部門都有類似的角色),讓這些企業(yè)機構(gòu)人員以合作伙伴的方式全程參與到項目中,在項目的實施過程中搭建起協(xié)作網(wǎng)絡(luò),提升決策效率,才能使組織結(jié)構(gòu)不再是企業(yè)數(shù)字化轉(zhuǎn)型的瓶頸。
06 SOA-微服務-中臺:妥協(xié)的藝術(shù)
Aliware
多年前,這些傳統(tǒng)的大型 ERP 業(yè)務軟件,其實都是在一個很大的范圍內(nèi)維護業(yè)務概念的完整性。一個 ERP 安裝完畢后,數(shù)據(jù)庫有七八百張表(也就是七八百個實體)處于同一個界限上下文之內(nèi)。但是這些 ERP 在這樣一個巨大的界限上下文內(nèi)仍然很好的維護了業(yè)務概念的完整性,實在令人敬佩。
然而實現(xiàn)它非常困難,但是破壞它卻非常容易。一套 ERP 定制項目實施下來,數(shù)據(jù)庫里可能又多了幾百張表,更不用說不規(guī)范的命名看起來千奇百怪。這些廠商的 ERP 實施顧問和開發(fā)人員,夜以繼日的維護這個龐大的“屎山”。我們不能讓這些龐大的“單體應用”無限制的增長,于是我們又一次祭起了“分而治之”的大旗。想 SOA 這樣的軟件組件化技術(shù)給我們提供了拆分的工具。我們把一個大的界限上下文按照利于拆分成幾個相對來說小一些的界限上下文;在物理上,我們把一個大的單體應用拆分成若干服務。
一般來說,我們會讓服務的物理邊界和界限上下文的領(lǐng)域邊界基本堆砌,一個界限上下文對一個或多個可以獨立部署的服務應用,服務應用包含了界限上下文的核心業(yè)務邏輯的實現(xiàn)。SOA 的服務組件的物理邊界給服務間的調(diào)用增加了一些困難,這就使得開飯人員簡化對象之間的關(guān)系,編寫更加“高內(nèi)聚、低耦合”的代碼。當服務組件不多的時候,構(gòu)建防腐層的工作量也不會很大,我們只要處理好組件之間的代碼即成就好了。
但是,我們的架構(gòu)師和開發(fā)人員太喜歡“分而治之”了,微服務的廣泛使用甚至說是濫用,讓我們看很多微服務真的是很“微”,幾乎是一個 DDD 的聚合就可以對應一個可以獨立部署的微服務。這樣的微服務單單靠本身做不了太多的業(yè)務,這就需要更多更多的微服務“聚合”起來一起才能對外提供業(yè)務服務。
當然,微服務技術(shù)基礎(chǔ)設(shè)施的發(fā)展也為服務之間的調(diào)用提供了更多的便利,跨越微服務的邊界成為了常態(tài);這個時候,業(yè)務開發(fā)人員區(qū)分“同一個上下文內(nèi)的服務調(diào)用”和“上下文之間的防腐層”就要時刻保持頭腦清醒,這時候的界限上下文和微服務的物理邊界往往很難對齊,這就必然增加了維護每個界限上下文概念完整性的難度。
既然維護一個個“微小”的獨立的界限上下文概念完整性越來愈難,那么我們干脆將它們再聚合起來吧?將它們?nèi)诤系揭粋€大小適度的界限上下文,那這就是所謂的企業(yè)級業(yè)務架構(gòu),也就是我們現(xiàn)在說的業(yè)務中臺,最終目的可以說想要獲得“企業(yè)級”的大和諧。
所以在一定程度上講,軟件工程就是妥協(xié)的藝術(shù),是“中庸之道”。我們要不要中臺,要大的中臺,不管企業(yè)的大小,都應該結(jié)合自身的業(yè)務目標以及擁有的資源,在“維護更大范圍的概念完整性”和“維護更多的防腐層代碼”之間做出平衡,那這也是一個企業(yè)級架構(gòu)師所要做的最核心的事情之一。
我們團隊這些年確實做了一些“業(yè)務中臺方法論”的積累和實踐,并且在一些項目中做了實踐,當然其中最靈魂的部分之一還是前面說的領(lǐng)域設(shè)計。以前很多人說 DDD 領(lǐng)域設(shè)計乃至業(yè)務中臺方法論最難的就是沒有一個合適的工具或者平臺來實踐,今天其實阿里開源的 COLA 以及內(nèi)部使用的星環(huán)、BizWorks 都是很好的工具和平臺。
07 結(jié)語
Aliware
企業(yè)級應用架構(gòu)是在不斷的演進和迭代,但是我始終感覺企業(yè)應用架構(gòu)的形成過程是在一種看起來科學的方法論下,但是又不完全科學的過程中實現(xiàn)的。仔細想一下,做軟件架構(gòu)的其實很羨慕做建筑架構(gòu)的,因為建筑架構(gòu)有嚴謹?shù)牧W基礎(chǔ)作為基座,有很多可以精確計算的東西,而軟件架構(gòu)卻沒有多少可以精確計算出來的成分,所以,前面說的“不斷的妥協(xié)”不失是一種可行的設(shè)計思路和設(shè)計藝術(shù);其實這也應驗了那句“沒有銀彈”。
由于時間倉促,有些內(nèi)容簡單帶過,有些本應該結(jié)合實例來說明的地方在本文中也簡略而過,后面有時間的話我會結(jié)合更多的實際案例來對本文說的觀點進行補充。也希望本文能夠激發(fā)大家一起對目前云原生時代的企業(yè)級應用架構(gòu)設(shè)計的思考和討論,相互學習,共同進步。