一文搞懂DDD的12個核心概念與2大建模方法
本文詳細介紹了領(lǐng)域驅(qū)動設(shè)計(DDD)的十二個核心概念及兩大建模方法,旨在幫助讀者理解DDD設(shè)計理念,掌握其在實踐中的運用技巧,從而提升個人技術(shù)水平和業(yè)務(wù)理解能力。
一、前言
領(lǐng)域驅(qū)動設(shè)計簡稱“DDD”,一套“知易行難”的方法論。同時我所工作的這些年,尤其在某大廠做初創(chuàng)項目的那段時間,經(jīng)常會產(chǎn)生各式各樣的“思想碰撞”,特別在設(shè)計中臺基建類領(lǐng)域時,為了保證充足的擴展性和穩(wěn)定性,都要好好的“碰撞”一下。雖然在設(shè)計過程中,每個人的想法不盡相同,但是最終達成一致的那一刻,每個人的技術(shù)思想都會得到提升。
對于DDD,我的觀點是,它是一套非常優(yōu)秀的能提升個人認(rèn)知高度的方法論。注意,我說的是個人認(rèn)知,不僅是它所帶來的業(yè)務(wù)和團隊價值(它所帶來的業(yè)務(wù)和團隊價值會在下面講)。它的戰(zhàn)略設(shè)計方法論能很好提升技術(shù)人員的全局視野,它的戰(zhàn)術(shù)設(shè)計方法論也能強化個人的技術(shù)細節(jié)把控力和結(jié)構(gòu)性思維。除此之外,好的DDD設(shè)計也反映出一個技術(shù)人員對于業(yè)務(wù)的理解力,往往優(yōu)秀的領(lǐng)域?qū)<乙彩前雮€業(yè)務(wù)專家。
如果你一直困惑于自己究竟該如何提升技術(shù)和業(yè)務(wù)思考能力;如何提升全局視野,提升自己的結(jié)構(gòu)化思維的能力;如何在寫了這么多代碼,做了這么多需求的情況下,補充系統(tǒng)化的技術(shù)理念。如果這些疑惑點你都涉及,那么理解DDD,同時按照DDD的方式去思考和建設(shè),能夠為你帶來顯著的提升。
同時我還要說明下,因為DDD的一些概念比較抽象,會讓剛了解的同學(xué)產(chǎn)生困惑和模糊感,所以關(guān)于戰(zhàn)略和戰(zhàn)術(shù)設(shè)計部分,我都會用實際的例子來解釋?;谖业慕?jīng)驗,最簡單的解釋才是有效的,所以我會用非常白話的方式表述清楚DDD的實戰(zhàn)部分,所以大家不用擔(dān)心理解問題。
PS:我最后想了下,還是要用個完整的示例來演示下DDD的建模流程,否則光說理論體感太弱,所以文章最后部分,我結(jié)合四色建模,加上我自己的過往建模經(jīng)驗,演示了某體驗產(chǎn)品0-1建設(shè)的具體流程(暫不涉及代碼和工程部分),比較喜歡看具體示例的可以直接拖到最后一部分。
二、DDD是什么
2004年,Eric Evans在發(fā)表了一部名為《Domain Driven Design》的著作,其中提及了一套從系統(tǒng)分析到軟件設(shè)計的方法論——領(lǐng)域驅(qū)動設(shè)計,簡稱DDD,領(lǐng)域建模的思想隨即鋪展開來。
DDD設(shè)計的目標(biāo)是實現(xiàn)軟件系統(tǒng)與業(yè)務(wù)需求的高度契合,提高開發(fā)效率和質(zhì)量,同時也能更好地應(yīng)對復(fù)雜性和變化性。它強調(diào)以業(yè)務(wù)為中心,通過深入領(lǐng)域知識和建立有效的領(lǐng)域模型,來驅(qū)動軟件設(shè)計和開發(fā)的整個過程。其中幾個核心理論提煉如下:
領(lǐng)域驅(qū)動設(shè)計——軟件設(shè)計復(fù)雜性解決之道。它是為了解決復(fù)雜軟件設(shè)計的一種優(yōu)秀方案,但不是唯一。
它把所有的業(yè)務(wù)規(guī)則、定義、范圍、知識等抽象成了一個大的概念,叫做領(lǐng)域。比如用戶支付的業(yè)務(wù)場景,叫做交易域;平臺提供售后等服務(wù)叫做服務(wù)域(或客服域),還有其他諸如金融域,人效域,物流域等。
它應(yīng)對復(fù)雜性的思想,總結(jié)下來既簡單,又精煉,叫做“分而治之”。把最大化的領(lǐng)域(復(fù)雜問題)分為下層的一個個子域,同時每個子域又規(guī)定好邊界和核心實體,通過一系列的拆分、歸類、衍生,最終找到最優(yōu)解。
業(yè)務(wù)是在變的,如何從多變的業(yè)務(wù)環(huán)境中,保持內(nèi)核的穩(wěn)定性和擴展性,適應(yīng)多變的業(yè)務(wù)發(fā)展,這是應(yīng)對復(fù)雜性的第二個關(guān)鍵點。領(lǐng)域模型是一套貫穿了整個軟件,從設(shè)計到交付的生命周期的方法論,因為他的共識性,可以讓開發(fā)、產(chǎn)品、架構(gòu)師圍繞著統(tǒng)一的模型去設(shè)計和探討,不至于走樣。
領(lǐng)域模型的圖形表達方式,在實操上除了實體模型圖的表達比較特殊,其他的時序、狀態(tài)機、流程圖其實無特殊性。
領(lǐng)域模型是業(yè)務(wù)的抽象,這點很關(guān)鍵,同時領(lǐng)域模型的設(shè)計應(yīng)該是基于現(xiàn)實,但不等于現(xiàn)實。
評論領(lǐng)域模型設(shè)計是否優(yōu)秀的方法很簡單:5年后,剔除掉所有的增值域,第一版建設(shè)的域模型是否還符合優(yōu)秀的穩(wěn)定性、擴展性和靈活性。
領(lǐng)域模型不是所有的軟件工程都適合,我經(jīng)常會問面試者一個問題,一個FBI(數(shù)據(jù)看板系統(tǒng)),一個電商交易系統(tǒng),它們都適合用DDD嗎,為什么?
三、DDD和MVC的比較
在講解DDD的價值前,我們先看下DDD這個理念提出來之前,經(jīng)典的MVC開發(fā)模式。
如圖,Controller負(fù)責(zé)業(yè)務(wù)邏輯的處理,Model代表和持久層交互的數(shù)據(jù)模型,View層負(fù)責(zé)視圖展示。MVC架構(gòu)其實很精粹,清晰,對于業(yè)務(wù)邏輯并不復(fù)雜,單一化的場景其實效率是很高的。但是隨著業(yè)務(wù)的多變性和不斷復(fù)雜化,MVC架構(gòu)就會暴露以下問題:
MVC架構(gòu)沒有邊界劃分的概念和規(guī)范,在復(fù)雜的業(yè)務(wù)場景下會造成盤根交錯的邏輯依賴,同時隨著業(yè)務(wù)場景的不復(fù)雜化,代碼意圖會逐漸模糊,維護成本增加,對于系統(tǒng)的穩(wěn)定性也會帶來挑戰(zhàn)。
MVC僅反映軟件架構(gòu)的分層,不定義業(yè)務(wù)語義的抽象和表達,對于業(yè)務(wù)知識的沉淀和復(fù)用性來說,不太友好。
MVC分割了數(shù)據(jù)和行為的表達,Model層(pojo)定義數(shù)據(jù),Service層表述行為,會造成業(yè)務(wù)邏輯的首尾分離。
于是,為了解決以上問題,DDD的概念被提了出來。
四、DDD究竟能帶來什么價值
1. 業(yè)務(wù)(團隊)價值
(1)統(tǒng)一語言
同一團隊,同一語言。這里的團隊不僅是指技術(shù)團隊,也包含業(yè)務(wù)、運營、產(chǎn)品、質(zhì)量等。所有角色的認(rèn)知語言統(tǒng)一化,不論是在溝通、設(shè)計、文檔編寫、畫圖、編碼等任何環(huán)節(jié),都使用同一種語言,保證效率的最大化。
(2)清晰的邊界定義
DDD的非常重要的一個概念,就是劃分領(lǐng)域和子域的邊界,通過邊界和核心實體的聚合與建立,定義出清晰的業(yè)務(wù)范圍,避免邊界紛爭(技術(shù)人員應(yīng)該經(jīng)常會遇到,明明這個事情屬于A范圍,但是卻要B的應(yīng)用改造;明明很基礎(chǔ)的一個通用能力,AB兩個應(yīng)用各做了一個,改造成本*2,同時還要兜底解決一系列不一致問題)。
(3)領(lǐng)域能力沉淀和復(fù)用
業(yè)務(wù)能力的可復(fù)用性,是衡量軟件架構(gòu)設(shè)計優(yōu)秀與否的一個重要指標(biāo),強大的復(fù)用能力,對于研發(fā)效能和業(yè)務(wù)效能的提升具有很好的正向作用。DDD通過領(lǐng)域能力的沉淀和打磨,使業(yè)務(wù)和模型統(tǒng)一,也使領(lǐng)域能力得以傳承。
(4)面向業(yè)務(wù)建模
基于現(xiàn)實業(yè)務(wù)做業(yè)務(wù)領(lǐng)域的抽象,切分?jǐn)?shù)據(jù)和領(lǐng)域(業(yè)務(wù))模型,從而降低整個軟件復(fù)雜度。開發(fā)人員應(yīng)始終聚焦于領(lǐng)域模型,而不是傳統(tǒng)理念中關(guān)注數(shù)據(jù)層和接口層的設(shè)計。
(5)設(shè)計和代碼的等價
設(shè)計即代碼,代碼直觀表現(xiàn)設(shè)計。好的DDD設(shè)計,在方案上一句代碼都沒有,但是卻已經(jīng)清晰的表明了所有的代碼實現(xiàn)(尤其在代碼結(jié)構(gòu)、層次、定義上會感受得更清楚)。
2. 個人價值
(1)提升全局視野
做領(lǐng)域建模的第一階段是戰(zhàn)略設(shè)計,其實就是在做全局業(yè)務(wù),流程的梳理,同時對于其中的域劃分都要有清晰的標(biāo)準(zhǔn)。要梳理清楚剛說的幾項內(nèi)容,沒有全局的認(rèn)知和思考是不行的,同時當(dāng)負(fù)責(zé)人員梳理完這一階段的時候,潛移默化的其實就已經(jīng)提升了個人的全局意識和視野了。這也就是我們常說的一個領(lǐng)域?qū)<?,也往往是半個業(yè)務(wù)專家的由來了。
(2)提升業(yè)務(wù)sense
這個和團隊價值中“面向業(yè)務(wù)建?!本邆鋸婈P(guān)聯(lián)性,因為DDD是面向業(yè)務(wù)建模為出發(fā)點,所以一切都需要在具備優(yōu)秀的業(yè)務(wù)敏感度下進行,沒有業(yè)務(wù)sense也做不好DDD,而做好了DDD,業(yè)務(wù)sense也一定不錯。同時在某大廠接觸DDD前期,讓我收益最大的一句話是——“業(yè)務(wù)不吃透,不聊技術(shù)”。
(3)構(gòu)建體系化思維
體系化思維強調(diào)將事物、概念和關(guān)系組織成一個有條理、有結(jié)構(gòu)的整體,能夠更全面、深入地理解問題本質(zhì),提供更有效的解決方案(體系化思維其實也是結(jié)構(gòu)化思維的一種呈現(xiàn),在這里推薦一本書《金字塔思維》,講的是從過程化思維向結(jié)構(gòu)化思維升級的一些方式方法)。DDD的幾個核心概念,要求負(fù)責(zé)人不能只從單點去看問題,需要從線和面上去深入理解,這點能很好的幫助個人去構(gòu)建體系化思維的能力。
五、DDD缺點
任何事物都一定存在正反兩面,雖然DDD在構(gòu)建復(fù)雜軟件模型上,有天然的優(yōu)勢,但同時這套方法論的缺點也非常明顯:
邏輯相對簡單的業(yè)務(wù)和產(chǎn)品(比如一些小型公司的內(nèi)部OA系統(tǒng)),用傳統(tǒng)的MVC架構(gòu)會更適合,構(gòu)建也更快速。
非業(yè)務(wù)形態(tài)產(chǎn)品和應(yīng)用并不適合,比如bigdata。這類應(yīng)用和業(yè)務(wù)專注于數(shù)據(jù)層的交互和適配,并無強業(yè)務(wù)語義類訴求,而DDD最關(guān)鍵的一部分就是業(yè)務(wù)領(lǐng)域的抽象和包裝,切記,它解決的是負(fù)責(zé)業(yè)務(wù)問題。
六、核心概念
DDD戰(zhàn)略+戰(zhàn)術(shù)全景圖
DDD的核心理念有兩部分,“戰(zhàn)略設(shè)計,戰(zhàn)術(shù)設(shè)計”,理解清楚了這兩部分,其實DDD的精髓也就理解了。但是在這之前,先簡單描述下DDD這套方法論的一個完整設(shè)計流程。
首先第一步,根據(jù)業(yè)務(wù)訴求,提煉出整體的業(yè)務(wù)流程,同時拆解出里面的關(guān)鍵事件,角色,參與者等核心實例。整個拆解和梳理的方法論,目前業(yè)界有一些比較成熟的,比如事件風(fēng)暴,四色建模法等,后面單獨講。
提煉完整個業(yè)務(wù)流程后,進入戰(zhàn)略設(shè)計階段,這個階段主要是從全局和頂層的視角,把整個業(yè)務(wù)語義轉(zhuǎn)換為結(jié)構(gòu)化分層。通過領(lǐng)域和子域的劃分,同時結(jié)合通用域、支撐域、限界上下文等設(shè)計,分解問題復(fù)雜度,其實就是前面說到的“分而治之”的思想。
接下來就會到具體的戰(zhàn)術(shù)設(shè)計階段,通過前面的戰(zhàn)略設(shè)計階段,已經(jīng)把整個領(lǐng)域、邊界、上下文等關(guān)鍵模塊都梳理完成,現(xiàn)在就是從各個域中再次拆解更細粒度的模塊,去指導(dǎo)最終的編碼實現(xiàn),這些更細粒度的模塊包括實體、聚合、聚合根等。
最后就到了編碼實現(xiàn)階段,DDD有一個關(guān)鍵價值,叫做“設(shè)計即實現(xiàn)”,所以在戰(zhàn)術(shù)階段的設(shè)計,理論上是可以直接作用于代碼的分層結(jié)構(gòu),如果架構(gòu)和戰(zhàn)術(shù)階段有出入,說明之前的設(shè)計有問題,可以復(fù)盤重新推演。
以上就是最基本的一個的設(shè)計流程,要完整的理解這個流程,“戰(zhàn)略設(shè)計,戰(zhàn)術(shù)設(shè)計”兩個階段尤其關(guān)鍵,接下來先說明戰(zhàn)略設(shè)計(戰(zhàn)略方法論)的核心概念。同時整體的戰(zhàn)略和戰(zhàn)術(shù)設(shè)計,光描述有點抽象,我提煉了下整個DDD的分層架構(gòu),只保留了最核心的部分,后面理解完了整個理論知識和部分實戰(zhàn)后,可以回來再看這張圖,會更有體感。
1. 戰(zhàn)略方法論
(1)領(lǐng)域
領(lǐng)域(Domain)是指業(yè)務(wù)問題的特定領(lǐng)域范圍,它涉及到特定業(yè)務(wù)的規(guī)則、概念、業(yè)務(wù)流程等。領(lǐng)域是對業(yè)務(wù)問題進行分解和組織的基本單位。
(2)子域
子域(Subdomain)是指在一個大的領(lǐng)域中劃分出的相對獨立的子領(lǐng)域,它通常代表一個獨立的業(yè)務(wù)領(lǐng)域,具有特定的業(yè)務(wù)邏輯和功能需求。子域可以是整個系統(tǒng)的一個功能模塊,也可以是一個獨立的業(yè)務(wù)流程。
(3)通用域
通用域(Generic Domain)是指與特定業(yè)務(wù)領(lǐng)域無關(guān)的通用功能,它是在整個領(lǐng)域中被多個子域所共享和復(fù)用的功能。通用域包括一些通用的服務(wù)、工具、組件等,用于支持多個子域的實現(xiàn)。
(4)支撐域
“支撐域”(Supporting Domain)指的是與核心業(yè)務(wù)的實現(xiàn)和發(fā)展密切相關(guān)的非業(yè)務(wù)功能。這些支撐域可以包括安全認(rèn)證、用戶管理、日志記錄等在整個系統(tǒng)中被多個子域所共享和使用的基礎(chǔ)設(shè)施功能。支撐域和通用域概念上有些類似,區(qū)分他們的標(biāo)準(zhǔn)簡單歸納下的話,支撐域是由外域提供的能力,通用域是本域提供。
(5)限界上下文
“限界上下文”(Bounded Context)則是DDD中的一個重要概念,用于劃分和隔離不同的領(lǐng)域或子系統(tǒng)。一個限界上下文指的是一個明確定義了特定業(yè)務(wù)領(lǐng)域所圍繞的邊界,它包含了領(lǐng)域模型、業(yè)務(wù)規(guī)則、相關(guān)的領(lǐng)域服務(wù)和持久化邏輯等。不同的限界上下文之間可以是相互隔離的,每個上下文內(nèi)部有其自己的語言和模型,但是它們之間也需要通過明確定義的接口進行通信。
(6)小結(jié)
在DDD戰(zhàn)略設(shè)計中,首先需要進行領(lǐng)域建模,即通過與領(lǐng)域?qū)<业暮献骱蜕钊腩I(lǐng)域知識的研究,將業(yè)務(wù)需求轉(zhuǎn)化為領(lǐng)域模型。接下來,根據(jù)領(lǐng)域模型進行軟件設(shè)計和開發(fā),實現(xiàn)業(yè)務(wù)邏輯和功能。在整個過程中,需要保持與業(yè)務(wù)專家的緊密合作,不斷迭代和驗證領(lǐng)域模型的準(zhǔn)確性和有效性。下圖是體驗VOC產(chǎn)品在做設(shè)計時的戰(zhàn)略架構(gòu):
某體驗產(chǎn)品的整體戰(zhàn)略設(shè)計
2. 戰(zhàn)術(shù)方法論
(1)實體
代表領(lǐng)域中具有唯一身份和生命周期的對象。實體有自己的行為和狀態(tài),并通過標(biāo)識屬性進行唯一標(biāo)識。
- 貧血模型:貧血模型是指領(lǐng)域?qū)ο笾痪哂袛?shù)據(jù)屬性,缺乏相關(guān)的行為邏輯。在貧血模型中,業(yè)務(wù)邏輯主要存在于服務(wù)層或者其它外部對象中,領(lǐng)域?qū)ο髢H被視為被動的數(shù)據(jù)容器。這種模型在領(lǐng)域驅(qū)動設(shè)計(DDD)中被認(rèn)為是反模式,因為它無法更好地體現(xiàn)領(lǐng)域的核心概念和規(guī)則。
- 失血模型:和貧血模型相似,指的是領(lǐng)域?qū)ο笕鄙贅I(yè)務(wù)邏輯和領(lǐng)域行為,以至于數(shù)據(jù)和行為的重要部分都被丟失。這種模型經(jīng)常出現(xiàn)在面向?qū)ο蟮拈_發(fā)中,尤其是基于關(guān)系數(shù)據(jù)庫的實現(xiàn)中。
- 充血模型:充血模型是在領(lǐng)域?qū)ο笾谐浞煮w現(xiàn)了業(yè)務(wù)邏輯和行為的模型。充血模型積極地包含了數(shù)據(jù)和相關(guān)的行為邏輯,它使得領(lǐng)域?qū)ο竽軌蚋玫胤庋b與之相關(guān)的業(yè)務(wù)規(guī)則和行為,提供了更加一致和抽象的編程接口。充血模型是DDD中推崇的設(shè)計模式,使得領(lǐng)域?qū)ο竽軌虺蔀闃I(yè)務(wù)規(guī)則的中心。
- 漲血模型:漲血模型是指在充血模型的基礎(chǔ)上,進一步將領(lǐng)域?qū)ο蟮臓顟B(tài)和行為擴展到前沿技術(shù)和新的設(shè)計模式中(有些理念力,漲血模型和充血模型的區(qū)別在于,漲血模型添加了持久層的行為)。
充血模型雖然是DDD中推崇的設(shè)計模式,通過領(lǐng)域?qū)嶓w,一些關(guān)鍵行為和邏輯其實也能一起拿到了,但是在我的經(jīng)驗中,我更喜歡使用貧血+充血的混合模型(或者叫充血模型的簡化版),因為這里涉及到一個標(biāo)準(zhǔn)的建立問題,如果只用充血模型的話,哪些行為和邏輯該下方到接口服務(wù)層,哪些又該收攏到實體中,這里面每個人的理念不一樣。而我的標(biāo)準(zhǔn)是,涉及到持久層和復(fù)雜行為都下放到服務(wù)層,簡單行為放到實體模型中。這樣有個好處,隨著業(yè)務(wù)的發(fā)展,如果只用充血模型,你的實體會越來越臃腫;如果只有貧血模型,自身又太單薄。所以一部分行為下放到服務(wù)層,我可以更細粒度的拆分服務(wù)接口,保證更優(yōu)良的邊界和代碼可讀性,同時也保證了模型自身的健壯性。
最后,不論哪種模型,都沒有絕對的好壞,能夠很好的定義出設(shè)計標(biāo)準(zhǔn),同時基于自己的理解設(shè)計出符合業(yè)務(wù)擴展的實體和服務(wù)就是好的模型。
(2)值對象
代表領(lǐng)域中沒有唯一標(biāo)識的對象,它的相等性是通過值的相等性來判斷的,而不是通過標(biāo)識。比如地址信息,手機號碼,標(biāo)簽屬性等。
(3)聚合根
聚合根是聚合的根實體,它是一組相關(guān)對象的入口點,管理著聚合內(nèi)其他對象的生命周期和完整性。聚合根通過封裝聚合內(nèi)部的對象,并定義了聚合的一致性邊界,確保聚合內(nèi)的對象之間的關(guān)系和約束得到維護。外部對象只能通過聚合根來訪問和操作聚合內(nèi)的對象,從而保證了聚合的完整性和一致性。
(4)聚合
一組相關(guān)對象的集合,由一個根實體(Aggregate Root)作為集合的入口點。聚合定義了一致性邊界,通過聚合根管理其內(nèi)部對象的生命周期和完整性。
(5)領(lǐng)域服務(wù)
代表領(lǐng)域中的一些操作或業(yè)務(wù)邏輯,它不屬于特定的實體或值對象,而是為解決特定領(lǐng)域問題提供通用的服務(wù)。
(6)領(lǐng)域事件
代表領(lǐng)域中的發(fā)生的重要事件,可以用于通知其他領(lǐng)域?qū)ο蠡蚩缦藿缟舷挛倪M行解耦和協(xié)作。
(7)資源庫
資源庫是用于管理領(lǐng)域?qū)ο蟮膭?chuàng)建、更新和持久化的接口。它實現(xiàn)了將領(lǐng)域?qū)ο髲膬?nèi)存中存儲到持久化介質(zhì)(如數(shù)據(jù)庫)中,以及從持久化介質(zhì)中檢索對象并還原為領(lǐng)域?qū)ο蟮墓δ?。資源庫隱藏了底層的數(shù)據(jù)訪問細節(jié),提供了一致的接口和抽象,使得領(lǐng)域?qū)ο蟮脑L問和持久化變得簡單和統(tǒng)一。
(8)小結(jié)
DDD戰(zhàn)術(shù)設(shè)計是在DDD戰(zhàn)略設(shè)計的基礎(chǔ)上,著重于解決如何將業(yè)務(wù)需求和設(shè)計模型有效地映射和實現(xiàn)的具體方法和技術(shù)。它的目標(biāo)是根據(jù)戰(zhàn)略設(shè)計的指導(dǎo),通過合理的領(lǐng)域建模和架構(gòu)設(shè)計,將領(lǐng)域問題轉(zhuǎn)化為高內(nèi)聚、低耦合的代碼實現(xiàn),從而更好地滿足業(yè)務(wù)需求。
某體驗產(chǎn)品協(xié)同域的戰(zhàn)術(shù)設(shè)計
七、領(lǐng)域建模
到這里,DDD的核心概念基本已經(jīng)講述完。基于以上的核心概念,接下來就是DDD最關(guān)鍵的部分——領(lǐng)域建模,它的目的歸納起來就一句話:提煉業(yè)務(wù)知識,形成統(tǒng)一語言,沉淀領(lǐng)域模型。
領(lǐng)域建模的優(yōu)秀與否,可以說直接決定著本次設(shè)計的成敗,因為一旦發(fā)生建模邊界不清晰,實體劃分錯亂,核心屬性沒有遵守開閉原則等問題,雖然當(dāng)下可以正常交付業(yè)務(wù),但是對于整個項目的后續(xù)發(fā)展可以說是災(zāi)難性的(之前接觸過一個系統(tǒng),因為一個實體的關(guān)鍵屬性在最初設(shè)計時,沒有制定標(biāo)準(zhǔn)規(guī)范,語義不統(tǒng)一,造成使用混亂。最后不得以重新設(shè)計,結(jié)果造成上游的業(yè)務(wù)使用方全要配合改造回歸,不僅改造成本巨大,同時引發(fā)了P級故障)。
我最開始說的“優(yōu)秀的領(lǐng)域?qū)<乙彩前雮€業(yè)務(wù)專家”,其實就體現(xiàn)在這一環(huán)節(jié),好的領(lǐng)域建模,前提一定是深刻理解完業(yè)務(wù)的,同時再次強調(diào)下這個觀點:領(lǐng)域建模,是基于現(xiàn)實,但不完全等價于現(xiàn)實。以下是領(lǐng)域建模的交付物:
- 領(lǐng)域模型:包含領(lǐng)域?qū)ο?、屬性、關(guān)系、行為、邊界范圍等各個方面,用于描述業(yè)務(wù)的本質(zhì),這也是最重要的產(chǎn)出物。
- 用例圖:用于明確系統(tǒng)的功能。
- 數(shù)據(jù)模型:描述系統(tǒng)的數(shù)據(jù)結(jié)構(gòu)和關(guān)系,包括實體關(guān)系模型、關(guān)系數(shù)據(jù)庫模型等。
- 狀態(tài)圖:用于描述系統(tǒng)各個狀態(tài)及其轉(zhuǎn)移條件。
- 活動圖:用于描述系統(tǒng)流程中的各個活動及其關(guān)系。
- 序列圖:描述系統(tǒng)中各個對象之間的交互過程和消息傳遞序列。
- 架構(gòu)模型:包含系統(tǒng)的物理和邏輯結(jié)構(gòu),包括組件、模塊、接口等。
1. 事件風(fēng)暴建模
事件風(fēng)暴(Event Storming)是一種用于快速探索、理解和設(shè)計領(lǐng)域模型的合作工作坊技術(shù)。
它是由Alberto Brandolini于2013年提出的。事件風(fēng)暴通過團隊協(xié)作的方式,以用戶的視角來討論和探索整個業(yè)務(wù)流程。參與者將自己的理解和知識通過貼在墻上的便利貼上表達出來,核心會圍繞著事件去編排整個業(yè)務(wù)流程。事件可以是任何對業(yè)務(wù)、系統(tǒng)或用戶有意義的事情,包括用戶觸發(fā)的操作、系統(tǒng)的狀態(tài)轉(zhuǎn)換、通信和消息傳遞等。這些事件以一種自頂向下的方式,以時間線的形式貼在墻上。隨著討論的深入,團隊可以探索和辨識出各種概念、實體、聚合根、資源庫、上下文邊界、業(yè)務(wù)流程和事件的關(guān)聯(lián)關(guān)系。這有助于更全面地理解整個領(lǐng)域的復(fù)雜性,并為后續(xù)的領(lǐng)域建模和業(yè)務(wù)流程設(shè)計提供線索和洞察。
事件風(fēng)暴具有高度可視化的特點,能夠促進團隊之間的溝通和共享知識。它也可以幫助團隊快速理解現(xiàn)有系統(tǒng)的復(fù)雜性,并為系統(tǒng)的重構(gòu)和演進提供指導(dǎo)。此外,事件風(fēng)暴還可以用作需求分析、業(yè)務(wù)流程優(yōu)化和團隊協(xié)作的工具。
需要注意的是,事件風(fēng)暴并非一種正式的建模方法,而是一種協(xié)作工作坊技術(shù)。它可以結(jié)合其他建模方法(如領(lǐng)域驅(qū)動設(shè)計)和工具(如UML、流程圖等)來進一步詳細和完善領(lǐng)域模型。在事件風(fēng)暴中,沒有確定的固定語法,但是有一些常用的技術(shù)和簡寫符號,用于記錄和表示不同的業(yè)務(wù)事件和概念。
以下是一些常見的事件風(fēng)暴語法和符號:
- 用戶角色:通常使用人物標(biāo)簽或者角色名字來代表具體的用戶,例如 “客戶”、“管理員”等。
- 業(yè)務(wù)事件:使用動詞來描述業(yè)務(wù)活動或事件,如“創(chuàng)建訂單”、“審核申請”、“發(fā)貨”等。
- 識別的領(lǐng)域概念:在事件風(fēng)暴中,通過寫在有色便利貼上來標(biāo)記關(guān)鍵的業(yè)務(wù)概念,例如“訂單”、“產(chǎn)品”、“支付”等。這些概念有助于團隊識別和理解業(yè)務(wù)的重要方面。
- 粘貼便利貼:使用不同顏色的便利貼來表示不同的類型或者關(guān)注點。例如,可以使用黃色便利貼表示業(yè)務(wù)活動和概念,使用藍色便利貼表示抽象的過程和規(guī)則,使用粉色便利貼表示意見、問題或待解決的事項。
- 關(guān)系箭頭:可以使用箭頭來表示業(yè)務(wù)事件之間的關(guān)系,例如表示事件的先后順序、依賴關(guān)系等。
- 事件風(fēng)暴的語法并不是嚴(yán)格規(guī)定的,而且可以根據(jù)團隊的需要和偏好進行適當(dāng)?shù)恼{(diào)整。重點是通過快速的頭腦風(fēng)暴,來協(xié)作識別和探索業(yè)務(wù)領(lǐng)域的關(guān)鍵事件,以促進團隊的共享理解和協(xié)作。
事件風(fēng)暴的本質(zhì)上是通過腦暴的方式,圍繞關(guān)鍵領(lǐng)域事件串聯(lián)整個業(yè)務(wù)場景的生命周期,通過發(fā)散去收集,通過收斂去提煉,要真正把這個方法用好,有兩個關(guān)鍵點:
主持人的綜合能力,尤其體系在最后的收斂上,是否能把如此多的腦暴信息,提煉成關(guān)鍵點。
事件風(fēng)暴是一個比較“重”的方法,對于一些0-1建設(shè)的大型項目(1000人日以上)比較適合,一些中小型項目有些“過渡設(shè)計”。
這個方法大家了解下就行,我不展開講,實戰(zhàn)中不常用
2. 四色建模
Peter Coad在他的書《Java Modeling In Color With UML》中,提出了一種與顏色相關(guān)的建模方法,被稱為Color Modeling。這種方法使用顏色作為一種可視化技巧,用于在領(lǐng)域模型中表示不同的對象和概念。它的目的是通過使用顏色來幫助開發(fā)者更清晰地理解和傳達模型的結(jié)構(gòu)和關(guān)系。
四色建模的思想是通過使用不同的顏色來標(biāo)識不同的概念和角色,以增加模型的可讀性和可理解性。每種顏色都代表一個特定的責(zé)任或角色,通過這種方式可以更好地定義和呈現(xiàn)領(lǐng)域模型的各個組成部分,使得開發(fā)團隊在理解和溝通模型時更加容易。
需要注意的是,四色建模并非DDD的核心概念或原則,它更多地是作為一種模型建立和可視化的輔助工具。DDD更關(guān)注于如何基于通用語言、領(lǐng)域模型和限界上下文等概念進行軟件系統(tǒng)的設(shè)計與開發(fā)。
以下是四色模型的語法:
- 時標(biāo)原型(Moment-Interval Archetype,也稱業(yè)務(wù)關(guān)鍵時刻,簡稱MI):表示事物在某個時刻或某一段時間內(nèi)發(fā)生的,如銷售訂單、收款記錄等,使用淺紅色表示。
- PPT原型(Part-Place-Thing Archetype,人/事/物原型,簡稱PPT):表示參與扮演不同角色的人或事物,如商品、賬戶、店鋪等,使用淺綠色表示。
- 角色原型(Role Archetype,簡稱ROLE):抽象了一種參與方式,由人或組織機構(gòu)、地點或物品來承擔(dān),如客戶、商家、財務(wù)組織等,使用淺黃色表示。
- 描述原型(Description Archetype,簡稱DESC):對上述顏色表示的內(nèi)容進行解釋,用于分類或者描述建模過程中產(chǎn)生的數(shù)據(jù)、事件或者活動,使用淺藍色表示。
用一句話來概括四色原型就是:一個什么樣的人或物品以某種角色在某個時刻或某段時間內(nèi)參與某個活動。其中“什么樣的”就是DESC,“人或物品”就是PPT,“角色”就是ROLE,而“某個時刻或某個時間段內(nèi)的某個活動”就是MI。按照這個邏輯,整體流程如下:
- 建立時標(biāo)原型:尋找需要追溯的事件,根據(jù)追溯事件尋找足跡。
- 建立PPT原型:豐富模型,尋找時標(biāo)原型周圍的人/事/物,使它可以更好地描述業(yè)務(wù)概念。
- 建立角色原型:進一步從中抽象出可以參與到不同流程中去的角色。
- 建立描述原型:把一些信息用描述對象補足。
八、建模實例
就結(jié)合剛說的四色建模來演示,否則光說還是不夠有體感。我以目前負(fù)責(zé)的“某體驗平臺(簡稱VOC)”結(jié)合四色建模法來具體演示下。
1. 梳理業(yè)務(wù)流程
首先描述下VOC的背景和目的,一句話:
站在橫向和全局的視角,快速發(fā)現(xiàn)用戶在得物系產(chǎn)品使用過程中發(fā)生的體驗問題,同時及時定位,解決該問題,最終提升用戶體驗。
以下是之前某大廠的體驗中臺的目標(biāo)描述,和VOC類似。
為了能達成上述目標(biāo),我們究竟應(yīng)該怎么做,或者說具備什么樣的能力呢,總結(jié)下來其實是以下幾點:
具備收集用戶所有原始“聲音”的能力,否則我們無法從全局的角度去分析這個事情,這里的原聲渠道需要盡可能多的涵蓋用戶想表達訴求的入口,才能全面,比如在線咨詢、熱線咨詢、工單、評價等。
有了聲音之后,我們需要具備分析聲音,同時通過聲音提煉出具體問題的能力,讓分析人員能夠快速精準(zhǔn)的判別用戶的問題是什么。
同時平臺也應(yīng)該具備快速及時的前置發(fā)現(xiàn)問題的能力,把這些重要的、緊急的問題通知到關(guān)鍵人員手上,讓他們第一時間知曉。
最后,不管是主動分析出問題,還是收到了重要的問題通知,都應(yīng)該立即著手處理這些問題。同時因為這些問題涉及的業(yè)務(wù),bu,歸屬都不盡相同,所以處理的方案和流程也應(yīng)該體現(xiàn)不同,這也衍生出在協(xié)作處理過程中,鏈接的上下游平臺應(yīng)該會非常多,處理動作和內(nèi)容會很豐富。
根據(jù)以上的分析思路,我們可以把整體的業(yè)務(wù)流程梳理出來,同時結(jié)合四色建模法,我們把除DESC的其他關(guān)鍵元素體現(xiàn)到流程里(為了便于理解,我畫的是比較粗的流程,實際流程會比這個復(fù)雜):
體驗VOC產(chǎn)品業(yè)務(wù)流程
從圖中可以明顯看出來,這個流程的關(guān)鍵四色要素:
- 時標(biāo)原型:用戶原聲、原聲問題明細、預(yù)警單等,表述某一時刻產(chǎn)生的關(guān)鍵事件,一般是運行態(tài)的實體。同時基于VOC的業(yè)務(wù),我們分別劃分了3個階段:分析問題、定位問題、解決問題。同時結(jié)合上面的思考,最關(guān)鍵的幾個時標(biāo)原型分別是分析階段的用戶原聲,定位階段的預(yù)警單,解決階段的協(xié)同單(按照戰(zhàn)術(shù)方法論,這3個時標(biāo)原因就是聚合根)。
- PPT原型:數(shù)據(jù)渠道、分析視圖、問題標(biāo)簽?zāi)0宓龋话闶桥渲脩B(tài)或維度相關(guān)實體。
- 角色原型:系統(tǒng)、運營管理員、分析師等,這塊比較好理解,使用產(chǎn)品的角色(一般可以不把系統(tǒng)角色放進去,這里放上去是為了便于理解)。
有了這個基本的業(yè)務(wù)流程和關(guān)鍵要素后,接下來進入概念模型的設(shè)計階段。
2. 建模-概念模型
首先什么是概念模型,一句話總結(jié):概念模型是一個高層次的抽象模型,獨立于具體實現(xiàn)的領(lǐng)域模型,它關(guān)注業(yè)務(wù)領(lǐng)域的核心概念和關(guān)系,以及團隊之間的共享理解。
一般我們做建模設(shè)計的時候,很多經(jīng)驗豐富的領(lǐng)域?qū)<視赃^這一環(huán)節(jié),直接抵達領(lǐng)域模型的建模階段。當(dāng)然,這并無任何不妥,因為我們最終在做軟件開發(fā)和編碼的時候,必然是基于具體的領(lǐng)域模型去設(shè)計的,但是概念模型對于整體建模流程來說,任然非常重要,主要體現(xiàn)在以下幾點:
概念模型因為是更高層次的抽象,所以只表述核心的概念和關(guān)系,不表述細節(jié)和完整實體,所以會更簡單,清晰。
團隊之間交流共享時,尤其是在和業(yè)務(wù),產(chǎn)品同學(xué)交流時,他們往往不會太過關(guān)注細節(jié),用概念模型來交流理解會更合適。
概念模型一般用在一級域的設(shè)計上,它必須要體現(xiàn)全局性,整體性。所以它是具備方向上的指導(dǎo)意義,我建議在新的一級域項目建設(shè)初期,一定要做概念模型的建模(像交易、商品、營銷、體驗、客服這些都屬于一級域)。
回到主線,基于第一步我們梳理完的業(yè)務(wù)流程和四色要素,我們做下編排,圍繞著上述3個關(guān)鍵時標(biāo)原型為核心,結(jié)合其他幾個要素和關(guān)系,即可得到體驗VOC的完整概念模型。
某體驗產(chǎn)品概念模型
3. 建模-領(lǐng)域模型
在完成概念模型的設(shè)計后,終于到了我們最終的環(huán)節(jié),也是建模流程里最重要的階段——領(lǐng)域建模。具體的領(lǐng)域模型是在概念模型的基礎(chǔ)上進行具體的實現(xiàn),除了表述清楚核心概念和關(guān)系外,還需要能夠表達非核心的實體關(guān)系的能力,同時它還是指導(dǎo)技術(shù)實現(xiàn)的標(biāo)準(zhǔn)。
基本上完成這個階段后,微服務(wù)拆分、代碼架構(gòu)的設(shè)計、模塊劃分、核心流程也就確定了。
我們做領(lǐng)域建模時,一般會按照一級子域做拆分,一般一級子域代表了一個完整的業(yè)務(wù)域,獨立解決一類業(yè)務(wù)問題。參考“體驗VOC產(chǎn)品的整體戰(zhàn)略設(shè)計”部分,我們劃分的是洞察子域,協(xié)同子域,預(yù)警子域和問題子域,所以理論上會拆分4個微服務(wù)應(yīng)用,同時各自去做自己子域的領(lǐng)域建模。
下面我例舉其中的協(xié)同子域來做演示。整體的建模思路如下:
第一步:定義解決標(biāo)準(zhǔn)。
首先,協(xié)同域的目標(biāo)是高效的助力業(yè)務(wù)解決問題,那邊這里就涉及到如何解決,用什么樣的方案解決,解決的流程是怎么樣的,誰來解決。首先要確定這個解決標(biāo)準(zhǔn),我們抽象為“協(xié)同方案”,他的核心就是制定解決標(biāo)準(zhǔn),包括我剛描述的那一系列要解決的問題。
第二步,根據(jù)解決標(biāo)準(zhǔn),定義執(zhí)行標(biāo)準(zhǔn)。
有了解決標(biāo)準(zhǔn)后,具體如何解決,這個時候我們就需要有個根據(jù)解決標(biāo)準(zhǔn)(協(xié)同方案)履約的載體,他會按照方案上制定的流程,處理人,解決方式等去流轉(zhuǎn),這個載體我們抽象為“協(xié)同單”。
第三步,圍繞著上述兩個標(biāo)準(zhǔn),去完善域邊界,實體關(guān)鍵屬性,周邊實體和關(guān)系網(wǎng)。
比如,協(xié)同方案里的流程,我們是希望抽象成獨立模版做復(fù)用性,還是一個方案就代表了一個流程(協(xié)同流程)?協(xié)同單履約當(dāng)中的所有記錄是否需要留痕和外化,那是否需要提煉一個服務(wù)記錄的概念(協(xié)同記錄)?流轉(zhuǎn)里的內(nèi)容呈現(xiàn)是否需要單獨抽出來,做成業(yè)務(wù)可自定義配置化(表單模版)?協(xié)同方案和協(xié)同單應(yīng)該是怎么樣的關(guān)系?等等這所有的業(yè)務(wù)邏輯,都需要反映到領(lǐng)域模型中表達出來。
最終以上三步完成后,整個協(xié)同域的領(lǐng)域模型也就基本確認(rèn)好了。因為協(xié)同域不復(fù)雜,領(lǐng)域模型結(jié)合實際做了簡化,所以就沒有表示核心的領(lǐng)域服務(wù),限界上下文等概念。具體呈現(xiàn)如下:
九、總結(jié)
對于領(lǐng)域驅(qū)動設(shè)計來說,應(yīng)該遵循一個道理:不拘于形式(有點類似電影里的,劍客最高的境界是身邊無劍,但是任何所見皆可為劍的感覺)。文章的前面部分,我講了許多的概念:聚合根、值對象、領(lǐng)域事件、限界上下文等,但是實際設(shè)計開發(fā)過程中,并不需要照搬全套的體現(xiàn)出來,只要能夠表達清楚核心的實體和關(guān)系、清晰的邊界和合理的擴展性即是好的領(lǐng)域設(shè)計。當(dāng)然這篇文章主要是理論部分,實戰(zhàn)部分我還是想先把戰(zhàn)術(shù)設(shè)計的全貌先展現(xiàn)一遍,最終再做精簡,這樣可以既知全貌,卻不教條。
同時我再強調(diào)下,合格的技術(shù)專家一定是半個業(yè)務(wù)專家,而DDD這套方法論,可以讓技術(shù)同學(xué)很好的去全局理解業(yè)務(wù)形態(tài),同時以結(jié)構(gòu)化的思維去抽象業(yè)務(wù)概念,既能提升全局的認(rèn)知高度和架構(gòu)能力,也能加強細節(jié)把控力,所以它是一套很好的軟件設(shè)計復(fù)雜性解決之道。
最后回到最初那個問題,一個FBI(數(shù)據(jù)看板系統(tǒng)),一個電商交易系統(tǒng),它們都適合用DDD嗎,為什么?
本文由人人都是產(chǎn)品經(jīng)理作者【湯師爺】,微信公眾號:【架構(gòu)師湯師爺】,原創(chuàng)/授權(quán) 發(fā)布于人人都是產(chǎn)品經(jīng)理,未經(jīng)許可,禁止轉(zhuǎn)載。
題圖來自Unsplash,基于 CC0 協(xié)議。
- 目前還沒評論,等你發(fā)揮!