一,主流架構模型SOA架構和微服務架構


1.1 SOA架構


  SOA 全稱(Service Oriented Architecture),中文意思為“面向服務的架構”,他是一種設計方法,其中包含多個服務,服務之間通過相互依賴最終提供一系列的功能。一個服務通常以獨立的形式存在與作業系統程序中。各個服務之間通過網路呼叫。跟 SOA 相提並論的還有一個 ESB(企業服務匯流排),簡單來說 ESB 就是一根管道,用來連線各個服務節點。為了整合不同系統,不同協議的服務,ESB 做了訊息的轉化解釋和路由工作,讓不同的服務互聯互通。

 

SOA 所解決的核心問題 


1. 系統整合:站在系統的角度,解決企業系統間的通訊問題,把原先散亂、無規劃的系統間的網狀結構,梳理成規整、可治理的系統間星形結構,這一步往往需要引入一些產品,比如 ESB、以及技術規範、服務管理規範;這一步解決的核心問題是【有序】。 
2. 系統的服務化:站在功能的角度,把業務邏輯抽象成可複用、可組裝的服務,通過服務的編排實現業務的快速再生,目的:把原先固有的業務功能轉變為通用 
的業務服務,實現業務邏輯的快速複用;這一步解決的核心問題是【複用】。 
3. 業務的服務化:站在企業的角度,把企業職能抽象成可複用、可組裝的服務;把原先職能化的企業架構轉變為服務化的企業架構,進一步提升企業的對外服務能力;“前面兩步都是從技術層面來解決系統呼叫、系統功能複用的問題”。第三步,則是以業務驅動把一個業務單元封裝成一項服務。這一步解決的核心問題是【高效】。

1.2 微服務架構


微服務架構其實和 SOA 架構類似,微服務是在SOA上做的昇華,微服務架構強調的一個重點是“業務需要徹底的元件化和服務化”,原有的單個業務系統會拆分為多個可以獨立開發、設計、執行的小應用。這些小應用之間通過服務完成互動和整合。

 元件表示一個可以獨立更換和升級的單元,就像PC中的CPU、記憶體、顯示卡、硬碟一樣,獨立且可以更換升級而不影響其他單元。如果我們把PC作為元件以服務的方式構建,那麼這臺PC只需要維護主機板和一些必要的外部裝置。CPU、記憶體、硬碟都是以元件方式提供服務,PC 需要呼叫 CPU 做計算處理,只需要知道 CPU 這個元件的地址即可。

微服務的特徵: 
1. 通過服務實現元件化 
2. 按業務能力來劃分服務和開發團隊 
3. 去中心化 
4. 基礎設施自動化(devops、自動化部署)

1.3 SOA架構和微服務架構的差別


微服務不再強調傳統SOA架構裡面比較重的 ESB 企業服務匯流排,同時 SOA 的思想進入到單個業務系統內部實現真正的元件化。
Docker 容器技術的出現,為微服務提供了更便利的條件,比如更小的部署單元,每個服務可以通過類似 Node或者 Spring Boot 等技術跑在自己的程序中。
SOA 注重的是系統整合方面,而微服務關注的是完全分離。


二,領域驅動設計及業務驅動劃分


2.1 領域驅動設計的概念


 領域驅動設計(DDD,Domain-Driven Design),軟體開發不是一蹴而就的事情,我們不可能在不瞭解產品(或行業領域)的前提下進行軟體開發,在開發前,通常需要進行大量的業務知識梳理,然後才到軟體設計的層面,最後才是開發。而在業務知識梳理的過程中,我們必然會形成某個領域知識,根據領域知識來一步步驅動軟體設計,就是領域驅動設計的基本概念。

2.2 為什麼需要DDD


  業務初期,功能大都非常簡單,普通的 CRUD 就能滿足,此時系統是清晰的。隨著產品不斷迭代和演化,業務邏輯變得越來越複雜,我們的系統也越來越冗雜。各個模組之間彼此關聯,甚至到後期連作者都很難說清模組的具體功能意圖是啥。導致在修改一個功能時,要追溯到這個功能需要的修改點就需要很長時間,更別提修改帶來的不可預知的影響面。比如說: 


  訂單服務介面中提供了查詢、建立訂單相關的介面,也提供了訂單評價、支付的介面。同時訂單表是個大表,包含了非常多欄位。在我們維護程式碼時,將會導致牽一髮而動全身,很可能只是想改下評價相關的功能,卻影響到了建立訂單的核心路徑。雖然我們可以通過測試來保證功能完備性,但當我們在訂單領域有大量需求同時並行開發時,改動重疊、惡性迴圈、疲於奔命修改各種問題。

  絕大部分公司都是這樣一個狀態,然後一般的解決方案是不斷的重構系統,讓系統的設計隨著業務成長也進行不斷的演進。通過重構出一些獨立的類來存放某些通用的邏輯解決混亂問題,但是我們很難給它一個業務上的含義,只能以技術緯度進行描述,這個帶來的問題就是其他人接手這塊程式碼的時候不知道這個的含義或者可以通過修改這塊通用邏輯來達到某些需求。

2.3 領域模型追本溯源


  其實領域模型本身就不是一個陌生的單詞,說直白點,在早期領域模型就是資料庫設計.我們做傳統專案的流程或者說包括現在我們做專案的流程,都是首先討論需求,然後是資料庫建模, 在需求逐步確定的過程不斷的去更新資料庫的設計。接著我們在專案開發階段,發現有些關係沒有建、有些欄位少了、些表結構設計不合理,又在不斷的去調整設計。最後上線。在傳統專案中,資料庫是整個專案的根本,資料模型出來以後後續的開發都是圍繞著資料展開;然後形成如下的一個架構: 


service 很重,所有邏輯處理基本都放在 service 層。
POJO()作為 service 層的非常重要的一個實體,會因為不同場景的需求做不同的變化和組合,就會早成POJO的幾種不同模型(失血、貧血、充血),用來形容領域模型太胖或者太瘦。
  隨著業務變得複雜以後,包括資料結構的變化,那麼各個模組就需要進行修改,原本清晰的系統經過不斷的演化變得複雜、冗餘、耦合度高。後果就非常嚴重。我們試想一下如果一個軟體產品不依賴資料庫儲存裝置,那我們怎麼去設計這個軟體呢?如果沒有了資料儲存,那麼我們的領域模型就得基於程式本身來設計。那這個就是 DDD 需要去考慮的問題。

2.4 以抽獎設計為例來DDD


  DDD 理解起來有點抽象, 這個有點像設計模式,感覺很有用,但是不知道怎麼應用到自己寫的程式碼裡面,或者生搬硬套最後看起來又很彆扭,那麼接下來以一個簡單的轉盤抽獎案例來分析一下 DDD 的應用。

 
1. 針對功能層面劃分邊界 


這個系統可以劃分為運營管理平臺和使用者使用層,運營平臺對於抽獎的配置比較複雜但是操作頻率會比較低。而使用者對抽獎活動頁面的使用是高頻率的但是對於配置規則來說是誤感知的,根據這樣的特點,我們把抽獎平臺劃分針對 C 端抽獎和 M 端抽獎兩個子域在確認了 M 端領域和 C 端的限界上下文後,我們再對各 
自上下文內部進行限界上下文的劃分,接下來以 C 端使用者為例來劃分界限上下文.

1.1 確認基本需求 


  首先我們要來了解該產品的基本需求: 
抽獎資格(什麼情況下會有抽獎機會、抽獎次數、抽獎的活動起始時間)
抽獎的獎品(實物、優惠券、理財金、購物卡…)
獎品自身的配置,概率、庫存、某些獎品在有限的概率下還只能被限制抽到多少次等。
風控對接, 防止惡意薅羊毛。


1.2 針對產品功能劃分邊界 
 

抽獎上下文是整個領域的核心,負責處理使用者抽獎的核心業務。 
對於活動的限制,我們定義了活動資格的通用語言,將活動開始/結束時間,活動可參與次數等限制條件都收攏到活動資格子域中。
由於 C 端存在一些刷單行為,我們根據產品需求定義了風控上下文用於對活動進行風控。
由於抽獎和發放獎品其實可以認為是兩個領域,一個負責根據概率去抽獎、另一個負責將選中的獎品發放出去。所以對於這一塊也獨立出來一個領域。
細化上下文 
  通過上下文劃分以後,我們還需要進一步梳理上下文之間的關係,梳理的好處在於:

任務更好拆分(一個開發人員可以全身心投入到相關子域的上下文中)。
方便溝通,明確自身上下文和其他上下文之間的依賴關係,可以實現更好的對接。

  然後是基於上下文的更進一步細化建模,在 DDD 中存在一些名字定義。

實體:當一個物件由其標識(而不是屬性)區分時,這種物件稱為實體(Entity)。
值物件:當一個物件用於對事物進行描述而沒有唯一標識時,它被稱作值物件。
聚合根:聚合根屬於實體物件,它是領域物件中一個高度內聚的核心物件。(聚合根具有全域性的唯一標識,而實體只有在聚合內部有唯一的本地標識, 值物件沒有唯一標識,不存在這個值物件或那個值物件的說法)。
領域服務:一些重要的領域行為或操作,可以歸類為領域服務。它實現了全部業務邏輯並且通過各種校驗手段保證業務的正確性。
資源庫:資源封裝了基礎設施來提供查詢和持久化聚合操作。這樣能夠讓我們始終關注在模型層面,把物件的儲存和訪問都委託給資源庫來完成。他不 是資料庫的封裝,而是領域層與基礎設施之間的橋樑。DDD 關心的是領域內的模型,而不是資料庫的操作。
程式碼設計 
  在實際開發中,我們一般會採用模組來表示一個領域的界限上下文,比如:

com.mko.bussiness.lottery.*;//抽獎上下文
com.mko.bussiness.riskcontrol.*;// 風控上下文
com.mko.bussiness.prize.*;//獎品上下文
com.mko.bussiness.qualification.*;// 活動資格上下文
com.mko.bussiness.stock.*;//庫存上下文 
  對於模組內的組織結構,一般情況下我們是按照領域物件、領域服務、領域資源庫、防腐層等組織方式定義的。
com.mko.bussiness.lottery.domain.valobj.*;//領域物件-值物件
com.mko.bussiness.lottery.domain.entity.*;//領域物件-實體
com.mko.bussiness.lottery.domain.aggregate.*;//領域物件-聚合根
com.mko.bussiness.lottery.service.*;//領域服務
com.mko.bussiness.lottery.repo.*;//領域資源庫


2.5 領域驅動的好處


  用DDD可以很好的解決領域模型到設計模型的同步、演進最後對映到實際的程式碼邏輯。總的來說,DDD 有幾個好處: 
1. DDD 能夠讓我們知道如何抽象出限界上下文上下文以及如何去分而治之. 
- 分而治之:把複雜的大規模軟體拆分成若干個子模組,每一個模組都能獨立執行和解決相關問題。並且分割後各個部分可以組裝成為一個整體。 
- 抽象:使用抽象能夠精簡問題空間,而且問題越小越容易理解,比如說我們要對接支付,我們抽象的緯度應該是支付,而不是具體的微信支付還是支付寶支付。 
2. DDD 的限界上下文可以完美匹配微服務的要求在系統複雜之後,我們都需要用分治來拆解問題。一般有兩種方式,技術維度和業務維度。技術維度是類似MVC 這樣,業務維度則是指按業務領域來劃分系統。微服務架構更強調從業務維度去做分治來應對系統複雜度,而DDD也是同樣的著重業務視角。

2.6 領域驅動的總結


 領域驅動設計其實我們可以簡單認為是一種指導思想,是一種軟體開發方法,通過DDD可以將系統解構更加合理,最終滿足高內聚低耦合的本質。在我的觀點來看,有點類似資料庫的三正規化,我們開始在學的時候並不太理解,當有足夠的設計經驗以後慢慢發現三正規化帶來的好處。同時我們也並不一定需要嚴格按照這三正規化去進行實踐,有些情況下是可以靈活調整。

原文:https://blog.csdn.net/lj1314ailj/article/details/80919955