<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          懟不過產(chǎn)品經(jīng)理?因?yàn)槟悴欢瓺DD領(lǐng)域建模與架構(gòu)設(shè)計(jì)

          共 5039字,需瀏覽 11分鐘

           ·

          2021-10-20 14:04

          前幾年就開始接觸DDD(Domain Driven Design,領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)),并且著迷于此。它更多地在戰(zhàn)略層指導(dǎo)了我的設(shè)計(jì),對(duì)于戰(zhàn)術(shù)層面的設(shè)計(jì),目前業(yè)界沒有統(tǒng)一的標(biāo)準(zhǔn),也沒有特別流行的方案。雖然也有許多技術(shù)大牛們熱衷于DDD,但一到代碼落地便一地雞毛,造不出“銀彈”。

          那DDD到底是什么呢?有什么技術(shù)落地方案呢?今天我來給大家科普一下。




          基本概念



          過去系統(tǒng)分析和系統(tǒng)設(shè)計(jì)都是分離的,正如我們國家“系統(tǒng)分析師” 和“系統(tǒng)設(shè)計(jì)師” 兩種職稱考試一樣,這樣割裂的結(jié)果導(dǎo)致,需求分析的結(jié)果無法直接進(jìn)行設(shè)計(jì)編程,而能夠進(jìn)行編程運(yùn)行的代碼卻扭曲需求,導(dǎo)致客戶運(yùn)行軟件后才發(fā)現(xiàn)很多功能不是自己想要的,而且軟件不能快速跟隨需求變化。


          DDD則打破了這種隔閡,提出了領(lǐng)域模型概念,統(tǒng)一了分析和設(shè)計(jì)編程,使得軟件能夠更靈活快速跟隨需求變化。


          DDD專門為解決復(fù)雜性而誕生,因此解決思路完全不同于傳統(tǒng)的CRUD,但是DDD本身掌握起來并不會(huì)感覺復(fù)雜,從程序員角度看,DDD其實(shí)是研究將包含業(yè)務(wù)邏輯的ifelse語句放在哪里的學(xué)問。

          Q:DDD有什么作用?
          A:想想我們做軟件設(shè)計(jì)的初衷是什么?通過微服務(wù)與領(lǐng)域驅(qū)動(dòng)設(shè)計(jì),簡化設(shè)計(jì),降低維護(hù)成本,提高軟件交付速度。這要求我們落地的時(shí)候,架設(shè)一個(gè)支持微服務(wù)、支持領(lǐng)域驅(qū)動(dòng)的架構(gòu)。

          Q:DDD適用于什么場(chǎng)景?

          A:在Evans寫的《領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)》一書,副標(biāo)題已經(jīng)說明一切:軟件核心復(fù)雜性應(yīng)對(duì)之道。領(lǐng)域驅(qū)動(dòng)的真正作用,在于項(xiàng)目中對(duì)日后的維護(hù),當(dāng)系統(tǒng)變得越來越復(fù)雜的時(shí)候,才能體現(xiàn)出它的威力。

          那新項(xiàng)目該不該用領(lǐng)域驅(qū)動(dòng)?新項(xiàng)目并不復(fù)雜,產(chǎn)品還在跑模式的階段,雖然它的優(yōu)勢(shì)并不能真正發(fā)揮出來,但我認(rèn)為,DDD同樣適用新項(xiàng)目。項(xiàng)目只會(huì)越做越復(fù)雜,我們從一開始就應(yīng)該考慮日漸發(fā)胖的代碼、隨時(shí)可能獨(dú)立的子業(yè)務(wù)。而新項(xiàng)目更多的是指導(dǎo)戰(zhàn)略層設(shè)計(jì)(如領(lǐng)域建模),戰(zhàn)術(shù)層的技術(shù)落地還是以團(tuán)隊(duì)成員最熟悉的方式進(jìn)行,目標(biāo)是持續(xù)快速交付、降低維護(hù)成本。



          領(lǐng)域建模



          Q:什么是領(lǐng)域模型?

          A:為解決場(chǎng)景下的問題而形成的一套模型,然后使用這套模型來解決業(yè)務(wù)問題。?根據(jù)重復(fù)勞動(dòng)經(jīng)驗(yàn)我們會(huì)形成一套模式,領(lǐng)域模型也一樣會(huì)形成一套模式,包括:實(shí)體、值對(duì)象、模塊、領(lǐng)域服務(wù)。

          1

          領(lǐng)域發(fā)現(xiàn)

          那領(lǐng)域模型是怎么一步一步確定下來的呢?推薦兩種比較常用的領(lǐng)域發(fā)現(xiàn)方法:事件風(fēng)暴四色建模法

          一、事件風(fēng)暴

          Event Storming(事件風(fēng)暴)是一種輕量級(jí)的系統(tǒng)分析方法,基于 DDD 的概念,能夠?yàn)槲覀兪崂硐到y(tǒng)中的各種相關(guān)元素,其中包括了核心的 Aggregate。它能夠幫助開發(fā)人員梳理核心的業(yè)務(wù)對(duì)象,從某種程度上來說就是就是領(lǐng)域?qū)ο笾械木酆稀?/p>

          描述產(chǎn)品愿景

          產(chǎn)品愿景的主要目的是對(duì)產(chǎn)品頂層價(jià)值的設(shè)計(jì),使產(chǎn)品目標(biāo)用戶、核心價(jià)值、差異化競(jìng)爭(zhēng)點(diǎn)等信息達(dá)成一致,避免產(chǎn)品偏離方向。

          產(chǎn)品愿景的參與角色:領(lǐng)域?qū)<摇I(yè)務(wù)需求方、產(chǎn)品經(jīng)理、項(xiàng)目經(jīng)理和開發(fā)經(jīng)理。

          事件風(fēng)暴關(guān)注點(diǎn)

          事件:某個(gè)動(dòng)作的結(jié)果

          屬性:事件的輸入、輸出

          命令:某個(gè)動(dòng)作

          實(shí)體:命令的觸發(fā)者

          簡單理解就是誰(實(shí)體)使用什么(輸入)做了什么(命令、動(dòng)作)產(chǎn)生了什么(輸出)影響了什么(事件)。


          二、四色建模法

          通過還原業(yè)務(wù)邏輯事件,依據(jù)是否影響公司的運(yùn)營和發(fā)展,確定憑證作為時(shí)標(biāo)型對(duì)象,并補(bǔ)全相關(guān)描述的建模方法。四色建模法一般運(yùn)用于問題分析建模。

          四色建模是哪四色?它包括——


          時(shí)標(biāo)型(Moment-Interval)對(duì)象:具有可追溯性的記錄運(yùn)營或管理數(shù)據(jù)的時(shí)刻或時(shí)段對(duì)象,用粉紅色表示;

          PPT(Party/Place/Thing)對(duì)象:代表參與到流程中的參與方/地點(diǎn)/物,用綠色表示;

          角色(Role)對(duì)象:在時(shí)標(biāo)型對(duì)象與 PPT 對(duì)象(通常是參與方)之間參與的角色,用黃色表示;

          描述(Description)對(duì)象:對(duì) PPT 對(duì)象的一種補(bǔ)充描述,用藍(lán)色表示。


          分析的五個(gè)步驟
          1. 找到溯源事件

          2. 確定時(shí)標(biāo)型對(duì)象

          3. 找到周圍的PPT對(duì)象

          4. 找到角色

          5. 補(bǔ)全描述對(duì)象

          四色建模法案例:


          2

          領(lǐng)域建模三步曲


          對(duì)于不同的人提煉出來的領(lǐng)域模型不可能完全一致,這是因?yàn)?strong>每個(gè)人對(duì)業(yè)務(wù)理解的角度都不同。那么,怎么才能保證建模的正確性?


          這聽起來是個(gè)合理的質(zhì)疑,但實(shí)際上卻不是那么有道理。首先我們需要明白建模的目的是什么?如果僅僅是為了描畫問題,那么并沒有什么對(duì)錯(cuò)之分——僅僅是立場(chǎng)和角度的差別;而如果是為了企業(yè)業(yè)務(wù)系統(tǒng)而進(jìn)行建模,那么這個(gè)問題應(yīng)該變?yōu)椋?strong style="font-family: -apple-system, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;">如何保證模型能夠支撐企業(yè)的運(yùn)營?

          我給大家梳理以下幾個(gè)步驟:

          一、統(tǒng)一語言,梳理業(yè)務(wù)

          在做設(shè)計(jì)的時(shí)候,梳理業(yè)務(wù)貫穿了整個(gè)過程。這需要技術(shù)與業(yè)務(wù)專家利用統(tǒng)一語言,描繪需求或問題本身,不斷梳理業(yè)務(wù),提煉出核心的領(lǐng)域模型(而非表設(shè)計(jì))。這有利于拉近技術(shù)人員與業(yè)務(wù)人員之間的關(guān)系,建立信任,達(dá)成統(tǒng)一的業(yè)務(wù)目標(biāo)。

          二、識(shí)別聚合、聚合根

          梳理完業(yè)務(wù)后,找出實(shí)體、值對(duì)象,識(shí)別出各個(gè)聚合與聚合根。

          如何識(shí)別聚合與聚合根?

          一個(gè)Bounded Context(限界上下文)可能包含多個(gè)聚合,每個(gè)聚合都有一個(gè)根實(shí)體,叫做聚合根;

          如何進(jìn)行關(guān)聯(lián)?
          聚合根到聚合根:通過ID關(guān)聯(lián)
          聚合根到其內(nèi)部的實(shí)體,直接對(duì)象引用;
          聚合根到值對(duì)象,直接對(duì)象引用;
          對(duì)于聚合,有以下設(shè)計(jì)原則:
          1. 聚合是用來封裝真正的不變性,而不是簡單的將對(duì)象組合在一起
          2. 聚合應(yīng)盡量設(shè)計(jì)的小,盡可能小的拆分,可以避免重構(gòu),重新拆分

          3. 聚合之間的關(guān)聯(lián)通過ID,而不是對(duì)象引用

          4. 聚合內(nèi)強(qiáng)一致性,聚合之間最終一致性

          應(yīng)用層實(shí)現(xiàn)跨聚合的調(diào)用,避免跨聚合的領(lǐng)域服務(wù)調(diào)用和數(shù)據(jù)表關(guān)聯(lián)。

          三、劃分限界上下文

          第二步完成以后,我們根據(jù)不同的場(chǎng)景來劃分限界上下文,以便進(jìn)行微服務(wù)拆分。通過這種基于業(yè)務(wù)理解的拆分方式,我們的系統(tǒng)就能做到高內(nèi)聚,做到單一職責(zé),拆分出來的每個(gè)微服務(wù)都是軟件變化的一個(gè)原因,不會(huì)因?yàn)槟硞€(gè)原因發(fā)生的變更去修改每個(gè)微服務(wù),“牽一發(fā)而動(dòng)全身”。

          ? ??


          架構(gòu)設(shè)計(jì)



          架構(gòu)設(shè)計(jì)作為DDD戰(zhàn)術(shù)層面的設(shè)計(jì),關(guān)乎到設(shè)計(jì)如何落地到項(xiàng)目中。下面介紹跨庫關(guān)聯(lián)查詢解決方案及幾種比較流行的架構(gòu)設(shè)計(jì)方案。

          1

          跨庫關(guān)聯(lián)查詢解決方案

          方案一:數(shù)據(jù)冗余

          這是最簡單常用的一種解決方案——以空間換時(shí)間,把需要關(guān)聯(lián)查詢的條件冗余存儲(chǔ)在需要查詢的庫。
          舉個(gè)例子,商品與商品類目被拆到兩個(gè)獨(dú)立的服務(wù)與數(shù)據(jù)庫中,兩者通過類目編碼關(guān)聯(lián),產(chǎn)品想通過類目名稱對(duì)商品分頁查詢,這時(shí)我們可以把類目名稱冗余到商品表存儲(chǔ),給它加個(gè)數(shù)據(jù)庫索引即可。

          方案二:數(shù)據(jù)補(bǔ)填

          結(jié)合Wrapper設(shè)計(jì)模式,一般在Dao層實(shí)現(xiàn)數(shù)據(jù)聚合——本地庫分頁查詢完數(shù)據(jù)后,通過查詢條件判斷是否需要填充關(guān)聯(lián)數(shù)據(jù),若需要?jiǎng)t通過跨服務(wù)查詢相關(guān)聯(lián)的服務(wù),再對(duì)各個(gè)服務(wù)的數(shù)據(jù)進(jìn)行填充組裝,最后返回。

          如下圖,要實(shí)現(xiàn)患者預(yù)約查詢,并聚合患者、醫(yī)生數(shù)據(jù),則在患者預(yù)約服務(wù)查詢完預(yù)約表數(shù)據(jù)后補(bǔ)填患者服務(wù)和醫(yī)生服務(wù)的數(shù)據(jù)。

          這種方法的缺點(diǎn)就是,當(dāng)一個(gè)完整的數(shù)據(jù)涉及到N個(gè)微服務(wù),就會(huì)增加N-1個(gè)服務(wù)調(diào)用,數(shù)據(jù)全量查詢/導(dǎo)出的場(chǎng)景也不好使。

          2

          CQRS與Event Sourcing

          CQRS(Command Query Responsibility Segregation)指的是命令查詢職責(zé)分離。Command服務(wù)專門寫數(shù)據(jù),使用關(guān)系型數(shù)據(jù)庫以保證ACID;Query服務(wù)專門讀數(shù)據(jù),一般使用NoSQL數(shù)據(jù)庫,實(shí)現(xiàn)寬表查詢,如MongoDB、ElasticSearch等。這是一種索引外置方案。

          Event Sourcing事件溯源——簡單來說就是,通過事件來管理領(lǐng)域?qū)ο蟮纳芷?,事件即領(lǐng)域?qū)ο笠寻l(fā)生的事實(shí),只增不改。一個(gè)對(duì)象從創(chuàng)建開始到消亡會(huì)經(jīng)歷很多事件,以前我們是在每次對(duì)象參與完一個(gè)業(yè)務(wù)動(dòng)作后把對(duì)象的最新狀態(tài)持久化保存到數(shù)據(jù)庫中,也就是說我們的數(shù)據(jù)庫中的數(shù)據(jù)是反映了對(duì)象的當(dāng)前最新的狀態(tài)。

          而事件溯源則相反,不是保存對(duì)象的最新狀態(tài),而是保存這個(gè)對(duì)象所經(jīng)歷的每個(gè)事件,所有的由對(duì)象產(chǎn)生的事件會(huì)按照時(shí)間先后順序有序的存放在數(shù)據(jù)庫中??梢钥闯觯录菰吹倪@種做法是更符合事實(shí)觀的,因?yàn)樗暾拿枋隽藢?duì)象的整個(gè)生命周期過程中所經(jīng)歷的所有事件。
          那么,事件到底如何影響一個(gè)領(lǐng)域?qū)ο蟮臓顟B(tài)的呢?很簡單,當(dāng)我們?cè)谟|發(fā)某個(gè)領(lǐng)域?qū)ο蟮哪硞€(gè)行為時(shí),該領(lǐng)域?qū)ο髸?huì)先產(chǎn)生一個(gè)事件,然后該對(duì)象自己響應(yīng)該事件并更新其自己的狀態(tài),同時(shí)我們還會(huì)持久化在該對(duì)象上所發(fā)生的每一個(gè)事件;這樣當(dāng)我們要重新得到該對(duì)象的最新狀態(tài)時(shí),只要先創(chuàng)建一個(gè)空的對(duì)象,然后將和該對(duì)象相關(guān)的所有事件按照事件發(fā)生先后順序從先到后再全部應(yīng)用一遍即可還原得到該對(duì)象的最新狀態(tài),這個(gè)過程就是所謂的事件溯源;
          另一方面,因?yàn)槭怯檬录肀硎緦?duì)象的狀態(tài),而事件是只會(huì)增加不會(huì)修改。這就能讓數(shù)據(jù)庫里的表示對(duì)象的數(shù)據(jù)非常穩(wěn)定,不可能存在DELETE或UPDATE等操作。因?yàn)?/span>一個(gè)事件就是表示一個(gè)事實(shí),事實(shí)是不能被磨滅或修改的。這種特性可以讓領(lǐng)域模型非常穩(wěn)定,在數(shù)據(jù)庫級(jí)別不會(huì)產(chǎn)生并發(fā)更新同一條數(shù)據(jù)的問題;

          下圖為一種支持讀寫分離的演化:

          寫服務(wù)只有一個(gè)統(tǒng)一的Controller入口,通過URL路徑與Body傳入進(jìn)入相應(yīng)的service、方法與入?yún)?,然后利?strong>反射定位到具體的Service的某個(gè)方法,邏輯處理完后再分發(fā)到單Dao,通過配置Vobj.xml映射到對(duì)應(yīng)的表。這樣的好處是新增業(yè)務(wù)只需要寫Service與配置映射關(guān)系即可,不需要再新增Controller與Dao,Contoller變成了一層薄薄的接入層,大大簡化了代碼;
          讀服務(wù)也有統(tǒng)一的Controller,通過Service分發(fā)到不同的DAO層實(shí)現(xiàn),寫自定義的SQL或利用ES存寬表來查。
          3

          領(lǐng)域驅(qū)動(dòng)架構(gòu)
          與上面的單Dao實(shí)現(xiàn)類似,建立統(tǒng)一的Controller與通用的倉庫與工廠,利用數(shù)據(jù)庫第三范式實(shí)現(xiàn)服務(wù)內(nèi)數(shù)據(jù)補(bǔ)填,利用服務(wù)調(diào)用實(shí)現(xiàn)跨服務(wù)數(shù)據(jù)補(bǔ)填。
          4

          整潔架構(gòu)

          整潔架構(gòu)的核心思想是通過適配器層解耦業(yè)務(wù)層與技術(shù)框架層代碼,使得業(yè)務(wù)代碼與技術(shù)框架可以各自升級(jí)迭代,互不影響。我們都知道,技術(shù)架構(gòu)一直以來都在不斷變化,對(duì)項(xiàng)目的技術(shù)架構(gòu)調(diào)整成本是非常高的,如何降低這種成本?這時(shí)候整潔架構(gòu)就派上用場(chǎng)了。

          如上圖所示,中間的Entities與Use Cases屬于業(yè)務(wù)領(lǐng)域?qū)樱珽ntities表示業(yè)務(wù)領(lǐng)域模型的核心業(yè)務(wù),Use Cases表示與用戶交互的Service;最外層技術(shù)框架層是各種技術(shù)實(shí)現(xiàn),與業(yè)務(wù)無關(guān)的一層;那業(yè)務(wù)與技術(shù)怎么進(jìn)行關(guān)聯(lián)呢?通過中間綠色的接口適配器層實(shí)現(xiàn)。適配器層分離了技術(shù)實(shí)現(xiàn)與業(yè)務(wù)邏輯。

          下圖為整潔架構(gòu)的一種落地方案。

          5

          六邊形架構(gòu)

          六邊形架構(gòu)是微服務(wù)設(shè)計(jì)的基礎(chǔ)。

          如圖,我們把微服務(wù)封裝在六邊形里,每個(gè)微服務(wù)的核心業(yè)務(wù)是六邊形里的應(yīng)用程序與領(lǐng)域模型。與整潔架構(gòu)類似,外部接口與內(nèi)部應(yīng)用層通過各種適配器進(jìn)行關(guān)聯(lián)解耦,當(dāng)發(fā)生變更的時(shí)候,只需要修改六邊形內(nèi)部即可,不需要修改其它微服務(wù)。

          6

          清晰架構(gòu)

          清晰架構(gòu)融合了DDD、整潔架構(gòu)、CQRS……曾在高水準(zhǔn)的平臺(tái)生產(chǎn)代碼中應(yīng)用,其中一個(gè)是擁有數(shù)千家遍布全球的網(wǎng)上商店的 SaaS 電子商務(wù)平臺(tái),另一個(gè)是已經(jīng)在兩個(gè)國家上線的市場(chǎng),擁有可以每月處理超過兩千萬條消息的消息總線。

          如上圖清晰架構(gòu)的架構(gòu)形態(tài),左側(cè)用戶從瀏覽器/客戶端/APP等發(fā)起業(yè)務(wù),經(jīng)過左側(cè)主適配器,把不同的接入技術(shù)與應(yīng)用層解耦,這樣一來業(yè)務(wù)應(yīng)用就只需要寫一套即可,大大降低了開發(fā)成本;數(shù)據(jù)經(jīng)過應(yīng)用層后,通過右側(cè)的從適配器接入,實(shí)現(xiàn)不同的存儲(chǔ)形式/技術(shù)實(shí)現(xiàn),解耦業(yè)務(wù)代碼。


          以上給大家介紹了DDD的基本概念、領(lǐng)域建模及幾種主流的架構(gòu)設(shè)計(jì)方案。DDD是一個(gè)非常大的課題,工程師們對(duì)DDD的各種爭(zhēng)論從不休止,但存在即合理,我們并不一定要把DDD落地到項(xiàng)目中去,在戰(zhàn)略層設(shè)計(jì)可以指導(dǎo)我們準(zhǔn)確梳理業(yè)務(wù)。

          無論如何,將來想要成為業(yè)務(wù)架構(gòu)師,DDD領(lǐng)域建模與架構(gòu)設(shè)計(jì)是一堂必修課,參與到這場(chǎng)思想運(yùn)動(dòng)與實(shí)踐中是非常有必要的。


          End



          往期精選??點(diǎn)擊標(biāo)題可跳轉(zhuǎn)

          你一定要掌握的畫圖技巧

          論程序員如何在35歲之前完成渡劫

          利用參數(shù)注解+AOP對(duì)方法進(jìn)行攔截校驗(yàn)

          為什么說高手都有“上游思維”?

          跨庫聚合全文搜索的三種存儲(chǔ)方案

          微服務(wù)設(shè)計(jì)的四大原則

          回復(fù)「題庫」領(lǐng)取海量算法題庫

          回復(fù)「設(shè)計(jì)」學(xué)習(xí)UML設(shè)計(jì)技巧

          瀏覽 66
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  日本一区二区电影久久精品 | 亚洲午夜免费 | 毛片其地 | 免费观看AA片 | 色色男人天堂 |