自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

當(dāng)我們談?wù)揇DD時我們在談?wù)撌裁?/h1> 原創(chuàng) 精選

開發(fā)
我嘗試在軟件設(shè)計領(lǐng)域,將這些問題劃分到幾個相互獨立的范疇,這可以幫助我和其他人討論,在明確范圍內(nèi)可以更好的交流。

作者 | 祁兮

談?wù)摰?DDD,我們會聊事件風(fēng)暴,會聊限界上下文,會聊六邊形架構(gòu),會聊實體值對象。這些概念各不相同,相關(guān)的概念也很不一樣,但都屬于DDD的范疇。見過了很多DDD的討論和工作坊,我發(fā)現(xiàn)大家唇槍舌劍無法達成一致,往往是因為各自腦中的問題并不相同。

我嘗試在軟件設(shè)計領(lǐng)域,將這些問題劃分到幾個相互獨立的范疇,這可以幫助我和其他人討論,在明確范圍內(nèi)可以更好的交流。

一種比較經(jīng)典的方式是劃分為戰(zhàn)略設(shè)計和戰(zhàn)術(shù)設(shè)計。由于領(lǐng)域模型設(shè)計復(fù)雜度也很高,所以我又把領(lǐng)域模型設(shè)計從戰(zhàn)術(shù)設(shè)計中劃分出來,形成單獨的范疇,以便更好的討論。

下面我將討論這三個范疇的概念和方法。

一、DDD戰(zhàn)略設(shè)計

在這個范疇里,主要討論目標(biāo)是復(fù)雜的業(yè)務(wù)需求。有多復(fù)雜呢?可能需要多個團隊分工合作,或者一個團隊分階段開發(fā),需要被設(shè)計成多個獨立部署運行的服務(wù),會有多個代碼庫。

這個范疇可以有很多名字,比如DDD戰(zhàn)略設(shè)計、進程間架構(gòu)、微服務(wù)架構(gòu)設(shè)計等。

在這個范疇里討論的主要問題是,如何將這個復(fù)雜的業(yè)務(wù)需求合理的分成多個部分,從而分而治之。

為什么要分成多個部分?因為解決復(fù)雜問題的一個有效方法是將其分解為多個相對簡單的問題,然后分別解決。如果不進行分解,這個復(fù)雜問題往往會讓我們在解決過程中陷入困境,就算設(shè)計出了解決方案,也往往由于解決方案過于復(fù)雜導(dǎo)致團隊的認知超載。

1.劃分方法

既然戰(zhàn)略設(shè)計需要將整個業(yè)務(wù)需求分成多個部分,那么如何找到用于劃分的接縫呢?

我看到行業(yè)里有這樣一些方法:

(1) 限界上下文

在《領(lǐng)域驅(qū)動設(shè)計》中,Eric提出了限界上下文。從領(lǐng)域模型設(shè)計的角度,為了讓模型保持完整獨立和清晰,需要識別出限界上下文,讓其作為模型的邊界。在書中并沒有完善的識別方法,更多的是提出一些概念。限界上下文往往被用來輔助判斷接縫的正確性。

在一個限界上下文中,領(lǐng)域知識是相對完整的。

(2) 核心域

在《領(lǐng)域驅(qū)動設(shè)計》中,Eric提出了精煉及核心域。在模型中識別出最有價值的核心域,將其獨立出來。

由于只提到了核心域,所以這也不是一個完整的劃分的方法。我曾在如何劃分限界上下文博客中基于此方法上提出了一種分解問題域的方法。

(3) 事件風(fēng)暴工作坊

事件風(fēng)暴工作坊可能是最早用來指導(dǎo)劃分限界上下文的方法。

對前一步(事件風(fēng)暴)產(chǎn)生的聚合進行分組,通過業(yè)務(wù)的內(nèi)聚性和關(guān)聯(lián)度劃分邊界,結(jié)合限界上下文的定義進行判斷,并給出上下文名稱。

——[服務(wù)化設(shè)計階段路徑方案]

但是「業(yè)務(wù)的內(nèi)聚性和關(guān)聯(lián)度」著實不是一個好的劃分依據(jù)。而事件風(fēng)暴的創(chuàng)始人Alberto曾經(jīng)提出過通過關(guān)鍵事件識別不同的階段進而識別限界上下文的方法,看上去是一個更加靠譜的方法。

(4) 8X Flow

8X Flow中提出了一套相對完整的劃分方法。首先定義「業(yè)務(wù)」和「領(lǐng)域」,然后將「業(yè)務(wù)」和「領(lǐng)域」劃分開來,接著基于合同將業(yè)務(wù)劃分成了不同的上下文,最終完成了劃分。

(5) 現(xiàn)代企業(yè)架構(gòu)白皮書

現(xiàn)代企業(yè)架構(gòu)白皮書提出通過職責(zé)類型劃分。流轉(zhuǎn)類識別不同的業(yè)務(wù)流程階段,規(guī)格類提取業(yè)務(wù)規(guī)則,視圖類專為統(tǒng)計報表而存在,配置類提供配置工具。

2.重新思考

我也嘗試過一些其他的劃分方法,比如通過時間階段劃分,通過使用者不同劃分,通過使用場景不同劃分,通過變化頻率不同劃分。這些方法和上面的一些方法都有些相似。

不好的劃分方法可能會導(dǎo)致分布式單體:每次變化不得不修改多個服務(wù)、每次部署必須同時部署多個服務(wù),服務(wù)之間有非常多的通信,同一個團隊管理著多個服務(wù),服務(wù)之間共享數(shù)據(jù)庫、同樣的代碼和模型。

也許我們可以總結(jié)出一些原則,來幫助我們驗證劃分是否合理。比如高內(nèi)聚低耦合,比如服務(wù)有明確的邊界且能自治,可以獨立演進,比如盡可能減少對于其他服務(wù)的依賴。

二、DDD戰(zhàn)術(shù)設(shè)計

在戰(zhàn)略層面劃分好了服務(wù)后,我們來看看一個服務(wù)內(nèi)部。

在這個范疇里,主要討論在一個服務(wù)內(nèi)部,如何劃分和組織代碼。

和上一節(jié)類似,在代碼也有不同的職責(zé);和上一節(jié)不同,對于代碼層面的劃分,已經(jīng)有相對成熟的方法。

這個范疇可以有很多名字,比如DDD戰(zhàn)術(shù)設(shè)計、進程內(nèi)架構(gòu)、分層架構(gòu)等。

需要指出的是,在一個服務(wù)內(nèi)部,如果領(lǐng)域模型足夠復(fù)雜,在分離領(lǐng)域邏輯和技術(shù)實現(xiàn)細節(jié)前,也需要先按照模塊進行一次劃分,然后再按上述的領(lǐng)域邏輯和技術(shù)實現(xiàn)細節(jié)的方式劃分。相關(guān)討論可以參見前綴分包vs后綴分包。

1.劃分方法

(1)《領(lǐng)域驅(qū)動設(shè)計》中的分層架構(gòu)

Eric在2003年提出的分層架構(gòu)。和傳統(tǒng)的展示層+業(yè)務(wù)邏輯層+數(shù)據(jù)訪問層的三層架構(gòu)相比多了一層,主要區(qū)別是將業(yè)務(wù)邏輯層分成了應(yīng)用層和領(lǐng)域?qū)印?/p>

圖片

圖片引自《領(lǐng)域驅(qū)動設(shè)計》第4章

其中「應(yīng)用層」這個概念,也指明了它和領(lǐng)域?qū)拥膮^(qū)別:領(lǐng)域?qū)訉W⒈磉_領(lǐng)域概念,而應(yīng)用層則在領(lǐng)域?qū)又?,加入了諸如持久化概念和事務(wù)概念等軟件的典型概念,對外提供了滿足具體場景的功能。展示層則在應(yīng)用層功能之上,定義了和外部系統(tǒng)通信的具體形式。

這里也將數(shù)據(jù)訪問層變成了基礎(chǔ)設(shè)施層?;A(chǔ)設(shè)施層為其他層提供支撐其概念的具體技術(shù)實現(xiàn)。

(2) 六邊形架構(gòu)

2005年六邊形架構(gòu)(翻譯)又稱端口和適配器架構(gòu),從設(shè)計模式的視角將代碼劃分成了負責(zé)業(yè)務(wù)邏輯的「應(yīng)用」和負責(zé)同外部系統(tǒng)交互的「適配器」。

圖片

圖片引自《六邊形架構(gòu)》

在2013的IDDD中Vaughn將六邊形架構(gòu)和DDD進行了結(jié)合,把「應(yīng)用」又細分成了「應(yīng)用程序」和「領(lǐng)域模型」。

圖片

圖片引自《實現(xiàn)領(lǐng)域驅(qū)動設(shè)計》第4章

2008年的洋蔥架構(gòu)也是類似的。

六邊形架構(gòu)從另外一個角度審視了一個理想架構(gòu),并將領(lǐng)域?qū)臃旁谥行?,凸顯其核心地位。

(3) 整潔架構(gòu)

Uncle Bob在2012提出了整潔架構(gòu),一般來說我們認為整潔架構(gòu)的四層(四圈)和IDDD的六邊形架構(gòu)基本是對應(yīng)的,只是整潔架構(gòu)將適配器劃分成了和框架耦合的「Frameworks & Drivers」層和負責(zé)內(nèi)外層數(shù)據(jù)轉(zhuǎn)換的「Interface Adapters」層。

圖片

圖片引自《整潔架構(gòu)》

整潔架構(gòu)也用「用例」來描述業(yè)務(wù)實體之外的一層,對應(yīng)于「應(yīng)用層」,更明確的指明了這層的職責(zé)是實現(xiàn)各個用例。

比較有趣的是,整潔架構(gòu)把Gateway接口放到了領(lǐng)域?qū)又獾摹赣美龑印埂_@使得領(lǐng)域?qū)又魂P(guān)注于當(dāng)前上下文的邏輯,而讓用例層負責(zé)和其他上下文/資源庫的協(xié)調(diào)和編排。

整潔架構(gòu)也討論了如何處理框架和架構(gòu)的關(guān)系。

(4) 清晰架構(gòu)

2017年更有集DDD、洋蔥架構(gòu)、整潔架構(gòu)、CQRS于一體的清晰架構(gòu)出現(xiàn)。

2.重新思考

以上的架構(gòu),指導(dǎo)每一個具體的業(yè)務(wù)功能分解來說是非常夠用的。然而在一個真實的項目中,除了每個具體功能的分層,其實還有一些對于平臺和框架的配置,這些其實要和每個業(yè)務(wù)功能的代碼有所區(qū)分,從代碼結(jié)構(gòu)上獨立出來。

另外,每一層都會有一些可以復(fù)用的代碼。比如領(lǐng)域?qū)拥幕A(chǔ)的業(yè)務(wù)異常,應(yīng)用層的事務(wù)處理,適配器層的HTTP客戶端。這些不只用于單個模塊或者單個服務(wù),也可以用于多個服務(wù);有些已經(jīng)有三方工具,有些需要我們自己定義和封裝。

我看到很多項目對于以上兩類代碼并沒有區(qū)分,而是把一切不屬于其他層的代碼都放到了基礎(chǔ)設(shè)施層。讓可憐的基礎(chǔ)設(shè)施層逐漸變成了垃圾桶。

三、領(lǐng)域模型設(shè)計

在戰(zhàn)術(shù)層面劃分好架構(gòu)后,我們來看看位于核心的領(lǐng)域模型。

在這個范疇里,主要討論基于面向?qū)ο蠹夹g(shù),如何用領(lǐng)域模型來表達業(yè)務(wù)概念。

為什么要使用領(lǐng)域模型這種模式,而不是用Service+數(shù)據(jù)模型的模式呢?如果復(fù)雜的業(yè)務(wù)邏輯采用數(shù)據(jù)模型這種模式,那么Service里會存在大量的復(fù)雜的邏輯,代碼是很難維護的。而領(lǐng)域模型充分利用了面向?qū)ο蠹夹g(shù)的優(yōu)勢,將復(fù)雜度轉(zhuǎn)變?yōu)槁氊?zé)明確的組件組合,讓各個組件相對簡單,來降低認知負載,提升可維護性。這就是設(shè)計的力量。

那為什么用面向?qū)ο蠹夹g(shù)呢?面向?qū)ο笏枷敫臃衔覀冋J知復(fù)雜問題的方式,并且現(xiàn)代編程語言都普遍支持面向?qū)ο螅訢DD選擇了面向?qū)ο蠹夹g(shù)。

1.關(guān)注點分離模式

在這個范疇里,主要還是使用《領(lǐng)域驅(qū)動設(shè)計》中的模式。我們以關(guān)注點分離的角度,來解析這些模式。

(1) 領(lǐng)域?qū)ο蟮纳芷陬愋?/h4>

從生命周期的角度,「領(lǐng)域?qū)ο蟆狗譃檫@樣幾個類型:

  • 和應(yīng)用生命周期一致,應(yīng)用啟動時被創(chuàng)建出來,應(yīng)用關(guān)閉時才銷毀。比如《領(lǐng)域驅(qū)動設(shè)計》5.4.1中的「資金轉(zhuǎn)賬」。
  • 在業(yè)務(wù)過程中被創(chuàng)建,會被保留一段時間,不隨著應(yīng)用關(guān)閉銷毀。比如電商系統(tǒng)中的「訂單」。
  • 在業(yè)務(wù)過程中被創(chuàng)建,在使用完成后即被銷毀。比如一些在對象之間傳遞的參數(shù)對象。

而在《領(lǐng)域驅(qū)動設(shè)計》的第5章,Eric也將領(lǐng)域?qū)ο髣澐譃榱藢嶓w、值對象、領(lǐng)域服務(wù)這三個重要模式。這三個模式和生命周期是如何對應(yīng)的呢?

對于類型1,和應(yīng)用生命周期一致,就是領(lǐng)域服務(wù)這種模式。對于類型2,在業(yè)務(wù)過程中被創(chuàng)建,會被保留一段時間,對應(yīng)于實體和值對象。而對于類型3,在業(yè)務(wù)過程中被創(chuàng)建隨即被銷毀,對應(yīng)于值對象。

VALUE OBJECT 經(jīng)常作為參數(shù)在對象之間傳遞消息。它們常常是臨時對象,在一次操作中被創(chuàng)建,然后丟棄。

——《領(lǐng)域驅(qū)動設(shè)計》 5.3 值對象

(2) 分離領(lǐng)域?qū)ο蟮膭?chuàng)建、查詢、保存和使用

從生命周期角度,對于這三類領(lǐng)域?qū)ο蟮膭?chuàng)建邏輯,可以使用Factory模式,將其封裝在Factory中。對于類型2的領(lǐng)域?qū)ο蟮谋A艏爸蟮牟樵?,可以使用Repository模式,將其模擬成一個集合從而進行存取操作。

Eric把Factory和Repository被歸為「支持對象」,以和其他用于表示模型的領(lǐng)域?qū)ο蠓珠_。

(3) 分離函數(shù)和命令

使用無副作用的函數(shù)模式,把沒有副作用的查詢邏輯提取出來,成為無副作用的函數(shù),而讓有副作用的命令盡可能簡單。

基于同樣的理由,我也在考慮將有IO操作的邏輯提取出來,直接讓應(yīng)用層調(diào)用,而不是和其他業(yè)務(wù)邏輯組合。

(4) 分離領(lǐng)域中的算法

使用Strategy模式,把業(yè)務(wù)邏輯中的變化點放到策略對象中,讓不同的實現(xiàn)可以互換,從而實現(xiàn)關(guān)注點分離。

(5) 分離領(lǐng)域中的規(guī)則

使用Specification模式,將領(lǐng)域中用于判斷是非的業(yè)務(wù)規(guī)則放到規(guī)格對象中。

(6) 分離做什么和怎么做

采用Intention-Revealing Interface和Cohesive Mechanism模式,把「做什么」和「怎么做」分離。讓釋意接口專注于表明意圖,方便調(diào)用方使用;讓內(nèi)聚機制封裝實現(xiàn)細節(jié),在釋意接口背后解決問題。

2.重新思考

我發(fā)現(xiàn)在OO BootCamp中得到的模型往往無法直接用于真實項目中,這讓我用新的角度重新學(xué)習(xí)和思考了領(lǐng)域模型。

在實際項目中,設(shè)計者往往過早陷入對于一些具體模式的識別,比如實體、聚合、領(lǐng)域服務(wù),而忽略了如何設(shè)計一個可以表達領(lǐng)域概念的模型。我們應(yīng)該基于領(lǐng)域概念設(shè)計領(lǐng)域模型,然后再采用合適的模式降低領(lǐng)域模型的復(fù)雜度,進一步增加領(lǐng)域模型的表達能力。

很多項目雖然也使用了以領(lǐng)域為核心的架構(gòu),但是設(shè)計者仍然是數(shù)據(jù)模型/貧血模型的思考方式,把大量領(lǐng)域邏輯放置在了萬能的Service中,讓領(lǐng)域概念隱藏在了冗長的過程代碼中,絲毫沒有享受到DDD帶來的收益。

軟件的核心是其為用戶解決領(lǐng)域相關(guān)的問題的能力。

——《領(lǐng)域驅(qū)動設(shè)計》 第一部分

在學(xué)習(xí)了讓我們眼花繚亂的眾多方法后,我們重新回到DDD的初衷,重新審視軟件設(shè)計和DDD之間的關(guān)系,讓DDD幫助我們提升軟件設(shè)計能力。

原文鏈接:??當(dāng)我們談?wù)揇DD時我們在談?wù)撌裁?(qq.com)??

責(zé)任編輯:趙寧寧 來源: 51CTO
相關(guān)推薦

2024-07-26 08:35:29

2020-11-16 15:47:05

SaaS軟件轉(zhuǎn)型

2016-08-12 10:11:22

2022-07-05 09:31:46

基礎(chǔ)設(shè)施容器Docker

2019-02-19 10:22:07

5G5G手機5G技術(shù)

2017-04-05 17:59:29

思科CTO下午茶

2024-03-28 14:16:43

容災(zāi)云計算

2022-04-28 13:02:32

cpu指令編程

2019-03-18 10:08:18

RSACRSA大會 網(wǎng)絡(luò)安全

2019-06-04 14:36:04

高并發(fā)Java架構(gòu)

2014-02-06 12:21:35

軟件集成

2022-03-11 21:28:31

部署開發(fā)服務(wù)器

2023-08-28 10:33:09

敏捷Scrum理念

2019-07-30 13:12:22

2019-12-24 11:19:44

容器DockerLinux

2016-11-22 23:44:56

2017-10-11 08:40:29

VR服務(wù)器移動端

2017-03-07 15:43:28

編程語言函數(shù)數(shù)據(jù)結(jié)構(gòu)

2021-11-18 21:09:50

流批場景引擎

2017-10-11 13:25:00

前端
點贊
收藏

51CTO技術(shù)棧公眾號