乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      使用DDD指導(dǎo)業(yè)務(wù)設(shè)計(jì)的一點(diǎn)思考

       漢無(wú)為 2020-03-22
      現(xiàn)實(shí)世界中的業(yè)務(wù)邏輯,在 IT 系統(tǒng)業(yè)務(wù)分析時(shí),適合某個(gè)行業(yè)和領(lǐng)域相關(guān)的,所以又叫做領(lǐng)域。
      領(lǐng)域,指的特定行業(yè)或者場(chǎng)景下的業(yè)務(wù)邏輯。
      DDD 中的模型是指反應(yīng) IT 系統(tǒng)的業(yè)務(wù)邏輯和狀態(tài)的對(duì)象,是從具體業(yè)務(wù)(領(lǐng)域)中提取出來(lái)的,因此又叫做領(lǐng)域模型。
      通過(guò)對(duì)實(shí)際業(yè)務(wù)出發(fā),而非馬上關(guān)注數(shù)據(jù)庫(kù)、程序設(shè)計(jì)。通過(guò)識(shí)別出固定的模式,并將這些業(yè)務(wù)邏輯的承載者抽象到一個(gè)模型上。這個(gè)模型負(fù)責(zé)處理業(yè)務(wù)邏輯,并表達(dá)當(dāng)前的系統(tǒng)狀態(tài)。這個(gè)過(guò)程就是領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)。
      我從這里面學(xué)到了什么呢?
      我們做的計(jì)算機(jī)系統(tǒng)實(shí)際上,是替代了現(xiàn)實(shí)世界中的一些操作。按照面向?qū)ο笤O(shè)計(jì)的話,我們的系統(tǒng)是一個(gè)電子餐廳?,F(xiàn)實(shí)餐廳中的實(shí)體,應(yīng)該對(duì)應(yīng)到我們的系統(tǒng)中去,用于承載業(yè)務(wù),例如收銀員、顧客、廚師、餐桌、菜品,這些虛擬的實(shí)體表達(dá)了系統(tǒng)的狀態(tài),在某種程度上就能指代系統(tǒng),這就是模型,如果找到了這些元素,就很容易設(shè)計(jì)出軟件。
      后來(lái),如果我什么業(yè)務(wù)邏輯想不清楚,我就會(huì)把電斷掉,假裝自己是服務(wù)員,用紙和筆走一邊業(yè)務(wù)流程。
      分析業(yè)務(wù),設(shè)計(jì)領(lǐng)域模型,編寫(xiě)代碼。這就是領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)的基本過(guò)程。隨后會(huì)介紹,如何設(shè)計(jì)領(lǐng)域模型,當(dāng)我們建立了領(lǐng)域模型后,我可以考慮使用領(lǐng)域模型指導(dǎo)開(kāi)發(fā)工作。
      • 指導(dǎo)數(shù)據(jù)庫(kù)設(shè)計(jì)

      • 指導(dǎo)模塊分包和代碼設(shè)計(jì)

      • 指導(dǎo) RESTful API 設(shè)計(jì)

      • 指導(dǎo)事務(wù)策略

      • 指導(dǎo)權(quán)限

      • 指導(dǎo)微服務(wù)劃分(有必要的情況)
      (使用DDD的一般模式)
      在我們之前的例子中,收銀員需要負(fù)責(zé)處理收銀的操作,同時(shí)表達(dá)這個(gè)餐廳有收營(yíng)員這樣的一個(gè)狀態(tài)。收營(yíng)員收到錢并記錄到賬本中,賬本負(fù)責(zé)處理記錄錢的業(yè)務(wù)邏輯,同時(shí)表達(dá)系統(tǒng)中有多少錢的狀態(tài)。

      分析領(lǐng)域模型時(shí),請(qǐng)把”電“斷掉

      我們進(jìn)行業(yè)務(wù)系統(tǒng)開(kāi)發(fā)時(shí),大多數(shù)人都會(huì)認(rèn)同一個(gè)觀點(diǎn):將業(yè)務(wù)和模型設(shè)計(jì)清楚之后,開(kāi)發(fā)起來(lái)會(huì)容易很多。
      但是實(shí)際開(kāi)發(fā)過(guò)程中,我們既要分析業(yè)務(wù),也要處理一些技術(shù)細(xì)節(jié),例如:如何響應(yīng)表單提交、如何存儲(chǔ)到數(shù)據(jù)庫(kù)、事務(wù)該怎么處理等。
      使用領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)還有一個(gè)好處,我們可以通過(guò)隔離這些技術(shù)細(xì)節(jié),先進(jìn)行業(yè)務(wù)邏輯建模,然后再完成技術(shù)實(shí)現(xiàn),因?yàn)闃I(yè)務(wù)模型已經(jīng)建立,技術(shù)細(xì)節(jié)無(wú)非就是響應(yīng)用戶操作和持久化模型。
      我們可以吧系統(tǒng)復(fù)雜的問(wèn)題分為兩類:
      • 業(yè)務(wù)復(fù)雜度
      • 技術(shù)復(fù)雜度

      (分離技術(shù)復(fù)雜度和業(yè)務(wù)復(fù)雜度)

      技術(shù)復(fù)雜度,軟件設(shè)計(jì)中和技術(shù)實(shí)現(xiàn)相關(guān)的問(wèn)題,例如處理用戶輸入,持久化模型,處理網(wǎng)絡(luò)通信等。
      業(yè)務(wù)復(fù)雜度,軟件設(shè)計(jì)中和業(yè)務(wù)邏輯相關(guān)的問(wèn)題,例如為訂單添加商品,需要計(jì)算訂單總價(jià),應(yīng)用折扣規(guī)則等。
      當(dāng)我們分析業(yè)務(wù)并建模時(shí),過(guò)于關(guān)注技術(shù)實(shí)現(xiàn),會(huì)帶來(lái)極大的干擾。我學(xué)到最實(shí)用的思維方法,就是在這個(gè)過(guò)程把”電“斷掉,技術(shù)復(fù)雜度中的用戶交互想象成人工交談,持久化想象成用紙和筆記錄。
      DDD 還強(qiáng)調(diào),業(yè)務(wù)建模應(yīng)該充分的和業(yè)務(wù)專家在一起,不應(yīng)該只是實(shí)現(xiàn)軟件的工程師自嗨。業(yè)務(wù)專家是一個(gè)虛擬的角色,有可能是一線業(yè)務(wù)人員、項(xiàng)目經(jīng)理、或者軟件工程師。
      由于和業(yè)務(wù)專家一起完成建模,因此盡量不要選用非常專業(yè)的繪圖的工具和使用技術(shù)語(yǔ)言。DDD 只是一種建模思想,并沒(méi)有規(guī)定使用的具體工具。我這里使用 PPT 的線條和形狀,用 E-R 的方式表達(dá)領(lǐng)域模型,如果大家都很熟悉 UML 也是可以的。甚至實(shí)際工作中,我們大量使用便利貼和白板完成建模工作。
      這個(gè)建模過(guò)程可以是技術(shù)人員和業(yè)務(wù)專家一起討論出來(lái),也可以是使用 ”事件風(fēng)暴“ 這類工作坊的方式完成。
      這個(gè)過(guò)程非常重要,DDD 把這個(gè)過(guò)程稱作 協(xié)作設(shè)計(jì)。
      通過(guò)這個(gè)過(guò)程,我們得到了領(lǐng)域模型。

      (原始領(lǐng)域模型)

      上圖使我們通過(guò)業(yè)務(wù)分析得到的一個(gè)非常基本的領(lǐng)域模型,我們的點(diǎn)餐系統(tǒng)中,會(huì)有座位、訂單、菜品、評(píng)價(jià) 幾個(gè)模型。一個(gè)座位可以由多個(gè)訂單,每個(gè)訂單可以有多個(gè)菜品和評(píng)價(jià)。
      同時(shí),菜品也會(huì)被不同的訂單使用。

      上下文、二義性、統(tǒng)一語(yǔ)言

      我們用這個(gè)模型開(kāi)發(fā)系統(tǒng),使用領(lǐng)域模型驅(qū)動(dòng)的方式開(kāi)發(fā),相對(duì)于事務(wù)腳本的方式,已經(jīng)容易和清晰很多了,但還是有一些問(wèn)題。
      有一天,市場(chǎng)告訴我們,這個(gè)系統(tǒng)會(huì)有一個(gè)邏輯問(wèn)題。就是系統(tǒng)中菜品被刪除,訂單也不能查看。在我們之前的認(rèn)知里面,訂單和菜品是一個(gè)多對(duì)多的關(guān)系,菜品都不存在了,這個(gè)訂單還有什么用。
      菜品,在這里存在了致命的二義性?。?!這里的菜品實(shí)際上有兩個(gè)含義:
      • 在訂單中,表達(dá)這個(gè)消費(fèi)項(xiàng)的記錄,也就是訂單項(xiàng)。例如,5號(hào)桌消費(fèi)的魚(yú)香肉絲一份。

      • 在菜品管理中,價(jià)格為30元的魚(yú)香肉絲,包含菜單圖片、文字描述,以及折扣信息。
      菜品管理中的菜品下架后,不應(yīng)該產(chǎn)生新的訂單,同時(shí)也不應(yīng)該對(duì)訂單中的菜品造成任何影響。
      這些問(wèn)題是因?yàn)?,技術(shù)專家和業(yè)務(wù)專家的語(yǔ)言沒(méi)有統(tǒng)一, DDD 認(rèn)識(shí)到了這個(gè)問(wèn)題,統(tǒng)一語(yǔ)言是實(shí)現(xiàn)良好的領(lǐng)域模型的前提,因此應(yīng)該 ”大聲的建模“。我在參與這個(gè)過(guò)程目睹過(guò)大量有意義的爭(zhēng)吵,正是這些爭(zhēng)吵讓領(lǐng)域模型變得原來(lái)越清晰。
      這個(gè)過(guò)程叫做統(tǒng)一語(yǔ)言。

      (領(lǐng)域模型v2)

      和現(xiàn)實(shí)生活中一樣,產(chǎn)生二義性的原因是因?yàn)槲覀兊膶?duì)話發(fā)生在不同的上下文中,我們?cè)谡勔粋€(gè)概念必須在確定的上下文中才有意義。在不同的場(chǎng)景下,即使使用的詞匯相同,但是業(yè)務(wù)邏輯本質(zhì)都是不同的。想象一下,發(fā)生在《武林外傳》中同福客棧的幾段對(duì)話。

      (對(duì)話)

      這段對(duì)話中實(shí)際上有三個(gè)上下文,這里的 ”菜“ 這個(gè)詞出現(xiàn)了三次,但是實(shí)際上業(yè)務(wù)含義完全不同。
      • 大嘴說(shuō)去買菜,這里的菜被抽象出來(lái)應(yīng)該是食材采購(gòu)品,如果掌柜對(duì)這個(gè)菜進(jìn)行管理,應(yīng)該具有采購(gòu)者、名稱、采購(gòu)商家、采購(gòu)價(jià)等。

      • 秀才說(shuō)實(shí)習(xí)生把賬單中的菜算錯(cuò)了價(jià)格,秀才需要對(duì)賬單進(jìn)行管理,這里的菜應(yīng)該指的賬單科目,現(xiàn)實(shí)中一般是會(huì)計(jì)科目。

      • 老白說(shuō)的客人點(diǎn)了一個(gè)醬鴨,這里老白關(guān)注的是訂單下面的訂單項(xiàng),訂單項(xiàng)包含的屬性有價(jià)格、數(shù)量、小計(jì)、折扣等信息。
      實(shí)際上,還有一個(gè)隱藏的模型——上架中商品。掌柜需要添加菜品到菜單中,客人才能點(diǎn),這個(gè)商品就是我們平時(shí)一般概念上的商品。
      我們把語(yǔ)言再次統(tǒng)一,得到新的模型。

      (領(lǐng)域模型v3)

      4個(gè)被紅色虛線框起來(lái)的區(qū)域中,我們都可以使用 ”菜品“ 這個(gè)詞匯(盡量不要這么做),但大家都明確 ”菜品“ 具有不同的含義。這個(gè)區(qū)域被叫做上下文。當(dāng)然上下文不只是由二義性決定的,還有可能是完全不相干的概念產(chǎn)生,例如訂單和座位實(shí)際概念上并沒(méi)有強(qiáng)烈的關(guān)聯(lián)關(guān)系,我們?cè)谡勛坏臅r(shí)候完全在談別的東西,所以座位也應(yīng)該是單獨(dú)的上下文。
      識(shí)別上下文的邊界是 DDD 中最難得一部分,同時(shí)上下文邊界是由業(yè)務(wù)變化動(dòng)態(tài)變化的,我們把識(shí)別出邊界的上下文叫做限界上下文(Bounded Context)。限界上下文是一個(gè)非常有用的工具,限界上下文可以幫助我們識(shí)別出業(yè)務(wù)的邊界,并做適當(dāng)?shù)牟鸱帧?/span>
      限界上下文的識(shí)別難以有一個(gè)明確的準(zhǔn)則,上下文的邊界非常模糊,需要有經(jīng)驗(yàn)的工程師并充分討論才能得到一個(gè)好的設(shè)計(jì)。同時(shí)需要注意,限界上下文的劃分沒(méi)有對(duì)錯(cuò),只有是否合適??缦藿缟舷挛闹g模型的關(guān)聯(lián)有本質(zhì)的不同,我們用虛線標(biāo)出,后面會(huì)聊到這種區(qū)別。

      (領(lǐng)域模型v4)

      使用上下文之后,帶來(lái)另外一個(gè)收獲。模型之間本質(zhì)上沒(méi)有多對(duì)多關(guān)系,如果有,說(shuō)明存在一個(gè)隱含的成員關(guān)系,這個(gè)關(guān)系沒(méi)有被充分的分析出來(lái),對(duì)后期的開(kāi)發(fā)會(huì)造成非常大的困擾。

      聚合根、實(shí)體、值對(duì)象

      上面的模型,尤其是解決二義性這個(gè)問(wèn)題之后,已經(jīng)能在實(shí)際開(kāi)發(fā)中很好地使用了。不過(guò)還是會(huì)有一些問(wèn)題沒(méi)有解決,實(shí)際開(kāi)發(fā)中,每種模型的身份可能不太一樣,訂單項(xiàng)必須依賴訂單的存在而存在,如果能在領(lǐng)域模型圖中體現(xiàn)出來(lái)就更好了。
      舉個(gè)例子來(lái)說(shuō),當(dāng)我們刪除訂單時(shí)候,訂單項(xiàng)應(yīng)該一起刪除,訂單項(xiàng)的存在必須依賴于訂單的存在。這樣業(yè)務(wù)邏輯是一致的和完整的,游離的訂單項(xiàng)對(duì)我們來(lái)說(shuō)沒(méi)有意義,除非有特殊的業(yè)務(wù)需求存在。
      為了解決這個(gè)問(wèn)題,對(duì)待模型就不再是一視同仁了。我們將那相關(guān)性極強(qiáng)的領(lǐng)域模型放到一起考慮,數(shù)據(jù)的一致性必須解決,同時(shí)生命周期也需要保持同步,我們把這個(gè)集合叫做聚合。
      聚合中需要選擇一個(gè)代表負(fù)責(zé)和全局通信,類似于一個(gè)部門的接口人,這樣就能確保數(shù)據(jù)保持一致。我們把這個(gè)模型叫做聚合根。當(dāng)一個(gè)聚合業(yè)務(wù)足夠簡(jiǎn)單時(shí),聚合有可能只有一個(gè)模型組成,這個(gè)模型就是聚合根,常見(jiàn)的就是配置、日志相關(guān)的。
      相對(duì)于非聚合根的模型,我們叫做實(shí)體。

      (領(lǐng)域模型v5)

      我們把這個(gè)圖完善一下,聚合之間也是用虛線鏈接,為聚合根標(biāo)上橙色。識(shí)別聚合根需要一些技巧。
      • 聚合根本質(zhì)上也是實(shí)體,同屬于領(lǐng)域模型,用于承載業(yè)務(wù)邏輯和系統(tǒng)狀態(tài)。
      • 實(shí)體的生命周期依附于聚合根,聚合根刪除實(shí)體應(yīng)該也需要被刪除,保持系統(tǒng)一致性,避免游離的臟數(shù)據(jù)。
      • 聚合根負(fù)責(zé)和其他聚合通信,因此聚合根往往具有一個(gè)全局唯一標(biāo)識(shí)。例如,訂單有訂單 ID 和訂單號(hào),訂單號(hào)為全局業(yè)務(wù)標(biāo)識(shí),訂單 ID 為聚合內(nèi)關(guān)聯(lián)使用。聚合外使用訂單號(hào)進(jìn)行關(guān)聯(lián)應(yīng)用。
      還有一類特殊的模型,這類模型只負(fù)責(zé)承載多個(gè)值的用處。在我們飯店的例子中,如果需要對(duì)賬單支持多國(guó)貨幣,我們將純數(shù)字的 price 字段修為 Price 類型。

      public Clsss Price(){

      private String unit;

      private BigDecimal value;

        public Price(String unit,BigDecimal value){

        this.unit = unit;

          this.value = value;

        }

      }

      價(jià)格這個(gè)模型,沒(méi)有自己的生命周期,一旦被創(chuàng)建出來(lái)就無(wú)須修改,因?yàn)樾薷木透淖兞诉@個(gè)值本身。所以我們會(huì)給這類的對(duì)象一個(gè)構(gòu)造方法,然后去除掉所有的 setter 方法。
      我們把沒(méi)有自己生命周期的模型,僅用來(lái)呈現(xiàn)多個(gè)字段的值的模型和對(duì)象,稱作為值對(duì)象。
      值對(duì)象一開(kāi)始不是特別好理解,但是理解之后會(huì)讓系統(tǒng)設(shè)計(jì)非常清晰?!钡刂贰笆且粋€(gè)顯著的值對(duì)象。當(dāng)訂單發(fā)貨后,地址中的某一個(gè)屬性不應(yīng)該被單獨(dú)修改,因?yàn)楸恍薷闹筮@個(gè)”地址“就不再是剛剛那個(gè)”地址“,判斷地址是否相同我們會(huì)使用它的具體值:省、市、地、街道等。
      值對(duì)象是相對(duì)于實(shí)體而言的,對(duì)比如下
      (實(shí)體和值對(duì)象對(duì)比)
      另外值得一提的是,一個(gè)模型被作為值對(duì)象還是實(shí)體看待不是一成不變的,某些情況下需要作為實(shí)體設(shè)計(jì),但是在另外的條件下卻最好作為值對(duì)象設(shè)計(jì)。
      地址,在一個(gè)大型系統(tǒng)充滿了二義性。
      • 作為訂單中的收貨地址時(shí),無(wú)需進(jìn)行管理,只需要表達(dá)街道、門牌號(hào)等信息,應(yīng)該作為值對(duì)象設(shè)計(jì)。為了避免歧義,可以重新命名為收貨地址。

      • 作為系統(tǒng)地理位置信息管理的情況中具有自己的生命周期,應(yīng)該作為實(shí)體設(shè)計(jì),并重命名為系統(tǒng)地址。
      • 作為用戶添加的自定義地址,用戶可以根據(jù) ID 進(jìn)行管理,應(yīng)該作為實(shí)體,并重命名為用戶地址。
      我們使用藍(lán)色區(qū)別實(shí)體和聚合根,更新后的模型圖如下:

      (領(lǐng)域模型v6)

      雖然我們使用 E-R 的方式描述模型和模型之間的關(guān)系,但是這個(gè)E-R圖使用了顏色、虛線,已經(jīng)和傳統(tǒng)的 E-R 圖大不相同,把這種圖暫時(shí)叫做CE-R圖(Classified Entity Relationship)。DDD沒(méi)有規(guī)定如何畫(huà)圖,你可以使用其他任何畫(huà)圖的方法表達(dá)領(lǐng)域模型

      使用領(lǐng)域模型指導(dǎo)程序設(shè)計(jì)

      在了解到 DDD 之前,到底該用一對(duì)多和多對(duì)多關(guān)系?RESTful API 設(shè)計(jì)時(shí)到底應(yīng)該選哪一個(gè)對(duì)象作為資源地址,評(píng)價(jià)應(yīng)該放到訂單路徑下還是單獨(dú)出來(lái)?訂單刪除相關(guān)有多少對(duì)象應(yīng)該納入事務(wù)管理?
      在沒(méi)有領(lǐng)域模型之前,這些大概率憑借經(jīng)驗(yàn)決定,當(dāng)我們把領(lǐng)域模型設(shè)計(jì)出來(lái)之后,領(lǐng)域模型可以幫助我們做出這些指導(dǎo)。領(lǐng)域模型不只是為編寫(xiě)業(yè)務(wù)邏輯代碼使用,這樣對(duì)領(lǐng)域模型來(lái)說(shuō)就太可惜了。
      下面是領(lǐng)域模型指導(dǎo)軟件開(kāi)發(fā)的一些方面,具體細(xì)節(jié)后面會(huì)再逐個(gè)討論。

      指導(dǎo)數(shù)據(jù)庫(kù)設(shè)計(jì)

      通過(guò) CE-R 圖,我們明顯可以設(shè)計(jì)出數(shù)據(jù)庫(kù)了。不過(guò)還有一些細(xì)節(jié)需要注意。
      首先,在之前的認(rèn)知里面,多對(duì)多關(guān)系是非常正常的。但是通過(guò)對(duì)領(lǐng)域模型的分析后發(fā)現(xiàn),傳統(tǒng)處理多對(duì)多關(guān)系時(shí),需要額外增加一張關(guān)聯(lián)表,這張關(guān)聯(lián)表本質(zhì)上是一個(gè)”關(guān)系“的實(shí)體沒(méi)有被發(fā)掘出來(lái)。否則,在實(shí)際開(kāi)發(fā)中會(huì)造成系統(tǒng)耦合,以及使用 ORM 的時(shí)候產(chǎn)生困惑。
      菜品和訂單之間是多對(duì)多關(guān)系嗎?
      如果是,菜品和訂單之間耦合了。實(shí)際上,菜品的管理處于系統(tǒng)操作的上游,菜品不依賴訂單的任何操作,也就是說(shuō)訂單的任何變化菜品無(wú)需關(guān)心。
      訂單擁有多個(gè)訂單項(xiàng),每個(gè)訂單項(xiàng)從菜品讀入數(shù)據(jù)并拷貝,或者引用一個(gè)菜品的全局 ID (菜品在另外一個(gè)聚合)。這樣在設(shè)計(jì)表結(jié)構(gòu)時(shí)訂單和訂單項(xiàng)關(guān)聯(lián),訂單項(xiàng)不關(guān)聯(lián)菜品。訂單項(xiàng)應(yīng)該從程序讀取菜品信息??雌饋?lái)多對(duì)多的關(guān)系,被細(xì)致分析后,變成了一個(gè)一對(duì)多關(guān)系。

      (數(shù)據(jù)庫(kù)設(shè)計(jì))

      在使用 ORM 時(shí),良好的領(lǐng)域模型尤其有用。不合適的關(guān)聯(lián)關(guān)系不僅讓 ORM 關(guān)聯(lián)變得混亂,還會(huì)讓 ORM 的性能變差。
      使用領(lǐng)域模型建立數(shù)據(jù)庫(kù)的要點(diǎn):
      • 留意多對(duì)多關(guān)系,并拆解成一對(duì)多關(guān)系

      • 值對(duì)象和實(shí)體往往為一對(duì)一關(guān)系

      • 使用 ORM 時(shí),聚合根和實(shí)體可以配置為級(jí)聯(lián)刪除和更新

      • 禁止聚合根之間進(jìn)行關(guān)聯(lián)

      指導(dǎo) API 設(shè)計(jì)

      RESTful API 已經(jīng)變成了主流 API 設(shè)計(jì)方式,當(dāng)設(shè)計(jì)好領(lǐng)域?qū)ο蠛螅O(shè)計(jì) API 的難度大大降低。
      使用聚合根作為 URI 的根路徑,使用實(shí)體作為子路徑。通過(guò) ID 作為 Path 參數(shù)。

      (API設(shè)計(jì))

      值對(duì)象沒(méi)有 ID,應(yīng)該只能依附于某個(gè)實(shí)體的路徑下做更新操作。

      (API設(shè)計(jì)v2)

      另外根據(jù)這個(gè)關(guān)系,處理批量操作的時(shí)候應(yīng)該在實(shí)體的上一級(jí)完成,例如批量添加訂單的訂單項(xiàng),可以設(shè)計(jì)為:
      POST /orders/{orderId}/items-batch
      不要設(shè)計(jì)為:
      POST /orders/{orderId}/items/batch

      指導(dǎo)對(duì)象設(shè)計(jì)

      在實(shí)踐中過(guò)程中,像 Java、Typescript具有類型系統(tǒng)的語(yǔ)言,對(duì)象很容易被誤用。如果 User 對(duì)象既被拿來(lái)當(dāng)做數(shù)據(jù)庫(kù)操作使用,又被拿來(lái)當(dāng)做接口呈現(xiàn)使用,這個(gè)類最終變成了上帝類,存在大量可有可無(wú)的屬性。
      例如用戶注冊(cè)時(shí)候需要輸入重復(fù)密碼,如果在 User 對(duì)象中添加 confirmPassword 屬性,存儲(chǔ)時(shí)候確并不需要。
      因此 DDD 中,數(shù)據(jù)庫(kù)各種對(duì)象的使用應(yīng)該針對(duì)不同的場(chǎng)景設(shè)計(jì)。回到我們上面說(shuō)的技術(shù)復(fù)雜度和業(yè)務(wù)復(fù)雜度中來(lái)。領(lǐng)域模型解決業(yè)務(wù)復(fù)雜度的問(wèn)題,領(lǐng)域模型只應(yīng)該被用作處理業(yè)務(wù)邏輯,存儲(chǔ)、業(yè)務(wù)表現(xiàn)都應(yīng)該和領(lǐng)域模型無(wú)關(guān)。

      (對(duì)象設(shè)計(jì))

      簡(jiǎn)單來(lái)說(shuō),可以把這些 Plain Object 分為三類:
      • DTO,和交互相關(guān)或者和后端、第三方服務(wù)對(duì)接

      • Entity,數(shù)據(jù)庫(kù)表映射

      • Model,領(lǐng)域模型
      另外,在使用領(lǐng)域模型使用上也需要額外注意
      • 領(lǐng)域?qū)ο蟊M量使用組合的方式,而不是繼承,現(xiàn)實(shí)業(yè)務(wù)邏輯中繼承這種概念實(shí)際上很少。例如菜品的設(shè)計(jì),有熱菜、湯菜、涼菜,實(shí)際上這里面并不是菜的繼承,而應(yīng)該抽象出分類這個(gè)模型。

      • 不要濫用領(lǐng)域模型,有些業(yè)務(wù)邏輯,實(shí)在找不出一個(gè)領(lǐng)域模型很正常,所以 DDD 中存在一個(gè)領(lǐng)域服務(wù)。例如,生成一個(gè) UUID。有些業(yè)務(wù)邏輯不持有系統(tǒng)業(yè)務(wù)狀態(tài),Eric 的書(shū)中比喻為像加油站一樣的業(yè)務(wù)邏輯。

      指導(dǎo)代碼組織

      代碼組織,通俗來(lái)說(shuō)就是如何分包。一種狹義的對(duì) DDD 的理解就是指按照 DDD 風(fēng)格進(jìn)行代碼組織,雖然 DDD 的內(nèi)容遠(yuǎn)不止于此。
      在很長(zhǎng)一段時(shí)間,我對(duì) DDD 分包策略陷入困惑,后來(lái)我明白到,討論 DDD 風(fēng)格的分包,必須將單體引用和微服務(wù)應(yīng)用分開(kāi)考慮。
      微服務(wù)應(yīng)用在邏輯上和解耦良好的單體應(yīng)用是一致的。
      但是微服務(wù)是一種分布式架構(gòu),映射到單體應(yīng)用中,各個(gè)包分布到不同的服務(wù)器中了。我們先以單體應(yīng)用入手,最后再討論如何將單體應(yīng)用架構(gòu)映射到到微服務(wù)中。
      在事務(wù)腳本的模式中,我們一般將代碼分為三層架構(gòu)。DDD 特別的抽離出一層叫做 application。這一層是 DDD 的精華,領(lǐng)域模型關(guān)心業(yè)務(wù)邏輯,但是不關(guān)心業(yè)務(wù)場(chǎng)景。

      application 用來(lái)隔離業(yè)務(wù)場(chǎng)景,顯得非常重要。舉個(gè)例子,用戶被添加到系統(tǒng)中,領(lǐng)域模型處理的是:

      1. 用戶被添加

      2. 授予基本權(quán)限

      3. 積分規(guī)則創(chuàng)建

      4. 賬戶創(chuàng)建(三戶模型,客戶、用戶、賬戶往往分開(kāi))

      5. 客戶資料錄入
      但是,用戶被添加到系統(tǒng)中由多個(gè)應(yīng)用場(chǎng)景觸發(fā)。
      • 用戶被邀請(qǐng)注冊(cè)

      • 用戶自己注冊(cè)

      • 管理員添加用戶
      application 需要隔離應(yīng)用場(chǎng)景,并組織調(diào)配領(lǐng)域服務(wù),才能使得領(lǐng)域服務(wù)真正被復(fù)用。因此 application 需要承擔(dān)事務(wù)管理、權(quán)限控制、數(shù)據(jù)校驗(yàn)和轉(zhuǎn)換等操作。當(dāng)領(lǐng)域服務(wù)被調(diào)用時(shí),應(yīng)該是純粹業(yè)務(wù)邏輯,并與場(chǎng)景無(wú)關(guān)。
      如果我們將三層架構(gòu)和 DDD 架構(gòu)對(duì)比,DDD 架構(gòu)如右圖所示。

      (三層架構(gòu)對(duì)比)

      我們將 DDD 的代碼架構(gòu)展開(kāi),可以看到更為細(xì)節(jié)的內(nèi)容。DDD 代碼實(shí)現(xiàn)上需要 Repository、Factory 等概念,但這些是可選的,我們?cè)诤竺婢唧w講代碼結(jié)構(gòu)的部分再闡述。

      (單體DDD架構(gòu))

      我們?cè)賮?lái)看,DDD 的單體應(yīng)用架構(gòu)映射到微服務(wù)架構(gòu)下會(huì)是怎么樣的。

      (單體到微服務(wù))

      微服務(wù)必須考慮到不再是一個(gè)服務(wù),Domain 層被抽離出來(lái)作為 Domain Server 存在,Domain Server 不關(guān)心業(yè)務(wù)場(chǎng)景,因此不需要 application 層。Application Server 需要 Application 層,Domain 層由后端的 Domain Server 提供。
      另外補(bǔ)充,一些 DDD 代碼組織的基本邏輯:
      • 隔離業(yè)務(wù)復(fù)雜度和技術(shù)復(fù)雜度

      • 使用接口隔離有必要的耦合和依賴倒置

        本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
        轉(zhuǎn)藏 分享 獻(xiàn)花(0

        0條評(píng)論

        發(fā)表

        請(qǐng)遵守用戶 評(píng)論公約

        類似文章 更多