架構設計篇之領域驅動設計(DDD)

{"type":"doc","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"本篇文章基於Eric Evans作者和翻譯作者孫向暉,霍泰穩的書,做的軟件思想筆記,向作者們致敬。"}]},{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"不要畏懼你所不知道的領域,如果你有需要,那麼就搞定它。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" - 劉曉成@小誠信驛站"}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":1},"content":[{"type":"text","text":"一、定義"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"領域驅動設計的定義:"}]},{"type":"paragraph","attrs":{"indent":1,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"領域驅動設計,其實就是業務驅動設計,通過軟件開發架構師和開發人員與最熟悉該領域的業務專家一起勾勒出需求領域模型去實際解決業務場景遇到的問題。"}]},{"type":"heading","attrs":{"align":null,"level":1},"content":[{"type":"text","text":"二、核心"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"DDD核心是什麼?"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" DDD核心是關注精簡的業務模型及實現的匹配。"}]},{"type":"heading","attrs":{"align":null,"level":1},"content":[{"type":"text","text":"三、爲什麼需要DDD?"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"DDD希望解決什麼問題?"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"目前我們使用的面向對象程序設計,也有面向過程程序設計,爲什麼還需要領域驅動設計?"}]},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":1,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"設計之選擇性的三個問題"}]}]}]},{"type":"numberedlist","attrs":{"start":1,"normalizeStart":1},"content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":2,"number":1,"align":null,"origin":null},"content":[{"type":"text","text":"在面向對象編程的過程中,哪些對象是對我們的系統有用的?("},{"type":"text","marks":[{"type":"color","attrs":{"color":"#FF7021","name":"orange"}},{"type":"strong"}],"text":"精簡業務模型"},{"type":"text","text":")"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":2,"number":2,"align":null,"origin":null},"content":[{"type":"text","text":"哪些是對我們擬建系統沒有用處的?("},{"type":"text","marks":[{"type":"color","attrs":{"color":"#FF7021","name":"orange"}},{"type":"strong"}],"text":"剋制系統邊界,需求邊界"},{"type":"text","text":")"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":2,"number":3,"align":null,"origin":null},"content":[{"type":"text","text":"我們應該如何保證我們選取的模型對象恰好夠用?("},{"type":"text","marks":[{"type":"color","attrs":{"color":"#FF7021","name":"orange"}},{"type":"strong"}],"text":"適度不蔓延,不泛化"},{"type":"text","text":")"}]}]}]},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":1,"number":4,"align":null,"origin":null},"content":[{"type":"text","text":"設計之封裝邊界的問題"}]}]}]},{"type":"numberedlist","attrs":{"start":1,"normalizeStart":1},"content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":2,"number":1,"align":null,"origin":null},"content":[{"type":"text","text":"對象封裝解決的一部分對象關聯依賴關係。但是如何更高點的層次上,通過保留對象之間有用的關係去除無用的關係,並且限定變更影響的範圍來降低系統的複雜度?(去除無用的關係,更好的封裝不變需求範圍)"}]}]}]},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":1,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"設計之業務和研發思維問題"}]}]}]},{"type":"numberedlist","attrs":{"start":1,"normalizeStart":1},"content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":2,"number":1,"align":null,"origin":null},"content":[{"type":"text","text":"開發人員會沉溺於技術思維,對業務理解和深入付出很少。業務理解對於技術實現不能理解,只想表達業務視角看到的內容。"}]}]}]},{"type":"paragraph","attrs":{"indent":2,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" 解決方式:看清楚我們提煉出的模型,在整個架構和整個開發過程中所處的位置和地位。"}]},{"type":"numberedlist","attrs":{"start":2,"normalizeStart":1},"content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":2,"number":1,"align":null,"origin":null},"content":[{"type":"text","text":"如何處理模型和對象實現"}]}]}]},{"type":"paragraph","attrs":{"indent":2,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" 解決方式: 哪些具有什麼樣素質和技能的人來處理模型和對象實現,應該用什麼樣團隊模型來匹配業務模型"}]},{"type":"numberedlist","attrs":{"start":1,"normalizeStart":1},"content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":2,"number":1,"align":null,"origin":null},"content":[{"type":"text","text":"如何應用開源項目設計思想和歷史項目設計思想?"}]}]}]},{"type":"paragraph","attrs":{"indent":2,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" 解決方式:盡信書不如無書,切勿生搬硬套,要有自己的方法論,進行切合實際場景的使用。"}]},{"type":"heading","attrs":{"align":null,"level":1},"content":[{"type":"text","text":"四、DDD方法論"}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"4.1、理解你的領域,熟悉你的業務"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" 所有的技術實現都是圍繞業務場景開展,在一個系統設計之前一定要充分理解你的應用場景。業務的需求(痛點),你要從哪個切入點(抓手)開展?從根本上看,你解決了什麼問題?"}]},{"type":"numberedlist","attrs":{"start":1,"normalizeStart":1},"content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":1,"number":1,"align":null,"origin":null},"content":[{"type":"text","text":"軟件和領域和諧相處其實就是軟件更好的爲你所涉及的業務領域服務。我們需要做的是理解你的業務領域核心概念和元素,並精確實現它們之間的關係。"},{"type":"text","marks":[{"type":"color","attrs":{"color":"#FF7021","name":"orange"}},{"type":"strong"}],"text":"軟件需要對領域進行建模"},{"type":"text","text":"。"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":1,"number":2,"align":null,"origin":null},"content":[{"type":"text","text":"那麼這裏的問題點是我們應該保留什麼?放棄什麼?"},{"type":"text","marks":[{"type":"color","attrs":{"color":"#FF7021","name":"orange"}},{"type":"strong"}],"text":"軟件需要對領域進行抽象"},{"type":"text","text":"。"}]}]}]},{"type":"paragraph","attrs":{"indent":1,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" 我們比如是滴滴的客服系統,則我們應該更好的記錄用戶的問題,解答客戶的問題,放棄商業化的售賣東西。"}]},{"type":"paragraph","attrs":{"indent":1,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" 我們比如是淘寶的運營系統,則我們應該更好的記錄用戶的購買轉化率,點擊率,曝光率,直接下單率,雙11同環比GMV,以及淨利潤營收等,而不應該關注用戶是否可以用滴滴APP打到車,美團APP是否可以下單訂到外賣。"}]},{"type":"numberedlist","attrs":{"start":3,"normalizeStart":3},"content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":3,"align":null,"origin":null},"content":[{"type":"text","text":"那麼領域專家和技術專家如何共享知識和信息,"},{"type":"text","marks":[{"type":"color","attrs":{"color":"#FF7021","name":"orange"}},{"type":"strong"}],"text":"軟件需要對領域進行交流"},{"type":"text","text":"。"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" 3.1、比如將模型圖形化:圖、用例、畫和圖片等(UML少量元素的場景來描述)。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" 3.2、針對要交流的領域內的特定問題建立一種語言(prd原型圖)"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" 3.3、用代碼作爲語言溝通,優秀的高可維護性的代碼(僞代碼來約定)"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"4.2、構建領域知識,實踐你的業務"}]},{"type":"paragraph","attrs":{"indent":1,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"對於你的業務和你不熟悉的領域,都需要從0-1開始構建你的業務領域知識體系。"}]},{"type":"numberedlist","attrs":{"start":1,"normalizeStart":1},"content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":1,"number":1,"align":null,"origin":null},"content":[{"type":"text","text":"構建的方式,最好的方式是交流"}]}]}]},{"type":"paragraph","attrs":{"indent":1,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" 與領域專家交談,比如淘寶的運營系統是和運營和商家交談,比如滴滴客服系統是跟滴滴的客服和司機乘客交談。你需要儘可能多地從專家處學 習領域知識。通過提出正確的問題,正確地處理得到的信息,你和專家會開始勾勒領域的骨架視圖,也就是領域模型。這種骨架視圖既不完整也不能保證是正確的,但它卻是你需要的開始點,可以盡 力判斷出領域的基礎性概念。比如美人魚電影中的警察根據報警人員的描述,勾勒出美人魚的畫像("},{"type":"text","marks":[{"type":"color","attrs":{"color":"#FF7021","name":"orange"}},{"type":"strong"}],"text":"初期領域建模不一定非常正確或者完美,但一定是盡力還原領域業務專家的描述"},{"type":"text","text":")。"}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/8d/8d7829bb0d5692bd69ed832d5bc5a5e7.png","alt":null,"title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":1,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"2.構建時間損耗,多次溝通不耐其煩"}]},{"type":"paragraph","attrs":{"indent":1,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"軟件架構師和開發人員和領域專家,會在一起創建領域的模型,可能這個過程需要耗時很久很久,但是爲了目標最後的建模的準確性,這個"},{"type":"text","marks":[{"type":"color","attrs":{"color":"#FF7021","name":"orange"}},{"type":"strong"}],"text":"多次溝通是最有效的方式"},{"type":"text","text":"。"}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"4.3、模型驅動設計,模型設計完成編碼"}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"4.3.1、我們應該如何動手處理從模型到代碼的轉換"}]},{"type":"paragraph","attrs":{"indent":1,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" 從分析模型出發,中間可以過程化編程(函數調用和數據結構算法來表達),如果是複雜的模型驅動,則不建議過程化編程,可以僞代碼實現。"}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"4.3.2、模型驅動設計的基本構成要素"}]},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"text","text":"4.3.2.1、分層架構設計之邏輯清晰(MVC)"}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/a8/a825aef5108de95937416eb99e53f686.png","alt":null,"title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/96/968f279a3d1b97423bb2af321308885b.png","alt":null,"title":null,"style":null,"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":"上面的的4個概念層其實就是我們所說的view- controller- service(domain)- dao(mapper),是不是非常符合我們的MVC架構。"}]},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"text","text":" 4.3.2.2、實體與值對象(entity與各種O)"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"建議選擇那些符合實體定義的對象作爲實體,將剩下的對象處理成值對象,沒有標識符,值對象就可以被輕易地創建或者丟棄。沒有人關心創建一個標識符,在沒有其他對象引用時,垃圾回收會處理這個對象。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"一條箴言是:值對象就是我們所說的dto或者vo,根據entity或者domain實體產生的多個副本(派生的對象)。"}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/df/dfdabeb6f10ef6c3cf8e538ad4848147.png","alt":null,"title":null,"style":null,"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}},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"text","text":" 4.3.2.3、服務(系統服務)"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"一個服務應該不是對通常屬於領域對象的操作的替代。我們不應該 爲每一個需要的操作來建立一個服務。但是當一個操作凸現爲一個領域中的重要概念時,就需要爲它建立一個服務了。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"以下是服務的3個特徵:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"1. 服務執行的操作涉及一個領域概念,這個領域概念通常不屬於一 個實體或者值對象。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"2.被執行的操作涉及到領域中的其他的對象。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"3.操作是無狀態的。"}]},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"text","text":" 4.3.2.4、模塊(功能模塊)"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"對一個大型的複雜項目,模型趨向很大。模型到達了一 個作爲整體很難討論的點,理解不同部件之間的關係和交互變得很 困難。將模型組織進模塊。模塊被用來作爲組織相關概念和任務以便降低複雜性的一種方法。"}]}]}]},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"text","text":"4.3.2.5、聚合(對象的封裝組合)"}]},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"聚合是一個用來定義對象所有權和邊界的領域模式。工廠和數據庫,用來幫助我們處 理對象的創建和存儲問題"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"一個模型會包含衆多的領域對象。不管在設計時做了多少考慮,我們都會看到許多對象會跟其他的對象發生關聯,形成了一個複雜的關係網"}]}]}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/18/18b763ec8c286b202a0edbcdd474cc96.png","alt":null,"title":null,"style":null,"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}},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"text","text":"4.3.2.6、工廠(工廠方法和抽象工廠)"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"工廠方法和抽象工廠,只關心對象的創建和強化所有的不變量,返回對那個對象的引用或者拷貝"}]},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"text","text":"4.3.2.7、資源庫(數據庫)"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"從數據庫或者new創建到刪除或者gc回收的過程"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"使用一個資源庫,它的目的是封裝所有獲取對象引用所需的邏輯。領域對象不需處理基礎設施,以得到領域中對其他對象的所需的引用。只需從資源庫中獲取它們,於是模型重獲它應有的清晰和焦點。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"資源庫會保存對某些對象的引用。當一個對象被創建出來時,它可以被保存到資源庫中,然後以後使用時可從資源庫中檢索到。如果 客戶程序從資源庫中請求一個對象,而資源庫中並沒有它,就會從 存儲介質中獲取它。換種說法是,資源庫作爲一個全局的可訪問對 象的存儲點而存在。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"資源庫可能包含一定的策略。它可能基於一個特定的策略來訪問某個或者另一個持久化存儲介質。它可能會對不同類型的對象使用不 同的存儲位置。最終結果是領域模型同需要保存的對象和它們的引 用中解耦,可以訪問潛在的持久化基礎設施。(如下圖式例)"}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/ba/ba3fc72fdcae29078a17c8a93b066e78.png","alt":null,"title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"資源庫的接口是純粹的領域模型(比如根據業務場景實現的查找用戶或者添加用戶的功能)"}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/d5/d5795331a93a9e716d8a48ee453e6cee.png","alt":null,"title":null,"style":null,"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}},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"text","text":"4.3.2.8、規約(比如API約定,接口文檔,交互協議等)"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"指定一個查詢條件,規約允許定義更復雜的條件。來提供服務支持。"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"4.3.3、面向深層理解的重構"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"基於模型驅動設計從模型我們開發用代碼進行了表達,以及對於業務領域進行了基本構成拆分形成了一個服務或者多個服務系統。正如我們之前所說的領域模型初期不一定非常完美切合業務場景。那麼隨着不斷深入瞭解業務以及功能逐漸完善,重構也是在這個過程中必不可少的環節。持續重構將是保證我們的好的方案以及應對變化的需求的保障護航艦隊。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#FF7021","name":"orange"}},{"type":"strong"}],"text":"一個好的模型產生於深層的思考、理解、經驗和才能"},{"type":"text","text":"。"}]}]}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"4.3.3.1、持續重構"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"設計方案應對需求的變化"}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"4.3.3.2、凸顯關鍵概念"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"業務領域建模的時候,約束(限制條件,校驗參數)、過程(實現業務的邏輯過程)和 規約(約定的接口文檔交互方式等)這些是一些關鍵的核心概念,而這些需要我們不斷完善,但並不是要經常變動的。"}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"4.3.3.3、保持模型一致性(每個領域保證業務領域模型與整體一致)"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"之前我們說過,針對業務專家描述的業務領域可能會有部分需要獨立部署服務系統,那麼這些單獨部署的服務系統,從整體上來看應該都符合整體業務領域模型的內容。"}]},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"劃清邊界,界定上下文"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"比如分層領域,需要界定應用上下文,每個系統服務的職能。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"持續集成"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"持續集成是基於模型中概念的集成,然後再通過測試實現。任何不完整的模型在實現過程中都會被檢測出來。持續集成應用於界定的上下文,不會被用來處理相鄰上下文之間的關係。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"上下文映射"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"(Context Map)是指抽象出不同界定上下文和它們之間關係的文 檔,它可以是像下面所說的一個試圖(Diagram),也可以是其他任何寫就的文檔。"}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/1d/1dedff2726d352f7744fbf89773fa616.png","alt":null,"title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"共享內核(共享基礎服務)"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"共享內核的目的是減少重複,但是仍保持兩個獨立的上下文。對於 共享內核的開發需要多加小心。兩個開發團隊都有可能修改內核代 碼,還要必須整合所做的修改。如果團隊用的是內核代碼的副本, 那麼要儘可能早地融合( Merge)代碼,至少每週一次。還應該使 用測試工具,這樣每一個針對內核的修改都能快速地被測試。內核 的任何改變都應該通知另一個團隊,團隊之間密切溝通,使大家都 能瞭解最新的功能。"}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/51/515513cd51c5462a5a72a7c21347b4a0.png","alt":null,"title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"客戶和供應商---實際上是上下游系統"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"順從者(如何應對內部需求堆積,合理協配外部需求)"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"防奔潰層(實際上指的是如何應對模型針對不同外部需求的服務變化可以用門面模式,適配層處理)"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/ff/ffc57e34a816dd2d7e3ee01323c6d70b.png","alt":null,"title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"獨立方法(獨立服務部署)"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"實際上指的是如果我們的領域模型 不相關的服務內容可以作爲獨立的服務部署和實現。"}]},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"開放主機服務(提煉核心服務,核心業務)"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"系統的核心域要看我們如何理解系統。精煉模型。找到核心域,發現一個能輕鬆地從支持模型和代碼中區 分核心域的方法。強調最有價值和特殊的概念。使核心變小。"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"4.3.4、實踐DDD的方式"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"numberedlist","attrs":{"start":null,"normalizeStart":1},"content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":1,"align":null,"origin":null},"content":[{"type":"text","text":"購買現成的方案。 這個方法的好處是可以使用別人已經做好 的全套方案。隨之而來的是學習曲線的問題,而且這樣的方 案還會引入其他麻煩。比如如果代碼有湊五,你只得等待別 人來解決。你還需要使用特定的編譯器和類庫版本。和自己 系統的集成也不是那麼容易。"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":2,"align":null,"origin":null},"content":[{"type":"text","text":"外包。 將設計和實現交給另外一個團隊,有可能是其他公司 的。這樣做可以使你專注於核心域,從處理其他領域的重壓 下釋放出來。不便的地方是集成外包的代碼。需要和子域通 信的結構需要預先定義好,還要和外包團隊保持溝通。"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":3,"align":null,"origin":null},"content":[{"type":"text","text":"已有模型。 一個取巧的方案是使用一個已經創建的模型。世 面上已經有一些關於分析模型的書,可以作爲我們子域的靈 感來源。直接複製原有的模型不太現實,但確實有些只需要 做少許改動就可以用了。"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":4,"align":null,"origin":null},"content":[{"type":"text","text":"自己實現。 這個方案的好處是能夠做到最好的集成,但這也 意味着額外的付出,包括維護的壓力等。"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":1},"content":[{"type":"text","text":"五、DDD的思維陷進"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"numberedlist","attrs":{"start":null,"normalizeStart":1},"content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":1,"align":null,"origin":null},"content":[{"type":"text","text":"事必躬親。模型需要代碼。"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":2,"align":null,"origin":null},"content":[{"type":"text","text":"專注於具體場景。抽象思維需要落地於具體案例。"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":3,"align":null,"origin":null},"content":[{"type":"text","text":"不要試圖對任何事情都進行領域驅動設計。畫一張範圍表,然後 決定哪些應該進行領域驅動設計,哪些不用。不要擔心邊界之外的事情。也就是說不要蔓延,要剋制。"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":4,"align":null,"origin":null},"content":[{"type":"text","text":"不停地實驗,期望能產生錯誤。模型是一個創造性的流程。"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"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":" "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}}]}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章