最近一直在學(xué)習(xí)和研究DDD領(lǐng)域驅(qū)動設(shè)計(Domain Driven Design),DDD其實已經(jīng)火了很多年了拔疚,只不過一直沒有系統(tǒng)的去學(xué)習(xí)和應(yīng)用到項目中,之前也是在網(wǎng)上和別人的演講中零零散散的了解了一些設(shè)計理念,DDD給初學(xué)者的感覺就是太抽象世杀,不實際,沒辦法應(yīng)用到日常項目中肝集,最近系統(tǒng)的看了DDD的兩本巨著后對DDD也有一些自己的感悟瞻坝,打算寫幾篇文章記錄下。
先從自己理解的角度概括下DDD的核心理念杏瞻,DDD我的理解其實就是從業(yè)務(wù)角度將系統(tǒng)進行可擴展的領(lǐng)域拆分所刀。同一個實體在不同的業(yè)務(wù)領(lǐng)域中可能有不同的屬性,但是現(xiàn)實中可能是同一個東西捞挥,例如一輛車在倉庫中是一個庫存車輛實體浮创,但是這輛車如果放到了4S店就成了一輛待售車輛實體,不同領(lǐng)域進行實體交互的時候通過各個領(lǐng)域中的適配層將不同領(lǐng)域的實體進行映射轉(zhuǎn)換砌函。講了這些可能還是有些抽象斩披,其實個人覺得這個核心理念其實和開發(fā)中的傳統(tǒng)分層概念很像只不過是從技術(shù)層面轉(zhuǎn)移到了業(yè)務(wù)層面溜族,例如傳統(tǒng)技術(shù)分層會將系統(tǒng)分為展示層、服務(wù)層垦沉、數(shù)據(jù)操作層煌抒,每層之間通過調(diào)用上下游系統(tǒng)的接口進行操作,這樣設(shè)計的目的無非也是為了避免各個層面如果有具體實現(xiàn)上的變動例如數(shù)據(jù)庫換了乡话,只要接口保持不變就不會影響到其他層次摧玫。DDD其實也是要達到一樣的效果,只不過這里就不是為了避免技術(shù)層面的改動影響很多上下游層的改動绑青,而是為了減少或避免某一個業(yè)務(wù)模塊的改動诬像,而影響到其他業(yè)務(wù)模塊的改動,這就要求前期對業(yè)務(wù)能夠有充分的理解闸婴,需要領(lǐng)域?qū)<夷軌驈臉I(yè)務(wù)角度充分拆解業(yè)務(wù)模塊坏挠,做到每個業(yè)務(wù)模塊是高內(nèi)聚,模塊之間是低耦合的邪乍。這個工作是非辰岛荩考驗對業(yè)務(wù)的理解的,并不是一個普通的技術(shù)人員就能夠很好的拆解出來庇楞,技術(shù)人員更多的還是習(xí)慣于從數(shù)據(jù)模型驅(qū)動開發(fā)榜配,想想平時我們開發(fā)的時候是不是先設(shè)計好數(shù)據(jù)表,然后根據(jù)數(shù)據(jù)表進行各個業(yè)務(wù)功能的開發(fā)吕晌。
這個系列的文章我計劃是將自己學(xué)習(xí)過程中對DDD的知識點進行提煉和總結(jié)蛋褥,希望能夠幫助大家在以后遇到類似這個功能應(yīng)該放在哪個系統(tǒng)去實現(xiàn)的問題時做到有章可循,在新系統(tǒng)設(shè)計的時候能夠提前就分析好業(yè)務(wù)模塊劃分睛驳,避免以后出現(xiàn)一個小改動結(jié)果涉及到一堆系統(tǒng)配合改造烙心。
第一篇文章先介紹下DDD中的一些核心概念的名詞解釋,讓大家知道這些抽象名詞都是什么意思乏沸。
界限上下文:代表一個系統(tǒng)淫茵、一個應(yīng)用程序或者一種業(yè)務(wù)服務(wù)。限界上下文所包含的領(lǐng)域模型概念應(yīng)該是高度相關(guān)的蹬跃,這樣可以保證在同一個上下文中所有的領(lǐng)域模型都是為了完成同一個業(yè)務(wù)功能而設(shè)計的匙瘪,這樣可以最大程度的避免不同界限上下文頻繁交互訪問,一旦發(fā)現(xiàn)一個界限上下文中頻繁訪問另一個界限上下文中的領(lǐng)域模型蝶缀,那么就應(yīng)該將這個領(lǐng)域模型放到你的界限上下文中了辆苔。
通用語言:在一個特定的限界上下文中只使用一套通用語言,并且保證它的清晰性扼劈,避免一個概念在同一個界限上下文中的二義性驻啤,也可以理解成一套業(yè)務(wù)字典,這套字典可以作為業(yè)務(wù)人員和技術(shù)人員之間的橋梁荐吵。
領(lǐng)域:從大了看骑冗,領(lǐng)域代表整個公司的運作一切赊瞬。從小了看,是每個組織運作中的一切贼涩。所以領(lǐng)域的概念必然與公司的組織架構(gòu)所承擔(dān)的職責(zé)有一定的關(guān)系巧涧。
子域:一個領(lǐng)域內(nèi)可以包含N個子域。理論上一個子域?qū)?yīng)一個限界上下文是最優(yōu)也是最理想的情況遥倦,但是有時又要考慮到業(yè)務(wù)關(guān)聯(lián)度需要做出權(quán)衡谤绳。子域又分核心域、支撐子域袒哥、通用子域缩筛。
核心域:它是整個業(yè)務(wù)領(lǐng)域的一部分,也是業(yè)務(wù)成功的主要促成因素堡称。從戰(zhàn)略層面上講瞎抛,企業(yè)應(yīng)該在核心域上勝人一籌。我們應(yīng)該給予核心域最高的優(yōu)先級却紧、最資深的領(lǐng)域?qū)<液妥顑?yōu)秀的開發(fā)團隊桐臊。在實施DDD的過程中將主要關(guān)注核心域。
支撐子域:對應(yīng)著業(yè)務(wù)的某些重要方面晓殊,但卻不是核心断凶,那么它便是一個支撐子域。
通用子域:某個支撐子域的運用范圍是整個系統(tǒng)巫俺,那么這個子域便是通用子域认烁。
上下文映射圖:由多個界限上下文和子域組成的表示當(dāng)前單個領(lǐng)域或者多個領(lǐng)域之間的集成關(guān)系圖。
上面介紹的是DDD中的核心概念名詞识藤,在實現(xiàn)層面同樣也會涉及到一些關(guān)系名詞:
合作關(guān)系(Partnership):如果2個限界上下文的團隊存在高度依賴要么一起成功砚著,要么一起失敗次伶,此時就是合作關(guān)系痴昧。應(yīng)該為相互關(guān)聯(lián)的軟件功能制定好計劃表,這樣可以確保這些功能在同一個發(fā)布中完成冠王。
共享內(nèi)核(Shared Kernel):對模型和代碼的共享將產(chǎn)生一種緊密的依賴性赶撰,對于設(shè)計來說,這種依賴性可好可壞柱彻。我們需要為共享的部分模型指定一個顯式邊界豪娜,并保持共享內(nèi)核的小型化。共享內(nèi)核具有特殊的狀態(tài)哟楷,在沒有與另一個團隊協(xié)商的情況下瘤载,這種狀態(tài)是不能改變的。
客戶方—供應(yīng)方(Customer-Supplier Development):當(dāng)2個團隊處于一種上游和下游關(guān)系時卖擅,上游團隊可能獨立于下游團隊完成開發(fā)鸣奔,此時下游團隊的開發(fā)可能會受到很大的影響墨技。因此,在上游團隊的計劃中挎狸,我們應(yīng)該顧及到下游團隊的需求扣汪,下游系統(tǒng)也可以先依賴擋板完成開發(fā)。
遵奉者(Conformist):在存在上下游關(guān)系的2個團隊中锨匆,如果上游團隊已經(jīng)沒有動力提供下游團隊之需崭别,下游團隊便孤軍無助了。處于利他主義恐锣,上游團隊可能向下游團隊做出種種承諾茅主,但是有很大的可能是:這些承諾是無法實現(xiàn)的。下游團隊只能盲目地使用上游團隊模型侥蒙。這個在日常工作中經(jīng)常會遇到例如銀行的核心系統(tǒng)是很強勢的暗膜,下游系統(tǒng)只能作為遵奉者使用核心系統(tǒng)提供的接口,再爛也要用鞭衩。学搜。。
防腐層(Anticorruption Layer):在集成2個設(shè)計良好的限界上下文時论衍,翻譯層可能很簡單瑞佩,甚至可以很優(yōu)雅的實現(xiàn)。但是坯台,當(dāng)共享內(nèi)核炬丸,合作關(guān)系或客戶方——供應(yīng)方關(guān)系無法順利實現(xiàn)時,此時的翻譯將變得復(fù)雜蜒蕾。對于下游客戶來說稠炬,你需要根據(jù)自己的領(lǐng)域模型創(chuàng)建一個單獨的層,該層作為上游系統(tǒng)的委派向你的系統(tǒng)提供功能咪啡。防腐層通過已有的接口與其他系統(tǒng)交互首启,而其他系統(tǒng)只需要做很小的修改,甚至無需修改撤摸。在防腐層內(nèi)部毅桃,它在你自己的模型和他方模型之間進行翻譯轉(zhuǎn)換。防腐層有點類似于設(shè)計模式中的Adapter模式准夷,幫不同領(lǐng)域之間的模型進行適配钥飞,這樣可以保證領(lǐng)域核心部分無需改動修改防腐層就能滿足需求。
開放主機服務(wù)(Open Host Service):定義一種協(xié)議衫嵌,讓你的子系統(tǒng)通過該協(xié)議來訪問你的服務(wù)读宙。并且需要將協(xié)議公開。開放服務(wù)的方式有很多楔绞,可以是rest api可以是TCP定長報文也可以是pb這樣的RPC協(xié)議格式结闸。
發(fā)布語言(Published Language):在2個限界上下文之間翻譯模型需要一種公用的語言掖棉。此時你應(yīng)該使用一種發(fā)布出來的共享語言來完成集成交流。發(fā)布語言通常與開放主機服務(wù)一起使用膀估。
大泥球(Big Ball of Mud):當(dāng)我們檢查已有系統(tǒng)時幔亥,經(jīng)常會發(fā)現(xiàn)系統(tǒng)中存在混雜在一起的模型,它們之間的邊界是非常模糊的察纯。此時你應(yīng)該為整個系統(tǒng)繪制一個邊界帕棉,然后將其歸納在大泥球范圍之列。在這個邊界內(nèi)饼记,不要試圖使用復(fù)雜的建模手段來化解問題香伴。同時,這樣的系統(tǒng)有可能會向其他系統(tǒng)蔓延具则,應(yīng)該對此保持警覺即纲。
本篇一股腦將DDD中常用的概念名詞都簡單解釋了一遍,后面會隨著我學(xué)習(xí)的深入再陸續(xù)產(chǎn)出一些個人對DDD理解的文章博肋,希望能幫助架構(gòu)師去學(xué)習(xí)DDD的設(shè)計理念低斋。