ddd 企业应用架构模式_灵魂拷问:用了DDD分包就是落地了领域驱动设计吗?谈谈DDD本质...
學(xué)習(xí)DDD的時(shí)候,作為開發(fā),我們更關(guān)心它在技術(shù)層面的東西,尤其體現(xiàn)在DDD的分包方式、編碼技巧等方面。
自然的,我們不禁發(fā)問,用了DDD的分包,就是實(shí)踐落地了DDD了么?
不賣關(guān)子,直接說答案,并不是。
用了DDD的分包,只能說滿足了DDD的"形",并沒有抓住DDD的"神"。DDD的神是什么,歸根到底還是面向?qū)ο?#xff0c;領(lǐng)域建模。所謂的各種分包方式本質(zhì)上還是為了滿足DDD面向?qū)ο蟮谋举|(zhì),方便開發(fā)者進(jìn)行代碼編寫而提供的一種"戰(zhàn)術(shù)設(shè)計(jì)"工具。
要深入討論這個(gè)問題,我們需要花一點(diǎn)時(shí)間來學(xué)習(xí)討論一下DDD中常見的幾種分包。
DDD分包概述
基于DDD的分包主要有兩大流派:分層架構(gòu)以及六邊形架構(gòu)。
分層架構(gòu)以四層架構(gòu)為主,基于四層架構(gòu)又誕生出衍生的五層架構(gòu)、六層架構(gòu)等等(限于篇幅以及討論重點(diǎn),本文中我們只討論四層架構(gòu))。
六邊形架構(gòu)出自 Robert C Martin(沒錯(cuò),就是傳說中的鮑勃大叔)提出的整潔架構(gòu),后來者不斷探索,又衍生出了洋蔥架構(gòu)。
這個(gè)過程可謂是百家爭鳴。實(shí)際開發(fā)中,最為我們熟知的當(dāng)屬四層架構(gòu)與六邊形架構(gòu)了,其余的各種架構(gòu)都是基于這兩種架構(gòu)方式的變體。
四層分層架構(gòu)
四層架構(gòu)的分層如下圖:
從上往下依次為:
|-userinterface 用戶界面層/表示層|-application 應(yīng)用層|-domain 領(lǐng)域?qū)觸-infrastructure 基礎(chǔ)設(shè)施層我們對(duì)這幾層的主要功能逐個(gè)分析:
User Interface?為用戶界面層(或表示層),負(fù)責(zé)為用戶做信息展示以及對(duì)用戶輸入的命令進(jìn)行解釋與輸出。這里指的用戶可以是另一個(gè)計(jì)算機(jī)系統(tǒng),不一定是使用用戶界面的人。
Application?為應(yīng)用層,應(yīng)用層主要提供了用例級(jí)別的功能。它定義了軟件要完成的任務(wù),并且借助表達(dá)領(lǐng)域概念的對(duì)象來組織并解決問題,可以理解為通過膠水粘合了各種領(lǐng)域概念。這一層所負(fù)責(zé)的工作對(duì)業(yè)務(wù)來說意義重大,也是與其它系統(tǒng)的應(yīng)用層進(jìn)行交互的必要渠道。應(yīng)用層要盡量簡單,它應(yīng)當(dāng)盡量不包含業(yè)務(wù)規(guī)則或者知識(shí),而只負(fù)責(zé)協(xié)調(diào)下一層中的領(lǐng)域?qū)ο?#xff0c;為領(lǐng)域?qū)ο蠓峙涔ぷ?#xff0c; 使它們互相協(xié)作。應(yīng)用層反應(yīng)不了業(yè)務(wù)情況的狀態(tài),但是可以表達(dá)另外一種狀態(tài),為用戶或程序顯示某個(gè)任務(wù)的進(jìn)度。
Domain?為領(lǐng)域?qū)?或模型層),負(fù)責(zé)表達(dá)業(yè)務(wù)概念,業(yè)務(wù)狀態(tài)信息以及業(yè)務(wù)規(guī)則。盡管保存業(yè)務(wù)狀態(tài)的技術(shù)細(xì)節(jié)是由基礎(chǔ)設(shè)施層實(shí)現(xiàn)的,但是反映業(yè)務(wù)情況的狀態(tài)確實(shí)是由領(lǐng)域?qū)涌刂撇⑶沂褂玫摹nI(lǐng)域?qū)邮菢I(yè)務(wù)軟件的核心,它體現(xiàn)了DDD的核心:領(lǐng)域模型。
Infrastructure?層為基礎(chǔ)實(shí)施層,它向其他層提供通用的技術(shù)能力:為應(yīng)用層傳遞消息,為領(lǐng)域?qū)犹峁┏志没瘷C(jī)制,為用戶界面層繪制屏幕組件,等等。基礎(chǔ)設(shè)施層還能夠通過架構(gòu)框架來支持四個(gè)層次間的交互模式。
說完概念,還是不夠直觀表現(xiàn)DDD四層架構(gòu)在實(shí)際開發(fā)中扮演的角色與包含的功能,稍安勿躁,我們舉幾個(gè)例子說明一下:
在實(shí)際開發(fā)中,User Interface層主要包含Restful消息處理/RPC 接口交互/消息消費(fèi)入口,配置文件解析,等等。
Application層主要是多進(jìn)程管理及調(diào)度,多線程管理及調(diào)度,多協(xié)程調(diào)度和狀態(tài)機(jī)管理,跨領(lǐng)域業(yè)務(wù)組織與交互(比如:對(duì)外調(diào)用的出口就可以在application進(jìn)行體現(xiàn),也就是所謂的防腐層),等等。
Domain層主要是領(lǐng)域模型的實(shí)現(xiàn),包括領(lǐng)域?qū)ο蟮拇_立,這些對(duì)象的生命周期管理及關(guān)系,領(lǐng)域服務(wù)的定義,領(lǐng)域事件的發(fā)布,等等。
infrastructure層主要是業(yè)務(wù)平臺(tái),編程框架,第三方庫的封裝,基礎(chǔ)算法,等等,它為上層提供了技術(shù)層面的支持,且往往與具體的業(yè)務(wù)細(xì)節(jié)無關(guān)。
六邊形架構(gòu)
六邊形架構(gòu)也稱為端口與適配器架構(gòu),一個(gè)典型的六邊形架構(gòu)如圖
六邊形每條不同的邊代表了不同類型的端口,端口要么處理輸入,要么處理輸出。對(duì)于每種外界類型,都有一個(gè)適配器與之對(duì)應(yīng),外界通過應(yīng)用層API與內(nèi)部進(jìn)行交互。
上圖中有3個(gè)客戶請(qǐng)求均抵達(dá)相同的輸入端口(適配器A、B和C),另一個(gè)客戶請(qǐng)求使用了適配器D。假設(shè)前3個(gè)請(qǐng)求使用了HTTP協(xié)議(瀏覽器、REST和SOAP等),而后一個(gè)請(qǐng)求使用了AMQP協(xié)議(比如RabbitMQ)。
端口并沒有明確的定義,它是一個(gè)非常靈活的概念。無論采用哪種方式對(duì)端口進(jìn)行劃分,當(dāng)客戶請(qǐng)求到達(dá)時(shí),都應(yīng)該有相應(yīng)的適配器對(duì)輸入進(jìn)行轉(zhuǎn)化, 然后端口將調(diào)用應(yīng)用程序的某個(gè)操作或者向應(yīng)用程序發(fā)送一個(gè)事件,控制權(quán)由此交給內(nèi)部區(qū)域。
應(yīng)用程序通過公共API接收客戶請(qǐng)求,使用領(lǐng)域模型來處理請(qǐng)求。
我們可以將DDD戰(zhàn)術(shù)設(shè)計(jì)建模元素Repository的實(shí)現(xiàn)看作是持久化適配器,該適配器用于訪問先前存儲(chǔ)的聚合實(shí)例或者保存新的聚合實(shí)例。
正如圖中的適配器E、F和G所展示的,我們可以通過不同的方式實(shí)現(xiàn)資源庫,比如關(guān)系型數(shù)據(jù)庫、基于文檔的存儲(chǔ)、分布式緩存或內(nèi)存存儲(chǔ)等。
如果應(yīng)用程序向外界發(fā)送領(lǐng)域事件消息,我們將使用適配器H進(jìn)行處理。該適配器處理消息輸出,而上面提到的處理AMQP消息的適配器則是處理消息輸入的,因此應(yīng)該使用不同的端口。
這張圖是筆者從《微服務(wù)架構(gòu)設(shè)計(jì)模式》中摘錄出來的
它通過OrderService表達(dá)了一個(gè)訂單服務(wù),它的核心通過六邊形架構(gòu)組織,由業(yè)務(wù)邏輯和一個(gè)或多個(gè)與其他服務(wù)和外部應(yīng)用程序連接的適配器組成。
圖中,REST API Adaptor?:表示入站適配器,實(shí)現(xiàn)REST API,這些API會(huì)調(diào)用業(yè)務(wù)邏輯(其實(shí)就是傳統(tǒng)開發(fā)下的controller/api之類的勞什子,換了個(gè)馬甲就顯得高大上了)
OrderCommandHandlers:入站適配器,它接收來自消息通道的命令式消息,并調(diào)用業(yè)務(wù)邏輯(其實(shí)就是傳統(tǒng)開發(fā)下的消息消費(fèi)者,比如Kafka中的listener之類的,沒什么新意)
Database Adaptor:業(yè)務(wù)邏輯調(diào)用以訪問數(shù)據(jù)庫的出站適配器。(好家伙,出站適配器,換了名字顯得十分陽春白雪, 按照下里巴人的理解,就是?相對(duì)業(yè)務(wù)邏輯而言,數(shù)據(jù)庫位于業(yè)務(wù)邏輯之外。因此持久化領(lǐng)域?qū)嶓w這操作,方向是由領(lǐng)域模型指向系統(tǒng)之外的,所以叫出站適配器)
Domain Event Publishing Adapter:將事件發(fā)布到消息代理的出站適配器(這其實(shí)就是傳統(tǒng)開發(fā)下的消息生產(chǎn)者,比如Kafka這種的Producer)之所以也是出站適配器,是因?yàn)橄l(fā)送到消息中間件后,相對(duì)業(yè)務(wù)邏輯而言,也是處于業(yè)務(wù)邏輯之外。
我們可以看到,六邊形架構(gòu)中的出站適配器、入站適配器,一旦映射到傳統(tǒng)開發(fā)中的概念,都是我們?nèi)粘i_發(fā)中經(jīng)常接觸到的。本質(zhì)上還是換湯不換藥,不得不佩服軟件行業(yè)造詞的能力。
階段總結(jié):四層架構(gòu)與六邊形架構(gòu)的對(duì)應(yīng)關(guān)系
我們對(duì)上面的講解做一個(gè)小小的總結(jié)。
四層架構(gòu)與六邊形架構(gòu),表面上看起來是不同的兩種架構(gòu)分層方式,本質(zhì)上,他們是同一事物的一體兩面, 是不同的思想對(duì)于同一個(gè)事物在不同時(shí)期思考總結(jié)的產(chǎn)物,雖然表象不同,但本質(zhì)卻能夠收斂對(duì)應(yīng)起來的。
具體是如何對(duì)應(yīng)的呢?
DDD四層架構(gòu)中UserInterface和infrastructure可以對(duì)應(yīng)到六邊形架構(gòu)中的適配器(入站和出站適配器均可,按照實(shí)際的角色具體分析對(duì)待);
四層架構(gòu)中的application能夠?qū)?yīng)到六邊形架構(gòu)中的應(yīng)用程序?qū)?#xff1b;
四層架構(gòu)中的domain能夠?qū)?yīng)到六邊形架構(gòu)中的領(lǐng)域模型層。
了解了DDD四層架構(gòu)和六邊形架構(gòu),我們又回到文章開頭的問題上來.
既然說DDD在架構(gòu)分層上往往能夠通過四層架構(gòu)、六邊形架構(gòu)表達(dá),那么我們用了四層架構(gòu)/六邊形架構(gòu)去做編碼,我們不就是落地了領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)了么?
文章的開頭我們直接給了回答,NO,用了分包并不代表落地了領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)。
我們經(jīng)常聽到一個(gè)成語,“形神兼?zhèn)洹薄?/p>
對(duì)于DDD而言,分包只是DDD的形,如果只是一味的套用DDD的分包,很容易重新回到傳統(tǒng)的三層架構(gòu)中來,用俗話說就叫?“開倒車”,而這個(gè)過程常常伴隨著代碼腐化,最終會(huì)演化為《人月神話》中提到的?“焦油坑”。
再談DDD本質(zhì)
這里,容我插一句與主題無關(guān)的話:
這個(gè)系列,雖然是針對(duì)DDD進(jìn)行的,但是筆者卻不厭其煩的試圖去挖掘所謂的本質(zhì)。原因在于不想將這個(gè)主題單純的寫成一個(gè)科普類的概念普及系列,如果是這樣的話,倒不如直接去看書來的更快更直接。
之所以不斷去強(qiáng)調(diào)DDD的本質(zhì),還是想以我的視角,去呈現(xiàn)一些我在學(xué)習(xí)DDD的過程中的一些思考,提供給讀者做參考,進(jìn)而去努力使讀者在學(xué)習(xí)過程中避免浪費(fèi)時(shí)間踩坑,更深層的意圖在于努力避免讀者進(jìn)入學(xué)習(xí)的誤區(qū)。
好了,我們還是回到正題。
在之前的文章中,筆者也提到過:“DDD本質(zhì)是面向?qū)ο鬄楹诵?#xff0c;通過領(lǐng)域建模還原現(xiàn)實(shí)世界”。
DDD作為一種指導(dǎo)復(fù)雜軟件設(shè)計(jì)開發(fā)的方法論,其根源還是基于面向?qū)ο笏枷?#xff0c;圍繞著對(duì)象本身的行為和屬性,為不同對(duì)象劃分邊界, 并規(guī)范約束了多個(gè)對(duì)象(所謂領(lǐng)域)分組間的通信/交互方式。
簡單的說,DDD的本質(zhì)還是面向?qū)ο缶幊?/strong>(不厭其煩,老生常談,希望你無論如何要記住這一點(diǎn)),通過為對(duì)象注入有業(yè)務(wù)屬性的行為,還對(duì)象以血肉;以對(duì)象建模映射現(xiàn)實(shí)世界的具體業(yè)務(wù)場景和真實(shí)交互行為, 通過業(yè)務(wù)概念映射代碼邏輯,借助一整套的戰(zhàn)略設(shè)計(jì)與戰(zhàn)術(shù)設(shè)計(jì),讓系統(tǒng)從流程化的貧血狀態(tài)機(jī)轉(zhuǎn)變?yōu)榫哂杏行驑I(yè)務(wù)交互的充血引擎。
我們可以說,通過DDD指導(dǎo)建模,到最終落地的過程,就是將真實(shí)世界的業(yè)務(wù)場景映射為領(lǐng)域模型及其交互流程的過程。
學(xué)習(xí)DDD的時(shí)候,作為初學(xué)者總是容易陷入它那一整套復(fù)雜方法論之中,DDD自身的概念、所謂的戰(zhàn)略設(shè)計(jì)、所謂的戰(zhàn)術(shù)設(shè)計(jì), 其本質(zhì)都是為了方便開發(fā)者/領(lǐng)域?qū)<?業(yè)務(wù)需求方統(tǒng)一溝通語言,并指導(dǎo)模型構(gòu)建最終進(jìn)行代碼落地的工具。
可以這么說,不論是戰(zhàn)術(shù)設(shè)計(jì)還是戰(zhàn)略設(shè)計(jì),本質(zhì)都是為了方便將真實(shí)世界映射到軟件模型中。
有了這樣的認(rèn)知,再回過頭去學(xué)習(xí)了解戰(zhàn)略設(shè)計(jì)、戰(zhàn)術(shù)設(shè)計(jì)及其衍生概念,就會(huì)更加容易。
如果只想記住一句話,那么只需要知道:DDD其實(shí)是一系列面向?qū)ο筌浖O(shè)計(jì)建模的方法論集合,其本質(zhì)還是面向?qū)ο缶幊?#xff0c;其根本目的在于更加系統(tǒng)化指導(dǎo)復(fù)雜軟件建模與落地,更好的將現(xiàn)實(shí)世界的復(fù)雜業(yè)務(wù)場景抽象為有序簡潔易維護(hù)的軟件系統(tǒng)。
當(dāng)然,開發(fā)簡潔有序易維護(hù)的軟件系統(tǒng),只用DDD是遠(yuǎn)遠(yuǎn)不夠的,還需要有豐富的工程思想、整潔架構(gòu)思想、扎實(shí)的編碼功底、系統(tǒng)的軟件工程理論等共同作用,這也是DDD這套方法論一直在發(fā)展的方向,它不斷吸納其他良好的最佳實(shí)踐為己用,不斷擴(kuò)展邊界。時(shí)至今日,DDD已經(jīng)是涵蓋建模、開發(fā)、測試、管理等領(lǐng)域的綜合軟件開發(fā)指導(dǎo)理論與思想。
正本清源,萬法歸宗
DDD的分包方式是領(lǐng)域建模的結(jié)果在代碼分層上的映射,只是解決了“代碼編寫完成之后往哪里放”的問題,
我們甚至可以大膽的斷言,
即便不采用DDD的分層,還是基于原有的 nterface->service->domain->dao的分層,只要基于面向?qū)ο蠓治鼋?#xff0c;
最終落地的代碼他和DDD建模的結(jié)果也會(huì)殊途同歸,因?yàn)?/p>
問題的根本其實(shí)還是在于領(lǐng)域如何劃分,領(lǐng)域之間如何進(jìn)行交互的問題。
下期預(yù)告
接下來的文章中,我們將正式進(jìn)入戰(zhàn)術(shù)設(shè)計(jì)/戰(zhàn)略設(shè)計(jì)中,不同于書籍,筆者會(huì)通過一個(gè)電商中的營銷/支付/記賬的業(yè)務(wù)場景,通過實(shí)戰(zhàn)與概念穿插的方式,去進(jìn)行內(nèi)容的呈現(xiàn)。
以馬克思主義為指導(dǎo),通過理論與實(shí)踐相結(jié)合,真正將DDD落地到實(shí)戰(zhàn)中去。
總結(jié)
以上是生活随笔為你收集整理的ddd 企业应用架构模式_灵魂拷问:用了DDD分包就是落地了领域驱动设计吗?谈谈DDD本质...的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: mysql连接超时timeout问题
- 下一篇: The server time zone