關(guān)于我們
書單推薦
新書推薦
|
實(shí)現(xiàn)領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)(DDD之父作序力薦 讓DDD思想真正落地的首創(chuàng)巨著)
領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)(DDD)是教我們?nèi)绾巫龊密浖模瑫r(shí)也是教我們?nèi)绾胃玫厥褂妹嫦驅(qū)ο蠹夹g(shù)的。它為我們提供了設(shè)計(jì)軟件的全新視角,同時(shí)也給開發(fā)者留下了一大難題:如何將領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)付諸實(shí)踐?Vaughn Vernon 的這本《實(shí)現(xiàn)領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)》為我們給出了全面的解答。
《實(shí)現(xiàn)領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)》分別從戰(zhàn)略和戰(zhàn)術(shù)層面詳盡地討論了如何實(shí)現(xiàn)DDD,其中包含了大量的最佳實(shí)踐、設(shè)計(jì)準(zhǔn)則和對(duì)一些問題的折中性討論。《實(shí)現(xiàn)領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)》共分為14 章,在DDD 戰(zhàn)略部分,《實(shí)現(xiàn)領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)》向我們講解了領(lǐng)域、限界上下文、上下文映射圖和架構(gòu)等內(nèi)容,戰(zhàn)術(shù)部分包括實(shí)體、值對(duì)象、領(lǐng)域服務(wù)、領(lǐng)域事件、聚合和資源庫(kù)等內(nèi)容。一個(gè)虛構(gòu)的案例研究貫穿全書,這對(duì)于實(shí)例講解DDD 實(shí)現(xiàn)來(lái)說(shuō)非常有用。 《實(shí)現(xiàn)領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)》在DDD 的思想和實(shí)現(xiàn)之間建立起了一座橋梁,架構(gòu)師和程序員均可閱讀,同時(shí)也可以作為一本DDD 參考書。
著譯俱佳 ThoughtWorks資深咨詢師傾力譯、! ⊥暾wDDD各方面知識(shí) 提供大量示例代碼 案例貫穿全書 理論與實(shí)踐緊密銜接之典范 架構(gòu)師、程序員境界提升不可或缺之必選書目
作者:Vaughn Vernon是一個(gè)經(jīng)驗(yàn)豐富的軟件工匠,在軟件設(shè)計(jì)、開發(fā)和架構(gòu)方面擁有超過(guò)25年的從業(yè)經(jīng)驗(yàn)。他提倡通過(guò)創(chuàng)新來(lái)簡(jiǎn)化軟件的設(shè)計(jì)和實(shí)現(xiàn)。從20世紀(jì)80年代開始,他便開始使用面向?qū)ο笳Z(yǔ)言進(jìn)行編程;在 20世紀(jì) 90年代早期,他便在領(lǐng)域建模中應(yīng)用了領(lǐng)域驅(qū)動(dòng)設(shè)計(jì),那時(shí)他使用的是Smalltalk語(yǔ)言。他在很多業(yè)務(wù)領(lǐng)域都有從業(yè)經(jīng)驗(yàn),包括航空、環(huán)境、地理、保險(xiǎn)、醫(yī)學(xué)和電信等領(lǐng)域。同時(shí),Vaughn在技術(shù)上也取得了很大的成功,包括開發(fā)可重用的框架和類庫(kù)等。他在全球范圍之內(nèi)提供軟件咨詢和演講,此外,他還在許多國(guó)家教授《實(shí)現(xiàn)領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)》的課程。
序 xix
前言 xxi 致謝 xxxi 關(guān)于作者 xxxv 如何使用本書xxxvii 第1章 DDD入門 我能DDD嗎? 為什么我們需要DDD 如何DDD 使用DDD的業(yè)務(wù)價(jià)值 1你獲得了一個(gè)非常有用的領(lǐng)域模型 2你的業(yè)務(wù)得到了更準(zhǔn)確的定義和理解 3領(lǐng)域?qū)<铱梢詾檐浖O(shè)計(jì)做出貢獻(xiàn) 4更好的用戶體驗(yàn) 5清晰的模型邊界 序 xix 前言 xxi 致謝 xxxi 關(guān)于作者 xxxv 如何使用本書xxxvii 第1章 DDD入門 我能DDD嗎? 為什么我們需要DDD 如何DDD 使用DDD的業(yè)務(wù)價(jià)值 1你獲得了一個(gè)非常有用的領(lǐng)域模型 2你的業(yè)務(wù)得到了更準(zhǔn)確的定義和理解 3領(lǐng)域?qū)<铱梢詾檐浖O(shè)計(jì)做出貢獻(xiàn) 4更好的用戶體驗(yàn) 5清晰的模型邊界 6更好的企業(yè)架構(gòu) 7敏捷、迭代式和持續(xù)建模 8使用戰(zhàn)略和戰(zhàn)術(shù)新工具 實(shí)施DDD所面臨的挑戰(zhàn) 虛構(gòu)的案例,真實(shí)的實(shí)踐 本章小結(jié) 第2章 領(lǐng)域、子域和限界上下文 總覽 工作中的子域和限界上下文 將關(guān)注點(diǎn)放在核心域上 戰(zhàn)略設(shè)計(jì)為什么重要 現(xiàn)實(shí)世界中領(lǐng)域和子域 理解限界上下文 限界上下文不僅僅只包含模型 限界上下文的大小 與技術(shù)組件保持一致 示例上下文 協(xié)作上下文 身份與訪問上下文 敏捷項(xiàng)目管理上下文 本章小結(jié) 第3章 上下文映射圖 上下文映射圖為什么重要 繪制上下文映射圖 產(chǎn)品和組織關(guān)系 映射3個(gè)示例限界上下文 本章小結(jié) 第4章 架構(gòu) 采訪一個(gè)成功的CIO 分層 依賴倒置原則 六邊形架構(gòu)(端口與適配器) 面向服務(wù)架構(gòu) REST REST作為一種架構(gòu)風(fēng)格 RESTful HTTP服務(wù)器的關(guān)鍵方面 RESTful HTTP客戶端的關(guān)鍵方面 REST和DDD 為什么是REST? 命令和查詢職責(zé)分離——CQRS CQRS的各個(gè)方面 處理具有最終一致性的查詢模型 事件驅(qū)動(dòng)架構(gòu) 管道和過(guò)濾器 長(zhǎng)時(shí)處理過(guò)程(也叫Saga) 事件源 數(shù)據(jù)網(wǎng)織和基于網(wǎng)格的分布式計(jì)算 數(shù)據(jù)復(fù)制 事件驅(qū)動(dòng)網(wǎng)織和領(lǐng)域事件 持續(xù)查詢 分布式處理 本章小結(jié) 第5章 實(shí)體 為什么使用實(shí)體 唯一標(biāo)識(shí) 用戶提供唯一標(biāo)識(shí) 應(yīng)用程序生成唯一標(biāo)識(shí) 持久化機(jī)制生成唯一標(biāo)識(shí) 另一個(gè)限界上下文提供唯一標(biāo)識(shí) 標(biāo)識(shí)生成時(shí)間 委派標(biāo)識(shí) 標(biāo)識(shí)穩(wěn)定性 發(fā)現(xiàn)實(shí)體及其本質(zhì)特征 揭開實(shí)體及其本質(zhì)特征的神秘面紗 挖掘?qū)嶓w的關(guān)鍵行為 角色和職責(zé) 創(chuàng)建實(shí)體 驗(yàn)證 跟蹤變化 本章小結(jié) 第6章 值對(duì)象 值對(duì)象的特征 度量或描述 不變性 概念整體 可替換性 值對(duì)象相等性 無(wú)副作用行為 最小化集成 用值對(duì)象表示標(biāo)準(zhǔn)類型 測(cè)試值對(duì)象 實(shí)現(xiàn) 持久化值對(duì)象 拒絕由數(shù)據(jù)建模泄漏帶來(lái)的不利影響 ORM與單個(gè)值對(duì)象 多個(gè)值對(duì)象序列化到單個(gè)列中 使用數(shù)據(jù)庫(kù)實(shí)體保存多個(gè)值對(duì)象 使用聯(lián)合表保存多個(gè)值對(duì)象 ORM與枚舉狀態(tài)對(duì)象 本章小結(jié) 第7章 領(lǐng)域服務(wù) 什么是領(lǐng)域服務(wù)(首先,什么不是領(lǐng)域服務(wù)) 請(qǐng)確定你是否需要一個(gè)領(lǐng)域服務(wù) 建模領(lǐng)域服務(wù) 獨(dú)立接口有必要嗎 一個(gè)計(jì)算過(guò)程 轉(zhuǎn)換服務(wù) 為領(lǐng)域服務(wù)創(chuàng)建一個(gè)迷你層 測(cè)試領(lǐng)域服務(wù) 本章小結(jié) 第8章 領(lǐng)域事件 何時(shí)/為什么使用領(lǐng)域事件 建模領(lǐng)域事件 創(chuàng)建具有聚合特征的領(lǐng)域事件 身份標(biāo)識(shí) 從領(lǐng)域模型中發(fā)布領(lǐng)域事件 發(fā)送方 訂閱方 向遠(yuǎn)程限界上下文發(fā)布領(lǐng)域事件 消息設(shè)施的一致性 自治服務(wù)和系統(tǒng) 容許時(shí)延 事件存儲(chǔ) 轉(zhuǎn)發(fā)存儲(chǔ)事件的架構(gòu)風(fēng)格 以REST資源的方式發(fā)布事件通知 通過(guò)消息中間件發(fā)布事件通知 實(shí)現(xiàn) 發(fā)布NotificationLog 發(fā)布基于消息的事件通知 本章小結(jié) 第9章 模塊 通過(guò)模塊完成設(shè)計(jì) 模塊的基本命名規(guī)范 領(lǐng)域模型的命名規(guī)范 敏捷項(xiàng)目管理上下文中的模塊 其他層中的模塊 先考慮模塊,再是限界上下文 本章小結(jié) 第10章 聚合 在Scrum核心領(lǐng)域中使用聚合 第一次嘗試:臃腫的聚合 第二次嘗試:多個(gè)聚合 原則:在一致性邊界之內(nèi)建模真正的不變條件 原則:設(shè)計(jì)小聚合 不要相信每一個(gè)用例 原則:通過(guò)唯一標(biāo)識(shí)引用其他聚合 通過(guò)標(biāo)識(shí)引用使多個(gè)聚合協(xié)同工作 建模對(duì)象導(dǎo)航性 可伸縮性和分布式 原則:在邊界之外使用最終一致性 誰(shuí)的任務(wù)? 打破原則的理由 理由之一:方便用戶界面 理由之二:缺乏技術(shù)機(jī)制 理由之三:全局事務(wù) 理由之四:查詢性能 遵循原則 通過(guò)發(fā)現(xiàn),深入理解 重新思考設(shè)計(jì) 估算聚合成本 常見用例場(chǎng)景 內(nèi)存消耗 探索另外的設(shè)計(jì) 實(shí)現(xiàn)最終一致性 這是Scrum團(tuán)隊(duì)成員的任務(wù)嗎? 決定的時(shí)候到了 實(shí)現(xiàn) 創(chuàng)建具有唯一標(biāo)識(shí)的根實(shí)體 優(yōu)先使用值對(duì)象 使用迪米特法則和“告訴而非詢問”原則 樂觀并發(fā) 避免依賴注入 本章小結(jié) 第11章 工廠 領(lǐng)域模型中的工廠 聚合根中的工廠方法 創(chuàng)建CalendarEntry實(shí)例 創(chuàng)建Discussion實(shí)例 領(lǐng)域服務(wù)中的工廠 本章小結(jié) 第12章 資源庫(kù) 面向集合資源庫(kù) Hibernate實(shí)現(xiàn) TopLink實(shí)現(xiàn) 面向持久化資源庫(kù) Coherence實(shí)現(xiàn) MongoDB實(shí)現(xiàn) 額外的行為 管理事務(wù) 警告 類型層級(jí) 資源庫(kù) vs 數(shù)據(jù)訪問對(duì)象(DAO) 測(cè)試資源庫(kù) 以內(nèi)存實(shí)現(xiàn)進(jìn)行測(cè)試 本章小結(jié) 第13章 集成限界上下文 集成基礎(chǔ)知識(shí) 分布式系統(tǒng)之間存在根本性區(qū)別 跨系統(tǒng)邊界交換信息 通過(guò)REST資源集成限界上下文 實(shí)現(xiàn)REST資源 使用防腐層實(shí)現(xiàn)REST客戶端 通過(guò)消息集成限界上下文 從Scrum的產(chǎn)品負(fù)責(zé)人和團(tuán)隊(duì)成員處得到持續(xù)通知 你能處理這樣的職責(zé)嗎? 長(zhǎng)時(shí)處理過(guò)程,以及避免職責(zé) 長(zhǎng)時(shí)處理過(guò)程的狀態(tài)機(jī)和超時(shí)跟蹤器 設(shè)計(jì)一個(gè)更復(fù)雜的長(zhǎng)時(shí)處理過(guò)程 當(dāng)消息機(jī)制或你的系統(tǒng)不可用時(shí) 本章小結(jié) 第14章 應(yīng)用程序 用戶界面 渲染領(lǐng)域?qū)ο? 渲染數(shù)據(jù)傳輸對(duì)象 使用調(diào)停者發(fā)布聚合的內(nèi)部狀態(tài) 通過(guò)領(lǐng)域負(fù)載對(duì)象渲染聚合實(shí)例 聚合實(shí)例的狀態(tài)展現(xiàn) 用例優(yōu)化資源庫(kù)查詢 處理不同類型的客戶端 渲染適配器以及處理用戶編輯 應(yīng)用服務(wù) 示例應(yīng)用服務(wù) 解耦服務(wù)輸出 組合多個(gè)限界上下文 基礎(chǔ)設(shè)施 企業(yè)組件容器 本章小結(jié) 附錄A 聚合與事件源:A+ES 應(yīng)用服務(wù)內(nèi)部 命令處理器 Lambda語(yǔ)法 并發(fā)控制 A+ES所帶來(lái)的結(jié)構(gòu)自由性 性能 實(shí)現(xiàn)事件存儲(chǔ) 關(guān)系型持久化 BLOB持久化 專注的聚合 讀模型投射 與聚合設(shè)計(jì)一道使用 增強(qiáng)事件 工具和模式 事件序列器 事件不變性 值對(duì)象 協(xié)議生成 單元測(cè)試和需求規(guī)范 事件源和函數(shù)式語(yǔ)言 參考文獻(xiàn)
所有的計(jì)算都表明它不工作,唯一的做法是:使其工作。 ——Pierre-Georges Latécoère早期法國(guó)航空企業(yè)家
是的,我們將使其工作。然而,在軟件開發(fā)過(guò)程中采用領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)卻是困難的。即便是有能力的開發(fā)者,也很難找到實(shí)現(xiàn)領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)的正確方法。 起飛,著陸 在我小的時(shí)候,我的父親學(xué)習(xí)過(guò)駕駛小型飛機(jī)。我們經(jīng)常會(huì)全家出去飛行,有時(shí)會(huì)飛到另一個(gè)機(jī)場(chǎng),在那里吃過(guò)午飯后再返回。當(dāng)父親時(shí)間有限而他依然想飛時(shí),父親便帶上我一起在機(jī)場(chǎng)上空盤旋,起飛,著陸,再起飛,再著陸。 也會(huì)有些長(zhǎng)途飛行,這時(shí)我們會(huì)帶上一張由父親先前繪制好的路線圖。我們幾個(gè)小孩便當(dāng)起了領(lǐng)航員:將圖上的標(biāo)志對(duì)應(yīng)著陸地上的地標(biāo),以確保我們沒有跑偏航線。這是一件很有趣的事情,因?yàn)橐R(shí)別遠(yuǎn)在地面上的物體是很有挑戰(zhàn)性的。事實(shí)上,我敢肯定父親根本不用我們領(lǐng)航便知道我們處于什么方位——他能看到儀表盤上的所有信息,并且他擁有儀表飛行執(zhí)照。 空中的景觀的確改變了我的視野。不時(shí)地,父親和我會(huì)飛過(guò)我們鄉(xiāng)下的房子。在幾百英尺的高空中,我體會(huì)到了另一種“家”的概念,而這在之前是沒有過(guò)的。當(dāng)我們飛過(guò)自家的房子時(shí),母親和我的姐妹們便會(huì)跑到院子里向我們揮手。我知道那是她們,即便我看不清楚她們是誰(shuí)。談話肯定是不行的,連大聲喊都不行,她們是聽不見的。我還可以看到將我家和外面公路分開的護(hù)欄,平時(shí)我們會(huì)像走平衡木一樣在護(hù)欄上面走來(lái)走去。從空中看,它們就像被細(xì)心編排過(guò)的小樹枝一樣。我們 家的院子很大,每每到了夏天,我都會(huì)開著割草機(jī)一排一排地修理院子里的草坪。而在空中時(shí),我只能看到一片綠色,小草的葉子肯定是看不清楚的。 我喜歡在空中的時(shí)刻,直到現(xiàn)在我還不時(shí)回想起這些時(shí)刻,好像那個(gè)降落飛 機(jī)的黃昏就發(fā)生在不久以前一樣。雖然如此,在地面上的感覺依然是無(wú)法取代的, 因?yàn)樗o我一種腳踏實(shí)地的感覺。 著陸于領(lǐng)域驅(qū)動(dòng)設(shè)計(jì) 一開始接觸領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)( DDD)就像一個(gè)小孩之于飛行一樣。天空中的景色是令人驚嘆的,但有時(shí)我們卻因?yàn)檫^(guò)于陌生而搞不明白它們到底是什么。要從甲地到乙地顯得如此的遙遠(yuǎn)。然而, DDD的“成年人 ”們卻總知道他們所處的方位,因?yàn)樗麄冊(cè)诤茉缰氨憷L制好了路線圖,并且能夠完全按照儀表進(jìn)行相應(yīng)的操作。而還有很多人找不到“在地面上”的感覺,此時(shí)我們需要的是“穩(wěn)定著陸”的能力,然后找到一張地圖給我們指引方向。 Eric Evans的《領(lǐng)域驅(qū)動(dòng)設(shè)計(jì):軟件核心復(fù)雜性應(yīng)對(duì)之道》是一本經(jīng)得住時(shí)間考驗(yàn)的經(jīng)典之作。我堅(jiān)定地相信,在接下來(lái)的幾十年里,本書依然會(huì)是開發(fā)者的實(shí)用指導(dǎo)。和其他模式一樣,該書為我們建立起了一種高屋建瓴式的寬闊視野。然而,對(duì)于如何實(shí)現(xiàn) DDD,我們可能將面對(duì)更多的挑戰(zhàn)。通常來(lái)說(shuō),我們更渴望看到一些具體的例子。 我的目標(biāo)之一便是幫助你來(lái)一個(gè)“軟著陸”,保全飛機(jī),然后沿著一條周知的線路帶你回家。這將幫助你如何更好地去實(shí)現(xiàn) DDD,并且通過(guò)你所熟悉的工具和技術(shù)給出示例演示。當(dāng)然,任何一個(gè)人都不可能一直呆在家里,所以我還會(huì)帶領(lǐng)你到新的地帶去冒險(xiǎn),這些地帶你可能從來(lái)沒有去過(guò)。冒險(xiǎn)之路是險(xiǎn)峻的,但是在正確的戰(zhàn)術(shù)應(yīng)對(duì)下,征服這些困難是可能的。在這條冒險(xiǎn)之路上,你將學(xué)到另外的架構(gòu)和模式來(lái)集成多個(gè)領(lǐng)域模型。你將接觸到先前沒有被研究過(guò)的集成方法,并且學(xué)到如何開發(fā)自治性服務(wù)。 我將向你提供一張對(duì)短途旅行和長(zhǎng)途旅行均適用的地圖,它可以幫助你更好地享受沿途風(fēng)景,同時(shí)又不至于迷失途中。 對(duì)照地形,繪制飛行圖 在軟件開發(fā)的過(guò)程中,我們經(jīng)常做的一件事便是將一種東西映射到另一種東西。我們將對(duì)象映射到數(shù)據(jù)庫(kù),映射到用戶界面,或者映射到不同的應(yīng)用層展現(xiàn)(包括作為消費(fèi)方的其他系統(tǒng)或應(yīng)用程序)。在所有這些映射中,我們很自然地希望在Evans提出的高層模式和具體實(shí)現(xiàn)之間存在一種映射。 即便你已經(jīng)接觸過(guò) DDD,你依然有很多可以獲益的地方。有時(shí), DDD首先被看作是一套技術(shù)工具集,有人將此稱為 DDD-Lite。我們可能已經(jīng)對(duì)實(shí)體、服務(wù)等 DDD概念非常熟悉了,并且大膽地嘗試著設(shè)計(jì)聚合,還通過(guò)資源庫(kù)來(lái)管理持久化。這些模式是大家相對(duì)熟知的,使用起來(lái)很容易,我們甚至還使用了值對(duì)象。以上這些都屬于戰(zhàn)術(shù)設(shè)計(jì)模式范疇,也即更加偏向技術(shù)層面。這些模式可以很好地幫我們解決軟件問題。而同時(shí),對(duì)于戰(zhàn)術(shù)性模式,我們依然有許多需要學(xué)習(xí)的。我將戰(zhàn)術(shù)模式映射到實(shí)現(xiàn)層面。 你曾了解過(guò)戰(zhàn)術(shù)建模之外的東西嗎?你曾了解過(guò)被稱為 DDD“另一半”的戰(zhàn)略設(shè)計(jì)模式嗎?如果你還沒有使用過(guò)限界上下文和上下文映射圖,那么你很有可能也沒有使用過(guò)通用語(yǔ)言。 如果說(shuō) Evans在軟件開發(fā)社區(qū)有一項(xiàng)發(fā)明,那便是通用語(yǔ)言。通用語(yǔ)言是一種團(tuán)隊(duì)協(xié)作模式,用于捕捉特定業(yè)務(wù)領(lǐng)域中的概念和術(shù)語(yǔ)。一個(gè)特定領(lǐng)域的軟件模型通過(guò)不同的名詞、形容詞和動(dòng)詞來(lái)表達(dá),這些詞匯是開發(fā)團(tuán)隊(duì)正式使用的,而團(tuán)隊(duì)中應(yīng)該包含一個(gè)或多個(gè)領(lǐng)域?qū)<。然而,將通用語(yǔ)言僅限定于一些詞匯則是錯(cuò)誤的。就像自然語(yǔ)言反映人們的思想一樣, DDD的通用語(yǔ)言反映了領(lǐng)域?qū)<覍?duì)于軟件系統(tǒng)的思維模型。通用語(yǔ)言和那些戰(zhàn)略和戰(zhàn)術(shù)性的建模模式同等重要,在有些情況下甚至更具有持久性。 簡(jiǎn)單地講, DDD-Lite將導(dǎo)致劣質(zhì)的領(lǐng)域?qū)ο螅驗(yàn)橥ㄓ谜Z(yǔ)言、限界上下文和上下文映射圖的作用太大了,你從其中獲得的并不只是一套團(tuán)隊(duì)共用的語(yǔ)言。在限界上下文中用通用語(yǔ)言來(lái)表述一個(gè)領(lǐng)域模型可以增加業(yè)務(wù)價(jià)值,并且使我們確信所開發(fā)軟件的正確性。即使從技術(shù)的角度,它也可以幫助我們創(chuàng)建更好的領(lǐng)域模型,這樣的模型行為豐滿,業(yè)務(wù)純凈,并且可以減少犯錯(cuò)誤的可能性。因此,我將戰(zhàn)略設(shè)計(jì)模式映射到了可理解的實(shí)際例子中。 本書對(duì)于 DDD的映射可以幫助你同時(shí)體會(huì)到戰(zhàn)略設(shè)計(jì)和戰(zhàn)術(shù)設(shè)計(jì)的好處。通過(guò)一些具體的例子,你將感受到這些 DDD映射的業(yè)務(wù)價(jià)值和技術(shù)展現(xiàn)力。 如果我們對(duì)于 DDD的所有實(shí)踐都只是停留在“地面上”,那將是令人失望的。過(guò)度地拘泥于細(xì)節(jié)將使我們喪失在空中俯瞰的機(jī)會(huì)。所以,不要將自己局限在地面的細(xì)節(jié)上,要勇敢地飛翔在空中,居高臨下。搭上戰(zhàn)略設(shè)計(jì)的航班,去了解限界上下文和上下文映射圖,你將獲得更廣闊的視野。當(dāng)你從 DDD的航班中獲益時(shí),我的目的也就達(dá)到了。 各章概要 以下是各章的主要內(nèi)容以及你將如何從中獲益。 第1章:DDD入門 本章向你介紹 DDD的好處,并且教你如何盡可能多地去實(shí)現(xiàn) DDD。你將學(xué)到當(dāng)你在應(yīng)對(duì)復(fù)雜的軟件系統(tǒng)時(shí), DDD可以為你的項(xiàng)目和團(tuán)隊(duì)帶來(lái)什么。同時(shí),你將了解到通常的 DDD替代方案以及這些方案為什么會(huì)導(dǎo)致問題。作為對(duì) DDD的基礎(chǔ)講解,本章將教你如何在項(xiàng)目中開始采用 DDD,還有如何向你的領(lǐng)域?qū)<液图夹g(shù)團(tuán)隊(duì)推銷 DDD。在DDD的武裝下,你將學(xué)會(huì)如何迎接挑戰(zhàn),勇往直前。 本章將介紹關(guān)于一個(gè)公司及其團(tuán)隊(duì)的案例研究,雖然該公司是虛構(gòu)的,但是他們所面臨的 DDD挑戰(zhàn)卻是真實(shí)存在的。該公司旨在開發(fā)一個(gè)新的多租戶 SaaS(Software as a Service,軟件即服務(wù))軟件產(chǎn)品。不出所料,在使用 DDD時(shí),他們犯了一些常見的錯(cuò)誤。不過(guò)還好,他們發(fā)現(xiàn)了這些錯(cuò)誤,并解決了一些問題,因此項(xiàng)目還算沒有偏離正軌。該團(tuán)隊(duì)需要開發(fā)一套基于 Scrum的項(xiàng)目管理軟件。該案例還會(huì)在本書的后續(xù)章節(jié)中連續(xù)講到。每一種戰(zhàn)略和戰(zhàn)術(shù)模式都將教給這個(gè)團(tuán)隊(duì)。在這個(gè)過(guò)程中,團(tuán)隊(duì)有誤入歧途的時(shí)候,但最終他們將向著成功的 DDD實(shí)踐昂首闊步。 第2章:領(lǐng)域、子域和限界上下文 領(lǐng)域、子域和核心域分別是什么?限界上下文是什么,我們?yōu)槭裁匆褂盟,并且如何使用?這些問題將在這個(gè) SaaS項(xiàng)目團(tuán)隊(duì)犯錯(cuò)誤的時(shí)候給予解答。在他們的第一個(gè) DDD項(xiàng)目中,他們并不了解子域、限界上下文和通用語(yǔ)言這些概念。事實(shí)上,他們根本不知道什么是戰(zhàn)略設(shè)計(jì),只是采用了戰(zhàn)術(shù)設(shè)計(jì)來(lái)解決一些技術(shù)問題。這樣他們?cè)陂_始設(shè)計(jì)領(lǐng)域模型的時(shí)候便遇到了不少問題。幸運(yùn)的是,他們及時(shí)地意識(shí)到了這些問題,項(xiàng)目還有挽回的余地。 本章還講到了如何使用限界上下文對(duì)模型進(jìn)行分離,這是非常重要的;同時(shí)還講到了一些模型分離不當(dāng)?shù)姆蠢,并且給出了有效的實(shí)現(xiàn)建議。在采用了這些建議之后,該團(tuán)隊(duì)的成員們重新創(chuàng)建了兩個(gè)不同的限界上下文。這種合理的模型分離帶來(lái)的好處是引出了第三個(gè)限界上下文——核心域,這將是本書使用的主要例子。 對(duì)于那些苦于單單從技術(shù)層面應(yīng)用 DDD的人來(lái)說(shuō),本章應(yīng)該能引起你的共鳴。如果你還是 DDD戰(zhàn)略設(shè)計(jì)的外行,那么本章將為你指明方向。 第 3章:上下文映射圖 上下文映射圖幫助我們理解業(yè)務(wù)領(lǐng)域、模型間的邊界,以及這些模型之間的集成方式。 上下文映射圖絕對(duì)不只是繪制系統(tǒng)架構(gòu)圖這么簡(jiǎn)單,它處理的是不同限界上下文之間的關(guān)系,以及如何在不同的模型之間映射對(duì)象。對(duì)于在復(fù)雜的業(yè)務(wù)系統(tǒng)中使用好限界上下文,這是至關(guān)重要的。在第 2章中,團(tuán)隊(duì)成員們?cè)谑状螄L試限界上下文時(shí)碰到了問題。本章中,他們將學(xué)著如何利用上下文映射圖來(lái)解決這些問題。這樣的結(jié)果是產(chǎn)生了兩個(gè)體面的限界上下文,這兩個(gè)上下文將被另外一個(gè)負(fù)責(zé)核心域的團(tuán)隊(duì)所使用。 第 4章:架構(gòu) 我們都知道分層架構(gòu),但它是開發(fā) DDD軟件的唯一方式嗎,也或許還存在另外的方式?在本章中,我們將講到:六邊形架構(gòu)(端口和適配器)、面向服務(wù)架構(gòu)、REST、CQRS、事件驅(qū)動(dòng)(管道和過(guò)濾器,長(zhǎng)時(shí)處理過(guò)程,事件源)和數(shù)據(jù)網(wǎng)格,其中好幾種架構(gòu)都將被該團(tuán)隊(duì)成員所采用。 第 5章:實(shí)體 在DDD的戰(zhàn)術(shù)模式中,我們將首先講到實(shí)體。團(tuán)隊(duì)成員們一開始過(guò)于強(qiáng)調(diào)實(shí)體的作用而忽視了值對(duì)象。受到數(shù)據(jù)庫(kù)和持久化框架的影響,實(shí)體被該團(tuán)隊(duì)濫用了,此時(shí)他們開始討論如何避免大范圍地使用實(shí)體。 在本章中,你將看到很多優(yōu)秀的實(shí)體設(shè)計(jì)例子。同時(shí),本章還將講到如何使用實(shí)體來(lái)表達(dá)通用語(yǔ)言,以及如何對(duì)實(shí)體進(jìn)行測(cè)試、實(shí)現(xiàn)和持久化。 第 6章:值對(duì)象 早些時(shí)候,團(tuán)隊(duì)成員們錯(cuò)過(guò)了采用值對(duì)象的好機(jī)會(huì)。他們過(guò)于注重為實(shí)體創(chuàng)建一些單一的屬性,這種方式是欠妥的,更好的方式是將這些單一的屬性聚合成一個(gè)不變的整體。本章將從不同的角度講解如何設(shè)計(jì)值對(duì)象,以及在什么時(shí)候采用值對(duì)象會(huì)優(yōu)于實(shí)體。同時(shí),本章還包含了一些其他話題,比如值對(duì)象在集成中的角色和對(duì)標(biāo)準(zhǔn)類型的建模等。然后,本章講到了如何設(shè)計(jì)以領(lǐng)域?yàn)橹行牡臏y(cè)試,如何實(shí)現(xiàn)值對(duì)象。此外,本章還講到了在聚合中存儲(chǔ)值對(duì)象時(shí),如何避免持久化機(jī)制所帶來(lái)的不利影響。 第 7章:領(lǐng)域服務(wù) 本章將講到,在領(lǐng)域模型中,什么時(shí)候應(yīng)該將一個(gè)概念建模成粒度適中,并且無(wú)狀態(tài)的領(lǐng)域服務(wù)。你將學(xué)到何時(shí)應(yīng)該使用領(lǐng)域服務(wù)而不是實(shí)體或值對(duì)象,以及如何使用領(lǐng)域服務(wù)來(lái)處理業(yè)務(wù)邏輯和技術(shù)上的集成。團(tuán)隊(duì)成員們向我們展示了何時(shí)應(yīng)該使用領(lǐng)域服務(wù),以及如何設(shè)計(jì)領(lǐng)域服務(wù)。 第 8章:領(lǐng)域事件 Eric Evans并沒有在他的書中正式介紹領(lǐng)域事件,領(lǐng)域事件是在他那本書出版之后才進(jìn)入人們視野的。在本章中,你將學(xué)到為什么領(lǐng)域事件如此有用,以及使用領(lǐng)域事件的不同方法。領(lǐng)域事件甚至被用來(lái)輔助集成和自治性服務(wù)。在軟件系統(tǒng)中,我們經(jīng)常使用一些技術(shù)層面的事件機(jī)制,但本章將著重講解領(lǐng)域事件與這些事件機(jī)制的區(qū)別。本章還將指導(dǎo)你如何設(shè)計(jì)并實(shí)現(xiàn)領(lǐng)域事件,包括一些可行的方案和對(duì)這些方案的權(quán)衡選擇。然后,本章將講到如何創(chuàng)建一個(gè)發(fā)布 -訂閱機(jī)制;如何利用事件來(lái)集成整個(gè)企業(yè)軟件中的各個(gè)訂閱方;如何創(chuàng)建和管理事件存儲(chǔ);如何處理消息機(jī)制所面臨的常見挑戰(zhàn)等。 第 9章:模塊 對(duì)于模型中的對(duì)象,我們應(yīng)該如何將他們組織在大小適中的容器中呢?我們又如何保證不同容器中的對(duì)象之間只存在有限的耦合?另外,我們?nèi)绾螌?duì)這些容器進(jìn)行命名以體現(xiàn)通用語(yǔ)言?除了包和命名空間之外,我們?nèi)绾问褂糜烧Z(yǔ)言和框架提供的現(xiàn)代模塊化機(jī)制,比如 OSGi和Jigsaw?在本章中,你將看到 SaaS團(tuán)隊(duì)成員是如何在不同的項(xiàng)目中使用模塊的。 第 10章:聚合 在DDD的戰(zhàn)術(shù)模式中,聚合可能是最不容易理解的了。然而,在遵循一定的經(jīng)驗(yàn)法則的情況下,我們是能夠更簡(jiǎn)單、更快地實(shí)現(xiàn)聚合的。在本章中你將學(xué)到:如何利用聚合在不同的小規(guī)模對(duì)象集群間創(chuàng)建一致性邊界,從而降低模型的復(fù)雜性。由于在細(xì)枝末節(jié)上花了太多精力, SaaS團(tuán)隊(duì)成員們?cè)谠O(shè)計(jì)聚合時(shí)總是磕磕絆絆。我們將仔細(xì)研究該團(tuán)隊(duì)所面臨的挑戰(zhàn),并且分析錯(cuò)誤的原因以及他們的應(yīng)對(duì)策略。結(jié)果,團(tuán)隊(duì)成員們對(duì)他們的核心域有了更深層次的理解。我們將看到,在合理的事務(wù)處理和保證最終一致性(Eventual Consistency)的前提下,該團(tuán)隊(duì)更正了他們所犯的錯(cuò)誤,并且在一個(gè)分布式環(huán)境中設(shè)計(jì)出了更具有伸縮性和更高效的模型。 第 11章:工廠 工廠已經(jīng)在 [Gamma et al.]中被大量地談及了,為什么還要講呢?本章并不打算重蹈覆轍,而是將重點(diǎn)放在“工廠應(yīng)該存在于何處”這個(gè)問題上。在本章中,我們將講到在 DDD中實(shí)現(xiàn)工廠的技巧。團(tuán)隊(duì)成員在他們的核心域中創(chuàng)建的工廠可以簡(jiǎn)化客戶端接口,并且對(duì)模型的消費(fèi)方起到保護(hù)作用,從而避免了在多租戶環(huán)境中引入災(zāi)難性的 bug。 第 12章:資源庫(kù) 資源庫(kù)只是一個(gè)數(shù)據(jù)訪問對(duì)象( Data Access Object, DAO)嗎?如果不是,它們之間有什么區(qū)別呢?我們?yōu)槭裁磻?yīng)該將資源庫(kù)看成是對(duì)集合的模擬而非數(shù)據(jù)庫(kù)呢?在本章中,我們將講到如何利用 ORM來(lái)實(shí)現(xiàn)資源庫(kù),其中有兩種 ORM方案,一種采用基于網(wǎng)格的分布式緩存,另一種則采用 NoSQL的鍵值對(duì)存儲(chǔ)。團(tuán)隊(duì)成員們可以采用任何一種作為他們的持久化機(jī)制。 第 13章:集成限界上下文 到現(xiàn)在為止,你已經(jīng)了解了戰(zhàn)略層次的上下文映射圖和多種戰(zhàn)術(shù)層次的模式。本章將講到,在 DDD中,我們?nèi)绾瓮ㄟ^(guò)上下文映射圖來(lái)集成不同的模型。在團(tuán)隊(duì)對(duì)核心域和其他輔助性的限界上下文進(jìn)行集成時(shí),我們將給出相應(yīng)的建議和指導(dǎo)。 第14章:應(yīng)用程序 對(duì)于每一個(gè)核心域的通用語(yǔ)言,我們都設(shè)計(jì)了相應(yīng)的模型,并且進(jìn)行了足夠的測(cè)試,模型工作正常。然而,客戶應(yīng)該如何使用我們的模型呢?他們應(yīng)該使用 DTO將數(shù)據(jù)在模型和用戶界面之間傳輸嗎?或者存在其他方案可以實(shí)現(xiàn)模型和展現(xiàn)組件間的數(shù)據(jù)傳遞? DDD中的應(yīng)用服務(wù)和基礎(chǔ)設(shè)施是如何工作的?對(duì)于這些問題,本章都將做出解答。 附錄A:聚合與事件源: A+ES 事件源是一種持久化聚合的重要技術(shù),同時(shí)也是事件驅(qū)動(dòng)架構(gòu)的基礎(chǔ)。事件源通過(guò)一系列的事件來(lái)表示聚合的所有狀態(tài)。通過(guò)有序的事件重放,我們可以重新構(gòu)建聚合的狀態(tài)。當(dāng)然,使用事件源的前提是:它能夠簡(jiǎn)化對(duì)數(shù)據(jù)的持久化,并且能夠捕捉到那些具有復(fù)雜行為屬性的概念。 Java和開發(fā)工具 本書中的絕大多數(shù)例子都是使用 Java語(yǔ)言編寫的。我本來(lái)可以用 C#的,但是我有意識(shí)地使用了 Java。 首先,我認(rèn)為 Java社區(qū)正在拋棄好的軟件設(shè)計(jì)和開發(fā)實(shí)踐,F(xiàn)在,對(duì)于多數(shù) Java項(xiàng)目而言,要在其中找到一個(gè)好的領(lǐng)域?qū)ο罂峙率抢щy的。在我看來(lái), Scrum和敏捷被人們看成了優(yōu)良設(shè)計(jì)的替代品,而其中的產(chǎn)品待定項(xiàng)(Product Backlog)被看成了設(shè)計(jì)本身。多數(shù)敏捷人士并不會(huì)過(guò)多地去思考這些待定項(xiàng)是否會(huì)影響到業(yè)務(wù)模型。我得說(shuō)明, Scrum的本意絕對(duì)不是要取代設(shè)計(jì)。不管有多少項(xiàng)目經(jīng)理想將你捆綁在持續(xù)交付這條路上,我得說(shuō) Scrum并不僅僅是要取悅于那些甘特圖( Gantt chart)的追隨者們。然而,太多的時(shí)候,情況的確是這樣的。 我認(rèn)為這是個(gè)很大的問題,所以我想鼓勵(lì) Java社區(qū)重新回到領(lǐng)域建模中來(lái),同時(shí)我會(huì)通過(guò)本書向大家說(shuō)明,設(shè)計(jì)是可以使我們獲益的。 此外,在 .NET社區(qū)中已經(jīng)有很好的DDD資源了,比如Jimmy Nilsson的《領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)與模式實(shí)戰(zhàn)》[Nilsson]。由于Jimmy的出色工作和其他人對(duì)Alt.NET的倡導(dǎo),.NET社區(qū)中正掀起一陣優(yōu)秀設(shè)計(jì)的開發(fā)浪潮,這是Java社區(qū)需要注意的。 其次,我意識(shí)到 C#.NET人員在理解 Java代碼上并不存在什么困難。由于很多 DDD社區(qū)的人都在使用 C#.NET,而本書的早期校對(duì)人員也都是 C#程序員,但是我從來(lái)就沒有收到他們的抱怨。因此,我便不用顧慮這些了。 在我寫這本書時(shí),業(yè)內(nèi)正將目光從關(guān)系型數(shù)據(jù)庫(kù)轉(zhuǎn)向基于文檔和鍵值對(duì)的存儲(chǔ)方案。這是有原因的, Martin Fowler將這些存儲(chǔ)方案稱為“面向聚合存儲(chǔ)”。這種命名是恰當(dāng)?shù)模芎玫孛枋隽嗽?DDD中使用 NoSQL的好處。 但是,就我從事咨詢的經(jīng)驗(yàn)來(lái)看,很多開發(fā)者還是認(rèn)定了關(guān)系型數(shù)據(jù)庫(kù)和對(duì)象-關(guān)系映射。因此我想, NoSQL追隨者們應(yīng)該能夠理解我在書中包含對(duì)象 -關(guān)系映射的章節(jié)。然而,我的確得承認(rèn),這可能會(huì)招致那些認(rèn)為存在對(duì)象 -關(guān)系阻抗失配(Object-Relational Impedance)的人的鄙視。這無(wú)所謂,對(duì)此我表示接受,因?yàn)榻^大多數(shù)人在他們的日常工作中都還得面對(duì)這種對(duì)象 -關(guān)系阻抗失配。 當(dāng)然,在第 12章“資源庫(kù)”中,我同樣提供了基于文檔的、鍵值對(duì)的和數(shù)據(jù)網(wǎng)格的存儲(chǔ)方案。在多處地方,我都討論到了 NoSQL對(duì)聚合設(shè)計(jì)的影響。 NoSQL趨勢(shì)很有可能持續(xù)下去,那些對(duì)象 -關(guān)系型的開發(fā)者們應(yīng)該注意了。在本書中你將看到,我能夠同時(shí)理解兩個(gè)陣營(yíng)的觀點(diǎn),并且對(duì)于雙方的觀點(diǎn)我都同意。這些都是技術(shù)趨勢(shì)所導(dǎo)致的摩擦,而這對(duì)于積極的變革是有必要的。
你還可能感興趣
我要評(píng)論
|