領域驅動設計(DDD)在百度愛番番的實踐

{"type":"doc","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"導讀:","attrs":{}},{"type":"text","text":"領域驅動設計(Domain Driven Design - DDD)起源於2004年Eric Evans出版《領域驅動設計》,相比於在國外IT圈享有盛譽且行之有效不同,國內IT圈瞭解DDD的人很少,落地實踐的少之又少。最近幾年隨着微服務架構的普及和中臺的興起,DDD也成了各大技術論壇和微信公衆號文章裏經常談起的話題。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"DDD的熱度是起來了,但業界介紹DDD的資料大多偏理論,缺乏生產項目可借鑑的實踐經驗。因此大多人讀了很多DDD材料後還是一臉懵,怎麼衡量DDD帶來的價值?老闆能同意搞DDD嗎?什麼樣的業務和團隊適合DDD?DDD跟互聯網強調的小步快跑快速迭代能搭嗎?如果要實踐DDD產研團隊都要做些啥?研發寫代碼跟平時有什麼不一樣?本文結合百度愛番番產研團隊在過去一年多經歷的從探索、推廣到全面落地DDD的過程,嘗試回答上述問題,力求給大家帶來一些借鑑意義。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"全文約9500字,預計閱讀時間25分鐘。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"1  初心:以客戶爲中心,產研團隊如何高效交付需求","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"百度愛番番圍繞營銷拓客和銷售提效幫助企業收集、擴充、清洗、培養、跟進和轉化線索。一方面愛番番的業務特點是典型的企業級(ToB)業務,具有一定的複雜度。業務對象多,單個業務對象提供的功能多,單個功能面向的場景多,業務對象之間組合出來的業務流程多。並且會隨着交付的功能越多而變的越複雜。另一方面產品處於爬坡階段,功能需要快速迭代交付到客戶,從而快速獲得客戶的反饋。產研團隊在資源一定的情況下如何高效交付更復雜的需求成爲了主要矛盾。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"分析當前階段需求迭代過程中的問題,可以總結爲以下幾類問題:","attrs":{}}]},{"type":"numberedlist","attrs":{"start":null,"normalizeStart":1},"content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":1,"align":null,"origin":null},"content":[{"type":"text","text":"業務邏輯不能從產品團隊精準傳遞到研發團隊,有時研發進行了一段時間開發才發現需求理解有偏差,導致需要重新跟產品經理討論需求。","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":2,"align":null,"origin":null},"content":[{"type":"text","text":"產品團隊和研發團隊對於業務複雜度沒有的認識不統一,產品經理認爲一個需求的開發不難,理應在較少時間內開發完畢。","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":3,"align":null,"origin":null},"content":[{"type":"text","text":"研發團隊面對需求增長和變化時,缺乏對業務邏輯的抽象,往往開發一個需要點需要改動多處,容易出錯且開發效率低,代碼維護性差。","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":4,"align":null,"origin":null},"content":[{"type":"text","text":"需求文檔和代碼邏輯不匹配,線上功能的業務邏輯爲什麼實現成那樣沒有依據可查,領域知識得不到沉澱,團隊得不到可持續成長。","attrs":{}}]}]}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"2  探索:找到適合的開發模式","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"上述問題集中體現在兩個方面,一是產品屬於企業應用類,功能本身複雜,如何讓產研團隊快速理解業務、快速交付。二是如何讓領域知識能夠比較準確的得到開發實現,讓代碼有比較好的可維護性。借鑑業內處理複雜企業級軟件的開發經驗,加上部分團隊成員曾經有過DDD使用的經驗,團隊決定嘗試運用DDD設計思想來指導產研團隊的日常需求迭代。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"2.1  DDD是啥?","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"DDD是一種圍繞領域建模來解決複雜業務交付的設計思想。讀者不妨自問幾個問題,什麼是複雜?什麼是領域建模?","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"1. 什麼是複雜?如何理解複雜?","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"複雜可能是現狀業務就複雜,也可能是業務日漸演變成複雜。複雜來自規模在變,比如幾個業務對象的邏輯不復雜,幾十上百個業務對象就會變得錯綜複雜。複雜來自結構化不足,比如下圖所示,結構化的中國結比非結構化的意大利麪更有序、易於大腦理解。此外,一旦協同方多了,如何協同不同團隊完成軟件交付也是一種複雜。","attrs":{}}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/ad/ad4de29fb82386ccbd592e8d87351c1a.png","alt":"圖片","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":"br"}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"2. 什麼是領域建模?","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"領域模型跟技術毫無關係,而是爲了更有結構化的拆解和表達業務邏輯。業務邏輯來自現實世界裏的具體場景,涉及可視畫面、操作動作和流程。要準確表達業務邏輯需要先講清楚每個概念是什麼,再建立概念之間的聯繫,基於這些關係再組合出更多的流程。概念、聯繫、流程就是領域模型。圍繞領域模型去表達業務時也自然而然地把技術實現細節分離出去了。後續代碼實現就是將業務架構映射到系統架構的過程,以後業務架構調整了能快速的調整技術架構。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"3. DDD中的領域如何理解?","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":"br"}},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"DDD中表示業務邏輯的領域概念是:實體、值對象、領域服務、領域事件。這意味着所有領域邏輯都應該在這四種對象裏,統一稱爲領域模型對象,這將極大減少業務邏輯的蔓延。","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"引入聚合進一步封裝實體和值對象,讓領域邏輯更內聚,起到邊界保護的作用。聚合的引入使得業務對象間的關聯變少。如何設計聚合見下面實踐部分。","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"圍繞聚合的操作引入工廠和資源庫。工廠負責複雜聚合的創建,資源庫負責聚合的加載、添加、修改、刪除。聚合內的實體狀態變更通過領域事件來推動。","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"引入應用服務,對領域邏輯編排、封裝。供上層接口層調用。一個應用服務就是一次編排,一次編排就是一個用戶用例。","attrs":{}}]}]}],"attrs":{}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"4. DDD領域概念詳細解釋和舉例","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"2.2  DDD如何開展?","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"DDD包含戰略設計、戰術設計、技術實現三個部分。戰略設計側重於高層次、宏觀上去劃分限界上下文,而戰術設計則關注使用建模工具來細化上下文,通過領域模型來表達業務。技術實現主要通過分層架構來隔離領域模型代表的業務邏輯和技術細節。一個整體過程大致包括:宏觀劃分各領域 → 領域內劃分限界上下文,定義上下文之間的關係 → 上下文內分析業務,識別領域概念,定義合適的領域概念 → 通過分層架構實現編碼,並驗證領域模型的合理性,必要時重新回到前面步驟重構領域模型。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"1. 戰略設計","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"戰略設計是團隊領導層或業務負責人關心的,該步驟需要針對產品願景、業務要解決的問題域,規劃核心域、通用域、支撐域,做合適的資源投入。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"什麼是領域和限界上下文?","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"領域代表現實世界的特定問題和解決方案的集合,比如銷售領域、營銷領域。DDD裏的限界上下文(Bouded Context)是對領域的軟件實現,比如線索系統、商機系統就是銷售領域內的限界上下文。限界上下文定義瞭解決方案的明顯邊界,邊界裏的每一個領域概念,包括領域概念內的屬性和行爲都有特殊含義。出了限界上下文這個邊界這層含義就不復存在。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"如何劃分限界上下文?","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"#1:根據相關性做歸類。一般是優先考慮功能相關性而不是語義相關性,比如創建訂單和支付訂單都是訂單語義,但功能相差比較大,應該劃分爲兩個限界上下文。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"#2:根據團隊粒度做裁剪、根據技術特點做裁剪。一些通用的技術功能應該儘可能歸攏到一個限界上下文,比如每個業務限界上下文都有監控,但監控能力應該歸攏到監控限界上下文。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"BC與微服務什麼關係?","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"微服務是包含高度相關功能的一個開發部署單元,有自己的技術自治性包括技術選型、彈性擴縮容、發佈上線頻率等,有自己的業務演變自治性。BC是根據領域邏輯的內聚情況形成的一個整體。一個微服務可以包含一個或多個BC,到底包含幾個?需要根據團隊大小、BC複雜度和技術特性來定。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"2. 戰術設計","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"DDD設計思想裏領域建模是最核心的一步,該階段主要目標是提煉和定義出領域模型和之間的關係。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"領域建模","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"建模就是設計的過程,建模的過程就是梳理、走查業務邏輯,拆解爲要解決的問題和涉及的業務場景、業務流程、業務概念,在這個過程中形成對應的領域概念。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如果團隊對於業務比較陌生適合採用事件風暴方法進行梳理;如果團隊對業務比較熟悉,如果業務流程相對簡單,則可以採用四色建模法進行業務梳理。採用這些分析業務的方法可以保證產研團隊對業務邏輯的理解在一個水平上。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"業務邏輯的顯性表達","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在完成了實體和值對象的設計後,有的時候會發現有些概念其實在領域上是存在的,但設計和代碼裏沒有Class來體現,可能僅僅是一個基本類型參數加上散落的對該參數的判斷檢驗邏輯,這個時候還需要思考應該把這個概念顯性化,定義專門的Class幷包含相應邏輯,入出參以相應Class爲類型。但凡業務代碼邏輯包含了一堆if-else,這時候需要考慮儘可能給這段邏輯建模成一個領域概念。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"比如CRM系統裏判斷一條線索是否爲推廣線索需要看線索的渠道屬性是否來自推廣平臺,那麼比較好的方式是這段邏輯用\"推廣線索\"這個概念來顯性表達,而不是淹沒在代碼裏不容易理解和維護。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"統一語言","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"爲了解決業務邏輯銜接的問題引入了統一語言。每個業務名詞的含義具有明確的定義,產品和研發都統一認識。沒有統一語言的溝通嚴重缺乏效率。比如CRM線索的概念,沒有統一語言的時候每個人的理解不一樣,有的人理解爲有過諮詢記錄的訪客是線索,有的人理解爲留下過聯繫方式的訪客是線索,有的人理解爲有購買意願的訪客是線索等等。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"有了統一語言描述,每個概念就有了明確定義,可以節省非常大的溝通交流成本。並且這個概念也同樣應用在相關的需求文檔、設計文檔、代碼編寫中。每個概念從引入到日常交流,從需求文檔到代碼實現都有了一致的表達,代碼實現和需求描述的真實度高,可理解性和可維護性就變好了。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"3. 技術實現","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"分層架構","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"爲了讓代碼實現圍繞領域模型開展,儘量降低業務代碼和純技術選型代碼的耦合,DDD引入了分層架構。確保了最核心的領域層不依賴其他層,反過來讓領域之外的代碼依賴領域代碼,降低了技術升級帶來的影響。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"DDD框架","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"框架內定義不同領域概念需要實現的接口,比如實現了聚合根接口的實體類就成爲了聚合的根實體。定義了異常管理規範,不同的分層應該拋出什麼類型的異常。定義了數據訪問的資源庫接口等等。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"領域事件","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"領域事件是對領域內發生的活動進行的建模,即聚合內的實體狀態變化的一個載體。DDD提倡限界上下文間儘量解耦,儘可能使用發佈訂閱領域事件的協作模式進行上下游解耦。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"2.3  DDD vs 數據模型驅動","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"傳統的業務開發模式裏,研發受到關係型數據庫設計範式、ER圖等影響深遠,在做軟件詳細設計過程中往往先想到如何設計對應的表結構,由此倒推出業務邏輯代碼該如何組織。這就是典型的數據模型驅動設計,或者叫面向數據表設計編程。數據模型設計關注的是數據存儲,數據儘量不要冗餘,控制表數量不膨脹,更多考慮數據的擴展性,比如新加一個字段儘量不要在幾張表都加,能用一個字段表達就不用兩個字段。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"這樣的思維跟DDD是相反的,DDD優先考慮領域概念的業務語義表達,具有獨立業務概念的東西會盡量抽象成一個內聚的領域對象。領域對象不僅僅有屬性,還有該有的行爲。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"因此,基於數據模型驅動的設計結果往往是:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"1. 業務邏輯代碼非常過程式,領域實體只包含一堆屬性,只是數據表的映射,沒有業務行爲。","attrs":{}},{"type":"text","text":"也就是常說的只有getter和setter方法的貧血對象。非常缺乏領域概念的表達,業務邏輯散亂。比如值對象的設計在DDD裏是一個類,在數據模型設計裏往往是其他類的幾個屬性。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"2. 聚合是DDD最小的複用單元,粒度更粗。","attrs":{}},{"type":"text","text":"數據模型設計裏領域實體的數量跟表數量一一對應,數據表是最小的複用單元,粒度太細。導致業務邏輯對應的實現類需要訪問很多的領域實體,實現類之間的調用關係發散而錯綜複雜。下圖是貧血模型和DDD富血模型的區別。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/71/71a4bad143dae2ba3839525b344c5319.webp","alt":"圖片","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"3. 數據表的關係表達很受限,具有主從關係的表之間很難看出主從。","attrs":{}},{"type":"text","text":"在DDD裏聚合和聚合內的實體、值對象之間的關係在代碼層面有顯示的表達。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"當然,DDD思想裏不是說不用考慮數據表設計,而是要優先考慮領域概念的識別和建模。表設計需要服務於領域模型的設計,是技術實現的細節。因此明白DDD和數據模型驅動設計的區別反過來能更好地理解DDD。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"3  實踐:案列分析","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"3.1  業務背景","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"以愛番番業務中\"線索\"功能舉例,線索管理功能特別多,有創建、清洗、分配、打標籤、跟進、回收、退回和轉化等十幾個管理動作。僅線索創建就分爲手工錄入創建、文件導入創建、營銷系統的後臺自動創建、開放平臺創建,創建還分爲單個創建和批量創建等等。線索這個對象跟其他對象比如客戶、商機等聯動組合出來很多場景和流程。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"3.2  規劃階段","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"規劃階段需要考慮產品願景和服務藍圖,需要劃分出產品的核心領域,支撐領域,通用領域。如果從0到1開發產品的話規劃階段需要做很多的工作,比如開發一個CRM產品需要考慮產品願景和服務藍圖,需要聚焦到哪些業務領域,是售前、售中還是售後?售前還可以細分爲營銷領域還是銷售領域等等。百度愛番番致力打造易用的、靈活可配的線索管家功能。因此銷售領域的線索功能自然是核心模塊。需要提供什麼線索功能?需要通過分析階段來拆解。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":"br"}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"3.3  分析階段","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"分析階段是基於業務流程和功能分析出具體的業務對象,不同的業務對象歸屬劃分到限界上下文。因爲線索功能複雜,團隊對於線索功能認知不一,有必要讓相關人員一起採用事件風暴方法來分析和梳理業務。事件風暴認爲事件流很⼤程度上反映了現實業務邏輯,參與人員基於領域事件發生的時間線,把事件的前因後果逐步挖掘出來。整個過程包含識別領域事件、決策命令、領域名詞三個步驟。通過嘗試回答這幾個問題:這個業務涉及的系統產生了什麼變化?變化由哪個角色通過什麼方式觸發的?系統變化產生了哪些結果?","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"基於上述步驟,領域專家和相關人員針對線索業務進行事件風暴的結果爲:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/de/de26f6df99a659f8bff18cb00c087fa6.png","alt":"圖片","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"事件風暴關鍵圖例:","attrs":{}}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/de/de9d29656e7b76a5523dd761334c60b7.png","alt":"圖片","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"事件風暴實踐過程的幾點tips:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"numberedlist","attrs":{"start":null,"normalizeStart":1},"content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":1,"align":null,"origin":null},"content":[{"type":"text","text":"事件流幾乎等同業務邏輯,以此來推敲業務邏輯的嚴密性,有果必有因。","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":2,"align":null,"origin":null},"content":[{"type":"text","text":"緊扣事件要素:事件、規則、名詞、命令、角色。","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":3,"align":null,"origin":null},"content":[{"type":"text","text":"命名:緊扣業務,不參雜技術元素,警惕使用泛泛的詞彙,儘可能地消除命名的⼆義性。","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":4,"align":null,"origin":null},"content":[{"type":"text","text":"優先關注happy-path即正常路徑,聚焦核心領域裏的路徑。","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":5,"align":null,"origin":null},"content":[{"type":"text","text":"事件風暴不是一蹴而就,保持迭代更新。","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":6,"align":null,"origin":null}}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"基於事件風暴的結果,需要把領域名詞和規則等劃分到合適的限界上下文。根據前面介紹的如何劃分限界上下文的方法,線索相關功能劃分爲幾個限界上下文合適呢?這個時候需要看業務邏輯的複雜程度,還要結合團隊規模大小。由於線索功能包含很多業務邏輯,線索歸集和創建、線索的分配、線索的跟進等都可以成爲一個獨立的限界上下文。定義好限界上下文後還需要定義不同限界上下文的協作關係。一般情況下如果業務允許的情況儘量選擇通過領域事件來協作。根據《領域驅動設計》所述常見的協作關係還包括開放主機服務(即通過暴露接口)、共享內核、防腐層等9種。微服務架構下的限界上下文之間的關係比較常見的有領域事件、開放主機服務、防腐層等。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"3.4  設計階段","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"設計階段就是把分析階段產出的領域名詞,領域事件,決策命令用DDD領域概念來承接,並細化每個領域概念的數據和行爲。這也是一種領域建模的過程。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"建議的建模過程是:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"numberedlist","attrs":{"start":null,"normalizeStart":1},"content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":1,"align":null,"origin":null},"content":[{"type":"text","text":"業務需求的分析過程自上而下,由業務流程,到用戶用例,到領域模型。而設計過程是自下而上的。從領域元素設計開始,最後纔是應用服務的編排。","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":2,"align":null,"origin":null},"content":[{"type":"text","text":"建議設計優先級是先值對象 → 再實體 → 再聚合 → 再領域服務→ 最後是應用服務,優先考慮領域是否應該爲值對象,其次是否爲實體,劃分出聚合。不屬於實體或值對象中的領域行爲放到領域服務,需要協調聚合的領域行爲設計爲領域服務或者應用服務。","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":3,"align":null,"origin":null},"content":[{"type":"text","text":"任何業務代碼邏輯優先映射到原子性的領域模型,比如值對象、實體、領域事件、資源庫接口、外部適配接口,其次再映射到組合性領域模型,比如領域服務、應用服務。","attrs":{}}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"建模過程中經常會被問到的問題有:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"1 值對象可以定義自己的行爲嗎?","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"可以,儘可能把屬於值對象自己的行爲放到值對象裏。比如聯繫方式定義成一個值對象,如果它的校驗只依賴自身數據,那校驗行爲應該屬於在聯繫方式這個值對象。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"2 聚合該設計爲多大粒度?","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"聚合設計要儘量小,如果一個實體不是根實體,但同時需要被外界直接訪問到,那麼這個實體不應該在這個聚合中,應該獨立成新的聚合。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"3 一個聚合如何訪問另外一個聚合?","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"只有聚合根纔是訪問聚合邊界的唯一入口,因此一個聚合需要通過另一個的聚合的聚合根來訪問它,聚合根可以理解爲聚合的根實體的Id。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"4 應用服務與領域服務的區別?","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"領域服務處在分層架構的領域層,是領域邏輯的一部分。應用服務處在應用層,負責領域模型的編排。當業務邏輯不屬於任何聚合時,應該考慮用領域服務來封裝這些邏輯。比如判定訂單是否重複,應該屬於訂單限界上下文的一種業務邏輯,訂單聚合本身不能判斷是否重複,因此訂單判重應該定義爲領域服務。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"5 應用服務可以直接調用聚合和資源庫嗎?","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"可以,可被應用服務編排的對象包括聚合、資源庫、領域服務和適配接口。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"6 領域事件內容是包含整個聚合裏的信息,還是身份標識信息(訂閱方再通過單獨接口根據標識進行查詢),還是隻包含聚合中一些特定的信息?","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"領域事件是用於跟其他聚合協作,事件內容不應是整個聚合,而是經過裁剪的特定信息。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"根據分析階段的產出結果,需要把領域名詞、規則映射到領域模型。主要幾個線索相關領域對象如下圖示:","attrs":{}}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/9b/9b614755b2b6a05471ed148d01547bb1.png","alt":"圖片","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"heading","attrs":{"align":null,"level":3}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"3.5  實現階段","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"傳統的接口-邏輯-數據訪問三層架構裏,業務邏輯層的XxxServiceImpl類是個上帝類,往往通過過程式業務邏輯實現。前幾行代碼做校驗,接下來做數據類型轉換,然後是業務處理邏輯的代碼,中間穿插着通過接口或者dao獲取更多的數據;拿到數據後,又是類型轉換代碼,然後接着一段業務邏輯代碼,最後可能還要落庫、發佈消息等等。這樣的代碼參雜了太多不同的代碼,非常難以維護。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"業界自從DDD的分層架構提出後陸續出現過洋蔥架構、六邊形架構、整潔架構等,其目標都是爲了分離業務和技術,保證領域模型的純粹性。下圖是結合業界架構實踐後定製的分層架構,具有以下幾個特點:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"numberedlist","attrs":{"start":null,"normalizeStart":1},"content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":1,"align":null,"origin":null},"content":[{"type":"text","text":"接口層負責對外暴露各種協議的接口比如http、tcp,轉換成應用服務能認識的協議。","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":2,"align":null,"origin":null},"content":[{"type":"text","text":"核心的領域層不依賴其他層,通過資源庫包下的接口定義做到依賴倒置,接口參數不能體現具體技術實現細節,領域模型裏的實現邏輯只依賴接口。這樣做到對領域邏輯的一層防腐。本層裏以聚合爲單位放置代碼,便於以後系統拆分,以聚合爲單位。","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":3,"align":null,"origin":null},"content":[{"type":"text","text":"應用層定義應用服務,一個接口對應業務場景的一個用例。此外應用層還可以處理橫切面事務比如啓動數據庫事務。","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":4,"align":null,"origin":null},"content":[{"type":"text","text":"基礎設施層完成資源庫的實際實現,以及領域層定義的其他接口的實現如對外部服務的訪問,領域事件發佈到消息隊列中間件等。","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":5,"align":null,"origin":null},"content":[{"type":"text","text":"分層架構還定義了每層的項目包結構,不同的領域概念和數據對象相應的命名規範。","attrs":{}}]}]}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/75/7584d98258f7d6619ca71ff704f9adcd.png","alt":"圖片","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"實現階段經常會被問到的問題有:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"1 每層應該用什麼類型數據對象承載和傳遞數據?","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如上面分層架構圖所示,接口層和應用服務層用DTO對象傳遞數據,領域層只能見到領域對象即聚合、實體Entity和值對象VO。應用服務層負責把DTO對象轉換成領域對象傳輸到領域層。基礎設施層用PO表示數據表,跟領域層調用時需要把PO和領域對象相互做轉換。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"2 repository和dao的區別?","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"聚合設計要儘量小,如果一個實體不是根實體,但同時需要被外界直接訪問到,那麼這個實體不應該在這個聚合中,應該獨立成新的聚合。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"3 領域事件的發佈應該在領域層還是應用層?","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"只要不會破壞各層的依賴順序,在哪發佈都行。取決於領域事件定義在哪層?一般推薦定義在領域層的聚合內。當然即便在應用層發佈事件也不會破壞依賴方向。因此聚合、領域服務、應用服務都可以發佈事件。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"3.6  代碼示例","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"以java代碼爲例,DDD骨架代碼包含了分層架構,每層就是一個maven pom項目,根據用途定義好了多層包結構,每個領域對象和數據傳輸對象都有具體的命名方式。基於自研的ddd-framework規範了不同領域對象需要實現的接口或繼承於特定的基類。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"總之,儘可能做到了能根據需求文檔裏的業務邏輯很快找到代碼所在之處,讓不同的代碼待在應該待的分層和包下面。團隊成員開玩笑說,現在開發業務代碼就像在做填空題,簡單直白。","attrs":{}}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/bd/bdc97d050adc6eb34a0d08b146220b63.png","alt":"圖片","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"heading","attrs":{"align":null,"level":3}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"3.7  收益","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"目前百度愛番番的新服務默認都會在符合DDD架構的骨架代碼基礎上開發,存量的核心模塊也進行過DDD改造。全面實施DDD後產研團隊目標更對齊,協作效率更高,收穫了很多收益,包括但不限於以下幾點:","attrs":{}}]},{"type":"numberedlist","attrs":{"start":null,"normalizeStart":1},"content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":1,"align":null,"origin":null},"content":[{"type":"text","text":"產研團隊協同成本降低,領域知識得到積累和沉澱。統一語言的使用和維護極大提高了大家對齊的成本。","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":2,"align":null,"origin":null},"content":[{"type":"text","text":"業務語義得到顯性表達,業務邏輯內聚可複用程度提高,避免了很多散彈式修改和發散式修改。一個需求不用改多個地方,多個需求也不用幾個研發集中改同一個地方。","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":3,"align":null,"origin":null},"content":[{"type":"text","text":"限界上下文的劃分從業務合理性出發,進而微服務的劃分會更合理,減少了團隊間的耦合和不必要的協同代價。","attrs":{}}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"numberedlist","attrs":{"start":null,"normalizeStart":1},"content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":1,"align":null,"origin":null},"content":[{"type":"text","text":"接口數量精簡、可控。由於業務代碼聚焦領域模型,邏輯內聚,複用性高,急劇減少了接口數量,降低接口維護成本。","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":2,"align":null,"origin":null},"content":[{"type":"text","text":"通過預定義好的腳手架創建符合DDD規範的代碼骨架,提高了新服務開發的效率。","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":3,"align":null,"origin":null},"content":[{"type":"text","text":"代碼可讀性高,不是代碼作者也能快速定位到代碼位置,代碼設計能夠得到傳承,可維護性也提高了。","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":4,"align":null,"origin":null},"content":[{"type":"text","text":"新人熟悉新業務和新代碼的速度極大提高,業務和技術知識的轉移代價減低。","attrs":{}}]}]}]},{"type":"heading","attrs":{"align":null,"level":3}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"3.8  實踐總結","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"從需求到交付的一次典型軟件開發流程包括收集提煉需求、需求分析、業務&技術設計、代碼實現、測試上線等環節。如何結合軟件開發流程,每個流程階段具體要做什麼、怎麼做,特別在編碼落地階段該有什麼保障措施?愛番番產研團隊在落地過程中逐步總結出了一套行之有效的DDD實施指南。包括規劃、分析、設計到實現四個階段對應的方法和產出等實施要點。","attrs":{}}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/e6/e646ef10df64d4ffa1672b67edac2743.png","alt":"圖片","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"heading","attrs":{"align":null,"level":2}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"4  結語:殊途同歸、沒有銀彈","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"DDD一方面使用分而治之的思想,引入劃分領域、限界上下文、模塊分層、劃分聚合在不同層次、不同粒度來降低問題的複雜度。另一方主張聚焦領域邏輯,通過不同手段來減少業務和技術的耦合。因此DDD只是大部分軟件設計思想一種,軟件設計的本質都是爲了高內聚低耦合。但是DDD並不是萬能的,不是所有業務開發場景都適合用DDD。有些簡單業務場景不使用DDD反而更恰當。因爲DDD有較高的學習門檻,需要整個團隊形成統一認識和協同,需要相應的編碼規範和架構落地。因此學習和落地DDD時要時刻記住自己的出發點是爲了應對現在或者將來的複雜業務領域而來。不必太拘泥於某些點是否遵守了DDD原則,如果覺得用了DDD會比沒有用好一點點,也值得邁出這一步。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"愛番番產研團隊始終秉持“以客戶爲中心”的理念,運用DDD設計思想構建統一的業務模型,實現業務功能的複用和融合。隨着愛番番業務的發展,我們相信DDD帶來的收益會更大。今後我們會從產品、技術、流程和組織方面持續關注能有效解決軟件工程複雜性問題的方法。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":"br"}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"本期作者|飛邪","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在百度愛番番主要負責銷售域和連通域的技術,長期關注技術團隊如何高效服務產品團隊等研發效能話題,擅長ToB企業級應用的規劃和落地。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"閱讀原文:","attrs":{}},{"type":"link","attrs":{"href":"https://mp.weixin.qq.com/s?__biz=Mzg5MjU0NTI5OQ==&mid=2247491684&idx=1&sn=58ab7fa7fe2f13c66d69b57fd95733e3&chksm=c03ed018f749590ec20396bad899c4f847d19ad23b59a86c1728dd50e385ca2a8a3a2aeb9bd0&token=73278986&lang=zh_CN#rd","title":"","type":null},"content":[{"type":"text","text":"領域驅動設計(DDD)在百度愛番番的實踐","attrs":{}}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"更多幹貨、內推福利,歡迎關注同名公衆號「百度Geek說」~","attrs":{}}]}]}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章