8/16開始,10/16結(jié)束檢視閱讀。慚愧,其實(shí)不算檢視閱讀,還有點(diǎn)分析閱讀了,總覺得自己閱讀方法把握還是不夠,不能充分有效地利用時間,我想,我完全按照檢視閱讀的要求去看一本技術(shù)書,最后能得到多少知識呢?還是值得一試的,看看自己的器量。
Eric Evans
domain-driven design
借鑒 Christopher Alexander 的建筑設(shè)計模式語言模式組織本書,同設(shè)計模式作者一樣從他身上得到了影響。
本以為才開始,沒想到是巔峰
聚焦于軟件的核心領(lǐng)域,以它來驅(qū)動開發(fā)。核心領(lǐng)域是核心競爭力,是利潤所在的地方,也是最值得下功夫的地方,再難也不能逃避。
領(lǐng)域模型并不是按照先建模,后實(shí)現(xiàn)來工作的,一般是在系統(tǒng)初始版本完成之后迭代,才有最好的想法的。
Eric清楚地表明他像我們大多數(shù)人一樣,既品嘗過成功的美酒,也體驗過失敗的沮喪。重要的是他能夠從成功和失敗中學(xué)習(xí)。
第一遍讀后感
總的來說這本書的思想是想要提供一種像建筑學(xué)那樣通用的模式設(shè)計語言來促使軟件的構(gòu)建更加地靈活,易懂且有效。跟設(shè)計模式相同點(diǎn)就是提供一種模式思路和通用語言想法,不同點(diǎn)是設(shè)計模式主要用于解決技術(shù)問題,而領(lǐng)域驅(qū)動設(shè)計更偏向于讓我們與領(lǐng)域?qū)<乙黄馂樗獦?gòu)建的業(yè)務(wù)領(lǐng)域知識設(shè)計一個更好的業(yè)務(wù)知識模型。前面的理論大體上是看得懂了,但后面幾章中的模式方法因為純理論沒有深入實(shí)踐理解,腦子浮躁,所以根本弄不清楚到底是怎么回事,怎么使用,也因此,到最后兩章直接放棄不看了。雖然不看了,但這只是第一遍,還會有第二,第三遍的,所以繼往開來,有個總體的印象和知識,這個目的是達(dá)到了的,等后面自己要設(shè)計一個系統(tǒng)時,再來參考實(shí)踐這些方法,邊學(xué)變練。
紙上得來終覺淺,絕知此事要躬行。
前言
跟設(shè)計模式一樣,領(lǐng)域設(shè)計也有一套技術(shù)詞匯庫,方便設(shè)計開發(fā)者之間交流溝通。
領(lǐng)域驅(qū)動設(shè)計的效果目標(biāo)是——交付后能夠滿足組織后續(xù)需求,不斷演進(jìn)擴(kuò)展。擴(kuò)展性
誤區(qū):僅靠使用模型并不會是項目達(dá)到富有擴(kuò)展性這樣的良性循環(huán)。注意建模(設(shè)計人員)與實(shí)現(xiàn)(開發(fā)人員)不能相脫節(jié)。這樣會導(dǎo)致設(shè)計無法反映不斷深化的分析。
領(lǐng)域驅(qū)動設(shè)計對應(yīng)的開發(fā)過程為——敏捷開發(fā)過程。
迭代開發(fā)。
開發(fā)人員與領(lǐng)域莊佳具有密切的關(guān)系。
極限編程最適合哪些對設(shè)計的感覺很敏銳的開發(fā)人員。
學(xué)習(xí)目標(biāo):學(xué)會用高級建模和設(shè)計技巧來解決實(shí)際問題。
核心章節(jié):引言、1、2、3、9、14
第三和第四部分很有必要重新研讀,里面都是寫模式方法的使用和舉例。
閱讀本書的方式:已掌握的知識可以采取跳躍式閱讀的方式,通過閱讀標(biāo)題和粗體字內(nèi)容掌握要點(diǎn)。高級讀者可以跳過前兩部分,重點(diǎn)閱讀第三、四部分內(nèi)容。(這兩部分是方法論實(shí)踐)
團(tuán)隊成員共同應(yīng)用領(lǐng)域驅(qū)動設(shè)計方法就有了一種公共語言,可以進(jìn)行更充分的溝通,創(chuàng)建出一個與模型步調(diào)一致的實(shí)現(xiàn)。
p17 圖形關(guān)系
一、讓領(lǐng)域模式發(fā)揮作用
三個基本用途決定了模型的選擇。
軟件的核心是其為用戶解決領(lǐng)域相關(guān)的問題的能力。
理解領(lǐng)域驅(qū)動設(shè)計核心目的的故事。
開發(fā)人員可以采用一些系統(tǒng)性的思考方法來透徹的理解領(lǐng)域并開發(fā)出有效的模型。還有一些設(shè)計技術(shù)可以使毫無頭緒的軟件應(yīng)用程序開發(fā)工作變得井井有條。掌握這些技巧可以令開發(fā)人員身價倍增,即使是在一個最初不熟悉的領(lǐng)域中也是如此。(即使是在一個最初不熟悉的領(lǐng)域中也是如此?)
消化業(yè)務(wù)知識
有效建模的要素:
模型和實(shí)現(xiàn)的綁定。
獲得了一種基于模型的語言。(方便溝通)
開發(fā)一個蘊(yùn)含豐富知識的模型。
提煉模型。
頭腦風(fēng)暴和實(shí)驗。
領(lǐng)域模型的不斷精化迫使開發(fā)人員學(xué)習(xí)重要的業(yè)務(wù)原理(深入理解業(yè)務(wù)知識和思想),而不是機(jī)械地進(jìn)行功能的開發(fā)。領(lǐng)域?qū)<冶黄忍釤捵约核赖闹匾R的過程往往也是完善其自身理解的過程,而且他們會漸漸理解軟件項目鎖必需的概念嚴(yán)謹(jǐn)性。
無知往往會導(dǎo)致我們做出錯誤的假設(shè)。——對領(lǐng)域知識在技術(shù)上難度的輕視。
高效率的團(tuán)隊需要有意識地積累知識,并持續(xù)學(xué)習(xí)。對于開發(fā)人員來說,這意味著既要完善技術(shù)知識,也要培養(yǎng)一般的領(lǐng)域建模技巧(以及目前正在從事的特定領(lǐng)域的知識)。善于自學(xué)的團(tuán)隊成員是團(tuán)隊的中堅力量。
例子:通過策略模式將航運(yùn)領(lǐng)域的超訂規(guī)則明確展示出來表示它是一個政策。
要想建立實(shí)用且清晰的模型要求團(tuán)隊成員既要精通領(lǐng)域知識,也要精通建模技術(shù)。
例子:航運(yùn)業(yè)務(wù)的認(rèn)識從“集裝箱在各個地點(diǎn)之間的運(yùn)輸”轉(zhuǎn)變?yōu)椤斑\(yùn)貨責(zé)任在各個實(shí)體之間的傳遞”。
疑問
系統(tǒng)性的思考方法怎么理解?
即使是在一個最初不熟悉的領(lǐng)域中也是如此?
頭腦風(fēng)暴?
語言的交流和使用
UML
沒有公共語言的項目交流就像沒有翻譯的兩個說不同國家語言的人在聊天。知識消化理解變得困難。
領(lǐng)域模型的模式名稱。
將模型作為語言的中心。確保交流、畫圖、代碼(注意命名描述)中使用這種語言。
領(lǐng)域?qū)<覒?yīng)該避免使用拗口或無法表達(dá)領(lǐng)域理解的術(shù)語或結(jié)構(gòu),開發(fā)人員應(yīng)該密切監(jiān)視那些將會妨礙設(shè)計的有歧義和不一致的地方。
P41領(lǐng)域驅(qū)動交流對話
用簡單高效易懂的語言交流來形成模型。
一個團(tuán)隊,一種語言
如果連經(jīng)驗豐富的領(lǐng)域?qū)<叶疾荒芾斫饽P停敲茨P鸵欢ㄊ怯袉栴}的。
UML擅長表達(dá)對象的關(guān)系和交互。
UML無法傳達(dá)模型的兩個最重要的方面:
模型所表示的概念的意義。
對象應(yīng)該做哪些事情。
模型設(shè)計的重要細(xì)節(jié)應(yīng)該在代碼中體現(xiàn)出來。以文本或描述為主,簡略圖為注釋?
模型不是圖。圖的目的是幫助表達(dá)和解釋模型。(不能強(qiáng)制完全用圖來表示模型或設(shè)計,因為這樣會削弱圖的清晰表達(dá)的能力)
文檔的作用:
文檔應(yīng)作為代碼和口頭交流的補(bǔ)充。完全依賴代碼作為一種交流媒介可以促使開發(fā)人員保持代碼的整潔和透明。
注意代碼作為設(shè)計文檔的局限性:會把讀代碼的人淹沒在細(xì)節(jié)中。因此文檔應(yīng)澄清設(shè)計意圖,著重說明含義,不應(yīng)重復(fù)表示代碼已經(jīng)明確表達(dá)的內(nèi)容。
文檔應(yīng)努力心情生存之道并保持最新。通過將文檔減至最少,并且注意用它來補(bǔ)充代碼和口頭交流,就可以避免文檔與項目脫節(jié)。
P50解釋性模型展示
疑問
將模型作為語言的中心,什么意思,什么叫模型?可以說是UML圖加大家約定成俗的語言描述么?
綁定模型和實(shí)現(xiàn)
領(lǐng)域驅(qū)動設(shè)計要求模型不僅能夠指導(dǎo)早期的分析工作,還應(yīng)該成為設(shè)計的基礎(chǔ)。這種設(shè)計方法對于代碼的編寫有著重要的暗示作用。
如果整個程序設(shè)計或者其核心部分沒有與領(lǐng)域模型相對應(yīng),那么這個模型就是沒有價值的,軟件的正確性也值得懷疑。同時,模型和設(shè)計功能之間太過復(fù)雜的對應(yīng)關(guān)系也是難于理解的,在實(shí)際項目中改變設(shè)計時也無法維護(hù)這種關(guān)系。分析和設(shè)計工作無關(guān)聯(lián),導(dǎo)致在這兩個過程中所獲得的知識無法彼此共享。
軟件系統(tǒng)各個部分的設(shè)計應(yīng)該忠實(shí)地反映領(lǐng)域模型,以便體現(xiàn)出這兩者之間的明確對應(yīng)關(guān)系。我們應(yīng)該繁復(fù)檢查并修改模型,在軟件中更加自然地實(shí)現(xiàn)模型,即使想讓它反映出更深層次的領(lǐng)域概念也應(yīng)如此。我們需要的模型不但應(yīng)該滿足這兩種需求,還應(yīng)該能夠支持健壯的通用語言。
從模型中獲取用于程序設(shè)計和基本任務(wù)分配的術(shù)語。程序代碼就是模型的表達(dá),修改代碼可以就是改變模型。
想要使代碼有效地描述模型就需要用到程序設(shè)計和實(shí)現(xiàn)的技巧(第二部分)
軟件開發(fā)是一個不斷精化模型、設(shè)計和代碼的統(tǒng)一的迭代過程(第三部分)
對象設(shè)計的真正突破是用代碼來描述模型中的概念。
用過程語言(C)編寫的軟件具有復(fù)雜的函數(shù),這些函數(shù)基于預(yù)先制定的執(zhí)行路徑連接在一起,而不是通過領(lǐng)域模型中的概念聯(lián)系連接的。
例子:P56 從過程設(shè)計到模型驅(qū)動設(shè)計
模型驅(qū)動設(shè)計中要結(jié)合設(shè)計模式來實(shí)現(xiàn)。
讓用戶更了解模型,給他們更多的集合挖掘軟件的潛能,也能使軟件的行為合乎情理、前后一致。
模式:Hands-on modeler (建模人員參與程序開發(fā))
經(jīng)驗豐富的工程師做設(shè)計工作,而技能水平較低的勞動力負(fù)責(zé)組裝產(chǎn)品。
架構(gòu)師不能脫離編程而設(shè)計架構(gòu),因為將分析、建模、設(shè)計和編程工作完全分離會對Model-driven design 產(chǎn)生不良影響。
如果項目組的分工阻斷了設(shè)計人員與開發(fā)人員之間的協(xié)作,使他們無法領(lǐng)悟Model-driven design 的奧秘,那么經(jīng)驗豐富的設(shè)計人員就不能將自己的知識和技術(shù)傳遞給開發(fā)人員。
任何參與建模的技術(shù)人員,不管在項目中的主要職責(zé)是什么,都必須花時間了解代碼。任何負(fù)責(zé)修改代碼的人員則必須學(xué)會用代碼來表達(dá)模型。每一個開發(fā)人員都必須不同程度地參與模型討論并且與領(lǐng)域?qū)<冶3致?lián)系。參與不同工作的人都必須有意識地通過Ubiquitous Language 與接觸代碼的人即使交換關(guān)于模型的想法。(這一段描述讓我想起了在亞信做訂單中心時的場景,雖然中間模型幾次調(diào)整討論,但總的來說是符合模型驅(qū)動設(shè)計的理念的,達(dá)到了充分交流設(shè)計,模型驅(qū)動設(shè)計的成功離不開詳盡的設(shè)計決策。)
疑問
設(shè)計和模型相脫離后怎么辦?
二、模式驅(qū)動設(shè)計的構(gòu)造塊
開發(fā)一個好的領(lǐng)域模型是一門藝術(shù)。而模型中各個元素的實(shí)際設(shè)計和實(shí)現(xiàn)則相對系統(tǒng)化。將領(lǐng)域設(shè)計與軟件系統(tǒng)中的其他關(guān)注點(diǎn)分離會使設(shè)計與模型之間的關(guān)系非常清晰。根據(jù)不同的特征來定義模型元素則會使元素的意義更加鮮明。對每個元素使用已驗證的模式有助于創(chuàng)建更易于實(shí)現(xiàn)的模型。
疑問
設(shè)計風(fēng)格中,什么叫職責(zé)驅(qū)動設(shè)計的原則?
”契約式設(shè)計“思想是指?
分離領(lǐng)域
Layered Architecture (分層架構(gòu))
分層架構(gòu)的基本原則:
層中的任何元素都僅依賴于本層的其他元素或其下層的元素。向上的通信必須通過間接的傳遞機(jī)制進(jìn)行(如回調(diào)模式或觀察者模式)。
一般的四個分層:
表示層(controller)
應(yīng)用層(service邏輯層)
領(lǐng)域?qū)樱P蛯樱瑢ο蟆⒔Y(jié)構(gòu))
基礎(chǔ)設(shè)施層(dao等)
使用框架的一些缺點(diǎn):要么是設(shè)定了太多的假設(shè),減小了領(lǐng)域設(shè)計的可選范圍;要么是需要實(shí)現(xiàn)太多的東西,影響開發(fā)進(jìn)度。
將領(lǐng)域?qū)崿F(xiàn)獨(dú)立出來是領(lǐng)域驅(qū)動設(shè)計的前提。所以分層架構(gòu)是必須的。
要想創(chuàng)建出能夠處理復(fù)雜任務(wù)的程序,需要把不同的關(guān)注點(diǎn)分開考慮,使設(shè)計中的每個部分都得到單獨(dú)的關(guān)注。在分離的同時,也需要維護(hù)系統(tǒng)內(nèi)部復(fù)雜的交互關(guān)系。
模式:The Smart UI "Anti-pattern"(智能用戶界面——反模式)用于與領(lǐng)域驅(qū)動設(shè)計作對比
一次性簡單開發(fā)才可能用到,已廢
把領(lǐng)域隔離出來的最大好處就是可以真正專注于領(lǐng)域設(shè)計,而不用考慮其他的方面。
疑問
為什么說J2EE中的實(shí)體bean比較笨重,影響程序性能,而改用spring的普通java對象比較輕呢?
軟件中所表示的模型
區(qū)分用于表示模型元素的三種模式:Entity、 Value Object、 Service
Entity(實(shí)體、標(biāo)識):一個對象是用來表示某種具有連續(xù)性和標(biāo)識的事物。
Value Object(值對象):用于描述某個事物的某種狀態(tài)的屬性。
Service(服務(wù)) :領(lǐng)域中適合用動作或操作來表示的方面。
使得對象關(guān)聯(lián)更易于控制的三個方法:
規(guī)定一個遍歷方向。
添加一個限定符,以便有效地減少多重關(guān)聯(lián)。
消除不必要的關(guān)聯(lián)。
堅持將關(guān)聯(lián)限定為領(lǐng)域中所偏向的方向,不僅可以提高這些關(guān)聯(lián)的表達(dá)力并簡化其實(shí)現(xiàn),而且還可以突出剩下的雙向關(guān)聯(lián)的重要性。
關(guān)聯(lián)關(guān)系最終的簡化是消除那些對當(dāng)前工作或模型對象的基本含義來說不重要的關(guān)聯(lián)。
仔細(xì)地簡化和約束模型的關(guān)聯(lián)是通往模式驅(qū)動設(shè)計的必經(jīng)之路。
模式:Entity(又稱為Reference Object)引用對象
Entity可以是任何事物,只要滿足兩個條件即可:
它在整個生命周期中具有連續(xù)性。
它的一些對用戶來說非常重要的不同狀態(tài)不是由屬性決定的。(怎么理解?)
標(biāo)識重不重要,完全取決于它是否有用。同一個事物在領(lǐng)域模型中可能需要表示為Entity,也可能不需要表示為Entity。
例子:演唱會座位預(yù)定程序中的座位。如果分配座位時是一對一對號入座,則需要座位是個標(biāo)識Entity,而座位號就是其標(biāo)識符;而如果分配座位時是先到先做的話,則不需要座位是個標(biāo)識Entity加以區(qū)分,只有座位總數(shù)才是重要的。
Entity最基本職責(zé)是確保連續(xù)性,以便使其行為更清楚且可預(yù)測。保持實(shí)體的簡練是實(shí)現(xiàn)這一責(zé)任的關(guān)鍵。
Entity的唯一ID可以通過技術(shù)框架實(shí)現(xiàn),也可以通過工程規(guī)程來約束。
模式: Value Object (值對象)
用于描述領(lǐng)域的某個方面而本身沒有概念標(biāo)識的對象稱為 Value Object 。 Value Object 被實(shí)例化之后用來表示一些設(shè)計元素,我們只關(guān)心這些元素是什么,而不關(guān)心它們是誰。(沒有個體特別的區(qū)別)
Value Object 可以是其他對象的集合。如窗戶是由窗戶樣式長寬高等值對象組合成的復(fù)雜Value Object 。
Value Object 可以引用Entity。如一條泉州到廈門的地圖導(dǎo)航路線,路線是Value Object ,而兩個城市是Entity。
當(dāng)我們只關(guān)心一個模型元素的屬性時,應(yīng)把它歸類為Value Object 。我們應(yīng)該使這個模型元素能夠表示出其屬性的意義,并為它提供相關(guān)功能。Value Object 應(yīng)該是不可變的。不要為它分配任何標(biāo)識,而且不要把它設(shè)計成像Entity那么復(fù)雜。
下圖中的address對象就是個值對象:
值對象的共享:享元模式。 例子:房屋設(shè)計軟件中的電源插座可以用享元模式來實(shí)現(xiàn)。
值對象的選擇:是使用復(fù)制,還是使用共享。
無論是否共享Value Object ,在可能的情況下都要將它們設(shè)計為不可變的。
通過復(fù)制(冗余),可以將這種作為很多Entity屬性的Value Object 存儲在Entity所在的同一頁上。這種存儲相同數(shù)據(jù)的多個副本的技術(shù)稱為非規(guī)范化。(denormalization) 當(dāng)訪問時間比存儲空間或維護(hù)的簡單性更重要時,使用這種技術(shù)。
模型中的關(guān)聯(lián)越少越好,越簡單越好。
模式:Service (服務(wù))
Service 強(qiáng)調(diào)的是與其它對象的關(guān)系。
當(dāng)領(lǐng)域中的某個重要的過程或裝換操作不屬于實(shí)體或值對象的自然職責(zé)時,應(yīng)該在模型中添加一個作為獨(dú)立接口的操作,并將其聲明為Service 。定義接口時要使用模型語言,并確保操作名稱是通用語言的術(shù)語。且Service 定義應(yīng)該是無狀態(tài)的。
領(lǐng)域?qū)ο笈c外部資源之間可以用外觀模式把外部的Service 包裝起來。
模式:Module(或Package)模塊或包
Module提供兩種觀察模型的方式:
可以在Module中查看細(xì)節(jié),而不會被整個模型淹沒。
觀察Module之間的關(guān)系,而不考慮其內(nèi)部細(xì)節(jié)。
基于可以作為模塊的概念組織的模塊可以以一種有意義的方式將元素集中到一起,找到一種低耦合的概念組織方式,從而可以相互獨(dú)立地理解和分析這些概念。
例子:Java中的包編碼慣例
除非真正有必要將代碼分布到不同的服務(wù)器上,否則就把實(shí)現(xiàn)單一概念對象的所有代碼放在同一個模塊中。
建模范式——主流的范式是面向?qū)ο笤O(shè)計
項目構(gòu)建時應(yīng)主動擁抱主流成熟的基礎(chǔ)設(shè)施和工具支持,解決開發(fā)資源和避開技術(shù)風(fēng)險。
P98使用不成熟范式帶來的風(fēng)險故事。
涉及大量數(shù)學(xué)問題的領(lǐng)域或者受全局邏輯推理控制的領(lǐng)域不適合使用面向?qū)ο蠓妒健?/p>
其他范式:邏輯范式
當(dāng)將非對象元素混合到以面向?qū)ο鬄橹鞯南到y(tǒng)中時,需要遵循的4條經(jīng)驗規(guī)則:
不要和實(shí)現(xiàn)范式對抗。
把通用語言作為依靠的基礎(chǔ)。
不要一味依賴UML。
保持懷疑態(tài)度。
模式:Aggregate 集合
我們在程序中需要用到的對象集合體,如下的汽車對象(訂單中心里的一個訂單項,里面包含調(diào)度信息,業(yè)務(wù)訂單信息,客戶訂單信息等)
固定規(guī)則是指在數(shù)據(jù)變化時必須保持不變的一致性規(guī)則。
模式:Factory 工廠
對象的創(chuàng)建本身可以是一個主要操作,但被創(chuàng)建的對象并不適合承擔(dān)復(fù)雜的裝配操作。將這些職責(zé)混合在一起可能導(dǎo)致出現(xiàn)難以理解的拙劣設(shè)計。讓客戶直接負(fù)責(zé)創(chuàng)建對象又會使客戶的設(shè)計陷入混亂,并且破壞被裝配對象或計劃的封裝,而導(dǎo)致客戶與創(chuàng)建對象的實(shí)現(xiàn)之間產(chǎn)生過于緊密的耦合。因此,用工廠模式創(chuàng)建對象是極好的。
好的工廠的要求:
每個創(chuàng)建方法都是原子方法,而且滿足被創(chuàng)建對象或集合的所有固定規(guī)則。如果無法正確創(chuàng)建,則應(yīng)該拋出異常等,以確保不會返回錯誤的值。
工廠應(yīng)該被抽象為所需的類型,而不是創(chuàng)建出具體的類。(伸縮性)
以下情況直接使用構(gòu)造函數(shù)new創(chuàng)建即可:
類是一種類型。它不是任何相關(guān)層次結(jié)構(gòu)的一部分,而且也沒有通過接口實(shí)現(xiàn)多態(tài)性。(就是個類,如bean)
客戶關(guān)心的是實(shí)現(xiàn),可能是將其作為選擇策略的一種方式
客戶可以訪問對象的所以屬性,因此向客戶公開的構(gòu)造函數(shù)中沒用嵌套的對象創(chuàng)建。
構(gòu)造并不復(fù)雜
模式:Repository 存儲
在所以持久對象中,有一小部分必須能夠通過基于對象屬性的搜索來全局訪問(即如通過手機(jī)號碼/身份證號碼等特殊屬性值區(qū)分來查詢獲取對象)。當(dāng)不易通過遍歷的方式來訪問某些集合的根的時候,就需要使用這種訪問方式(即不能通過如訂單項來獲取業(yè)務(wù)訂單數(shù)據(jù)的時候,要通過上述的查詢,比如通過客戶訂單號來獲取業(yè)務(wù)訂單數(shù)據(jù))。它們通常是Entity,有時是具有復(fù)雜內(nèi)部結(jié)構(gòu)的Value Object,有時還可能是枚舉Value。而其他對象則不宜使用數(shù)據(jù)庫搜索訪問獲取對象數(shù)據(jù)的方式,因為這會混淆它們之間的重要區(qū)別。(即有些對象數(shù)據(jù)通過數(shù)據(jù)庫來獲取會破壞整個訂單項的構(gòu)成)。毫無約束的數(shù)據(jù)庫查詢可能會破壞領(lǐng)域?qū)ο蟮姆庋b和集合。技術(shù)基礎(chǔ)設(shè)施和數(shù)據(jù)庫訪問機(jī)制的暴露會增加客戶的復(fù)制度,并妨礙模型驅(qū)動的設(shè)計。
只為那些確實(shí)需要直接訪問的集合提供Repository。讓客戶始終聚焦于模型,而將所有對象存儲和訪問操作交給Repository來完成。
數(shù)據(jù)庫查詢時要注意檢索到的數(shù)據(jù)對象不能無限大,可能會導(dǎo)致內(nèi)存爆滿溢出。
疑問
Entity 和 Value Object 的區(qū)別?怎么理解P85頁上地址什么時候是實(shí)體,什么時候是值對象?
Service 定義應(yīng)該是無狀態(tài)的指的是不能有類成員變量?
WebSphere是什么?
7、使用語言:一個擴(kuò)展的實(shí)例
P131實(shí)例,詳細(xì)了解作者的針對一個案例的領(lǐng)域驅(qū)動設(shè)計思維全過程。跳過,待回頭細(xì)讀。
疑問
三、通過重構(gòu)來加深理解
想成功開發(fā)出實(shí)用的模型的三點(diǎn)注意:
復(fù)雜巧妙的領(lǐng)域模型是可以實(shí)現(xiàn)的,也是值得我們?nèi)セㄙM(fèi)力氣實(shí)現(xiàn)的。
這樣的模型離開不斷的重構(gòu)是很難開發(fā)出來的,重構(gòu)需要領(lǐng)域?qū)<液蜔釔蹖W(xué)習(xí)領(lǐng)域知識的開發(fā)人員密切參與進(jìn)來。
要實(shí)現(xiàn)并有效地運(yùn)用模型,需要警惕設(shè)計技巧。
重構(gòu)定義:重構(gòu)就是在不改變軟件功能的前提下重新設(shè)計它。
設(shè)計模式重構(gòu)
微重構(gòu)
深層模型能夠穿過領(lǐng)域表象,清楚地表達(dá)出領(lǐng)域?qū)<覀兊闹饕P(guān)注點(diǎn)以及最相關(guān)的知識。
8、突破
重構(gòu)前:
重構(gòu)后:
疑問
什么叫微重構(gòu)?
9、將隱式概念轉(zhuǎn)變?yōu)轱@示概念(重要)
若開發(fā)人員識別出設(shè)計中隱含的某個概念或是在討論中受到啟發(fā)而發(fā)現(xiàn)一個概念時,就會對領(lǐng)域模型和相應(yīng)的代碼進(jìn)行許多轉(zhuǎn)換,在模型中鍵入一個或多個對象或關(guān)系,從而將次概念顯式地表達(dá)出來。
當(dāng)傾聽領(lǐng)域?qū)<业恼Z言時,是否有一些術(shù)語能夠簡潔地表達(dá)出復(fù)雜的概念;有沒有被他們提醒或糾正過描述用詞?當(dāng)你描述的特定短語時他們是否流露出迷惑的標(biāo)簽?如果有則暗示著某個概念也許可以改進(jìn)模型。
P163 實(shí)例 待詳細(xì)解讀
不同的領(lǐng)域?qū)<覍ν瑯拥氖虑闀胁煌目捶ǎ@取決于他們的經(jīng)驗和需求。
在尋找模型概念時,可以通過查閱書籍來解釋和理解基本概念。
閱讀書籍并不能提供現(xiàn)成的解決方案,但可以為他提供一些全新的實(shí)驗起點(diǎn),以及在這個領(lǐng)域中探索過的人總結(jié)出來的經(jīng)驗。這樣可以避免開發(fā)人員重復(fù)設(shè)計已有的概念。
約束是模型概念中非常重要的類別。它們通常是隱式出現(xiàn)的,將它們顯式地表現(xiàn)出來可以極大地提高設(shè)計質(zhì)量。
例子如下:
顯式地約束:
把約束條件提取成"有名有姓"的概念
需要修改約束設(shè)計的情況:
計算約束所需的數(shù)據(jù)從定義上看并不屬于這個對象。
相關(guān)規(guī)則在多個對象中出現(xiàn),造成了代碼重復(fù)或?qū)е虏粚儆谕蛔宓膶ο笾g產(chǎn)生了繼承關(guān)系。
很多設(shè)計和需求討論是圍繞這些約束進(jìn)行的,而在代碼實(shí)現(xiàn)中,它們卻隱藏在過程代碼中。
模式:Specification(規(guī)格)
為特殊目的創(chuàng)建謂詞形式的顯式的Value Object. Specification就是一個謂詞,可用來確定對象是否滿足某些標(biāo)準(zhǔn)。
疑問
單元測試?
10、柔性設(shè)計
模式:Intention-Revealing Interfaces(意圖展示接口)
意圖展示接口清楚地表明了用途。
思考:如果代碼只是在執(zhí)行規(guī)則后得到結(jié)果,而沒有把規(guī)則顯式地表達(dá)出來,那么我們就不得不一步一步的去思考軟件的執(zhí)行步驟。
對象的強(qiáng)大功能是它能夠把所有這些細(xì)節(jié)封裝起來,這樣客戶代碼就能夠很簡單,而且可以用高層概念來解釋。
如果開發(fā)人員為了使用一個組件而必須要去研究它的實(shí)現(xiàn),那么就失去了封裝的價值。(所有要展示組件的意圖)
類和方法的名稱為開發(fā)人員之間的溝通創(chuàng)造了很好的機(jī)會,也能改善系統(tǒng)的抽象。
意圖命名原則:
命名類和操作時要描述它們的效果和目的,而不用表露它們是通過何種方式達(dá)到目的地。這樣可以使客戶開發(fā)人員不必去理解內(nèi)部的細(xì)節(jié)。在創(chuàng)建一個行為之前先為它編寫一個測試,這樣可以促使你站在客戶開發(fā)人員的角度上來思考它。
在領(lǐng)域的公共接口中,可以把關(guān)系和規(guī)則表述出來,但不要說明規(guī)則是如何實(shí)施的;可以把事件和動作描述出來,但不要描述它們是如何執(zhí)行的;可以給出方程式,但不要給出解方程式的數(shù)學(xué)方法。可以提出問題,但不要給出獲取答案的方法。
命名的案例:
模式:side-effect-free function(無副作用的函數(shù) )
副作用指的是意外的結(jié)果。
如果沒有了可以安全預(yù)見到結(jié)果的抽象,開發(fā)人員就必須限制“組合爆炸”,這樣會限制系統(tǒng)行為的豐富性。
返回結(jié)果而不產(chǎn)生副作用的操作稱為函數(shù),讓我們能夠更準(zhǔn)確地預(yù)測結(jié)果。
盡可能把程序的邏輯放在函數(shù)中,因為函數(shù)是只返回結(jié)果而不產(chǎn)生明顯副作用的操作。嚴(yán)格地吧命令(引起明顯的狀態(tài)改變的方法)隔離到不返回領(lǐng)域信息的、非常簡單的操作中。當(dāng)發(fā)現(xiàn)了一個非常適合承擔(dān)復(fù)雜邏輯職責(zé)的概念時,就可以把這個復(fù)雜邏輯移到Value Object(利用其不變性)中,這樣可以進(jìn)一步控制副作用。
模式:Assertion(斷言)
使用Entity時有些有副作用的命令,使用人必需了解使用這些命令的后果。(如Entity里某個值不能為NULL)
這種情況下,使用斷言可以把副作用明確地表示出來,使他們更易于處理。
斷言是前置條件(契約式設(shè)計 design by contract)。前置條件就像是合同條款,即為了滿足后置條件而必須要滿足的前置條件。類的固定規(guī)則規(guī)定了在操作結(jié)束時對象的狀態(tài)。
模式:Conceptual contour (概念上的輪廓)一般發(fā)生中后期在重構(gòu)上
把設(shè)計元素(操作、接口、類和集合)分解為內(nèi)聚的單元,在這個過程中,你對領(lǐng)域中一切重要劃分的直觀認(rèn)識也要考慮在內(nèi)。在連續(xù)的重構(gòu)過程中觀察發(fā)生變化和保證穩(wěn)定的規(guī)律性,并尋找能夠解釋這些變化模式的底層概念輪廓。使模型與領(lǐng)域中那些一致的方面相匹配。
模式:Standalone Class (孤立的類)
Module 和 Aggregate 的目的都是為了限制互相依賴的關(guān)系網(wǎng)。但即使在Module內(nèi)部,設(shè)計也會隨著依賴關(guān)系的增加而變得越來越難以理解。這加重了我們的思考負(fù)擔(dān),從而限制了開發(fā)人員能處理的設(shè)計復(fù)雜度。隱式概念比顯示的引用增加的負(fù)擔(dān)更大。
低耦合是對象設(shè)計的一個基本要素。盡一切可能保持低耦合。把其他所有無關(guān)概念提取到對象之外。這樣類就變得完全孤立了,這使得我們可以單獨(dú)地研究和理解它。每個這樣孤立的類都極大地減輕了因理解Module 而帶來的負(fù)擔(dān)。(單一職責(zé))
盡力吧最復(fù)雜的計算提取到Standalone Class 中,可能實(shí)現(xiàn)此目的的一種方法是把具有緊密聯(lián)系的類中所含有的Value Object 建模出來。
模式:Closure of Operation(閉合操作)
當(dāng)我們對集合中的任意兩個元素組合時,結(jié)果仍然在這個集合中,這就叫閉合操作。
大部分引起我們興趣的對象所產(chǎn)生的行為僅用基本類型是無法描述的。
在適當(dāng)?shù)那闆r下,在定義操作時讓它的返回類型與其參數(shù)的類型相同。(我們一般查詢頁面的出入?yún)⑾嗤?/strong>如果實(shí)現(xiàn)者的狀態(tài)在計算中會被用到,那么實(shí)現(xiàn)者實(shí)際上就是操作的一個參數(shù),因此參數(shù)和返回值應(yīng)該與實(shí)現(xiàn)者有相同的類型。這樣的操作就是在該類型的實(shí)例集合中的閉合操作。閉合操作提供了一個高層接口,同時又不會引入對其他概念的任何依賴性。
Model-Driven Design 的作用受細(xì)節(jié)設(shè)計的質(zhì)量和實(shí)現(xiàn)決策的質(zhì)量影響很大,而且只要有少數(shù)幾個開發(fā)人員沒有弄清楚它們,整個項目就會偏離目標(biāo)。
specification 實(shí)現(xiàn)
原則:盡可能利用已有的形式。如會計學(xué)定義了一組成熟的Entity和規(guī)則,我們很容易對這些Entity和規(guī)則進(jìn)行調(diào)整,得到一個深層的模型和柔性設(shè)計。(這也就是喬布斯說的好的藝術(shù)家抄襲,偉大的藝術(shù)家剽竊 。或者其實(shí)就是牛頓說的站在巨人的肩膀上。 )作者最喜歡的概念框架是數(shù)學(xué)——它能用基本數(shù)學(xué)概念把一些復(fù)雜的問題提取出來。
疑問
在領(lǐng)域的公共接口中,可以把關(guān)系和規(guī)則表述出來,但不要說明規(guī)則是如何實(shí)施的;可以把事件和動作描述出來,但不要描述它們是如何執(zhí)行的;可以給出方程式,但不要給出解方程式的數(shù)學(xué)方法。可以提出問題,但不要給出獲取答案的方法。這一段話如何理解?
11、分析模式的應(yīng)用
要點(diǎn):如何將分析模式集成到領(lǐng)域驅(qū)動設(shè)計過程中。
分析模式是一種概念集合,用來表示業(yè)務(wù)建模中的常見構(gòu)造。它可能只與一個領(lǐng)域有關(guān),也可能跨越多個領(lǐng)域。
分析模式并不是技術(shù)解決方案,而只是用來指導(dǎo)人們設(shè)計特定領(lǐng)域中的模型。分析模式的最大作用是借鑒其他項目的經(jīng)驗,把那些項目中所做的廣泛的設(shè)計方向討論和實(shí)現(xiàn)結(jié)果的經(jīng)驗與當(dāng)前的模型結(jié)合起來。
依賴性設(shè)計中的三種處理方法(業(yè)務(wù)的后續(xù)處理):
主動觸發(fā)。(如調(diào)用接口)
基于主體(Account的觸發(fā))允許推遲處理。(如通過發(fā)送消息)
有外部代理(調(diào)度任務(wù))來啟動觸發(fā)。一個定時觸發(fā)任務(wù)(基于過賬規(guī)則的觸發(fā),如每天凌晨的對賬調(diào)度任務(wù))
分析模式為我們提前預(yù)測了一些后期結(jié)果,避免我們?nèi)绻约喝?shí)踐可能付出的高昂的代價。
疑問
12、將設(shè)計模式應(yīng)用于模型
設(shè)計模式從代碼的角度來看它們是技術(shù)設(shè)計模式,從模型的角度來看它們就是概念模式。
策略模式
領(lǐng)域模型包含一些并非用于解決技術(shù)問題的過程,將它們包含進(jìn)來是因為他們對過程問題領(lǐng)域具有實(shí)際的價值。當(dāng)必須從多個過程中進(jìn)行選擇時,選擇的復(fù)雜性再加上多個過程本身的復(fù)雜性會使局面失去控制。(開發(fā)和維護(hù)人員很難理解一堆的if、else及龐大的代碼塊)
我們需要把過程中的易變部分提取到模型的一個單獨(dú)的策略對象中。將規(guī)則與它所控制的行為區(qū)分開。按照策略設(shè)計模式來實(shí)現(xiàn)規(guī)則或可替換的過程。策略對象的多個版本表示了完成過程的不同方式。
組合模式
使用的前提:當(dāng)嵌套容器的關(guān)聯(lián)性沒有在模型中反映出來時,公共行為必然會在層次結(jié)構(gòu)的每一層重復(fù)出現(xiàn),而且嵌套也變得僵化。客戶必須通過不同的接口來處理層次結(jié)構(gòu)中的不同層,盡管這些層可能在概念上沒有區(qū)別。通過層次結(jié)構(gòu)來遞歸地收集信息也變得非常復(fù)雜。
定義一個把組合的所有成員都包含在內(nèi)的抽象類型(父類,子類有葉節(jié)點(diǎn)和容器節(jié)點(diǎn)),在容器上實(shí)現(xiàn)一些用來查詢信息的方法,這些方法可用來收集與容器內(nèi)容有關(guān)的信息。葉節(jié)點(diǎn)基于它們自己的值來實(shí)現(xiàn)這些方法(有些葉節(jié)點(diǎn)不具備的方法也要實(shí)現(xiàn),不過要拋出異常或者返回空)。這樣客戶就只需使用抽象類型,而無需區(qū)分葉節(jié)點(diǎn)和容器。
設(shè)計模式運(yùn)用于領(lǐng)域模式的基本特征是其既適用于模型,也適用于實(shí)現(xiàn)。
把設(shè)計模式用作領(lǐng)域模式的唯一要求是這些模式能夠描述關(guān)于概念領(lǐng)域的一些事情,而不僅僅是作為解決技術(shù)問題的技術(shù)解決方案。
疑問
13、通過重構(gòu)得到更深層的理解
重構(gòu)的核心:
以領(lǐng)域為本。
用一種不同的方式來看待事物。
始終堅持與領(lǐng)域?qū)<覍υ挕?/p>
(領(lǐng)域模型驅(qū)動)重構(gòu)的原因:
模型的語言沒有與領(lǐng)域?qū)<冶3忠恢拢蛘咝碌男枨蟛荒鼙蛔匀坏靥砑拥侥P椭小?/p>
開發(fā)人員通過學(xué)習(xí)獲得了更深刻的理解,從而發(fā)現(xiàn)了一個得到更清晰或更有用的模型的機(jī)會。
團(tuán)隊:
包含領(lǐng)域?qū)<业?-5個人的小組,其中開發(fā)人員應(yīng)該擅長思考該類型問題,了解領(lǐng)域,或者掌握深厚的建模技巧。
保證效率:
自主決定。一個臨時的頭腦風(fēng)暴團(tuán)隊,只工作幾天。
注意范圍和休息。如果討論時間和范圍都太長導(dǎo)致毫無進(jìn)展,那么可以選擇一個較小的設(shè)計方面,集中討論它。
練習(xí)使用通用語言來討論。
在模型設(shè)計中,經(jīng)常需要修改的地方要能夠保持很高的靈活性,而其他地方則相對比較簡單。
重構(gòu)的時機(jī):
設(shè)計沒有表達(dá)出團(tuán)隊對領(lǐng)域的最新理解。
一些重要的概念被隱藏在設(shè)計中了(開發(fā)人員能這些概念呈現(xiàn)出來)。
發(fā)現(xiàn)了一個能令某個重要的設(shè)計部分變得更靈活的機(jī)會。
注意:項目發(fā)布前不要重構(gòu);不要引入一些只顧炫耀技術(shù)能力而沒有解決領(lǐng)域核心問題的柔性設(shè)計。
疑問
一個系統(tǒng)過于龐大的話那么還有必要重構(gòu)么?
四、戰(zhàn)略設(shè)計
戰(zhàn)略設(shè)計用于大而復(fù)雜的系統(tǒng)領(lǐng)域設(shè)計,通過團(tuán)隊乃至多個團(tuán)隊進(jìn)行決策指定。
首先便是分割模塊化設(shè)計業(yè)務(wù)模型,在不損害集成利益的前提下。
進(jìn)行模塊化領(lǐng)域設(shè)計是因為如果設(shè)計一個把所有概念都涵蓋進(jìn)來的單一領(lǐng)域模型,它將會非常笨拙且會出現(xiàn)大量難以察覺的重復(fù)和矛盾。會么?
三大主題:上下文、精煉、大比例結(jié)構(gòu)。
結(jié)構(gòu)和精煉能夠幫助我們理解各個部分之間的復(fù)制關(guān)系,同時保持整體視圖的清晰。Bounded Context 使我們能夠在不同的部分中進(jìn)行工作,而不會破壞模型或是無意間導(dǎo)致模型的分裂。
14、保持模型的完整性
大型系統(tǒng)領(lǐng)域模型的完全統(tǒng)一是不可行的,也不是一種經(jīng)濟(jì)有效的做法。
除技術(shù)上的因素外,權(quán)力上的劃分和管理級別的不同也要求把模型分開。
因為有以下風(fēng)險:
一次嘗試對遺留系統(tǒng)做過多的替換。
大項目可能會陷于困境,因為協(xié)調(diào)的開銷太大,超出了這些項目的能力范圍。
具有一些特殊需求的應(yīng)用程序可能不得不使用無法重復(fù)滿足需求的模型,而只能將這些無法滿足的行為放到其他地方。
試圖用一個模型來滿足所有人的需求可能會導(dǎo)致模型中包含過于復(fù)雜的選擇,因而很難使用。
模式:Bounded Context(有界的上下文)
明確地定義模型所應(yīng)用的上下文。根據(jù)團(tuán)隊的組織、軟件系統(tǒng)的各個部分的用法以及物理表現(xiàn)(代碼和數(shù)據(jù)庫模式等)來設(shè)置模型的邊界。在這些邊界中嚴(yán)格保持模型的一致性,而不要受到邊界之外問題的干擾和混淆。
要想避免共享模型產(chǎn)生的問題(含義和代表的意思是否不同等),每個人都必須理解模型上下文的邊界在哪里。
模式:Continuous Integration(連續(xù)集成)
Continuous Integration是指把一個上下文中的所有工作足夠頻繁地合并到一起,并使它們經(jīng)常保持一致,以便當(dāng)模型發(fā)生分裂時,可以迅速發(fā)現(xiàn)并糾正問題。
連續(xù)集成的操作:
模型概念的集成。
實(shí)現(xiàn)的集成。
建立一個經(jīng)常把所有代碼和其他實(shí)現(xiàn)工件合并到一起的過程,并通過自動測試來快速查明模型的分裂問題。嚴(yán)格堅持使用通用語言,以便在不同人的頭腦中演變出不同的概念時,使所有人對模型都能達(dá)成一個共識。
模式:Context Map()
識別每個模型在項目中的作用,并定義其Bounded Context。這包括非面向?qū)ο笞酉到y(tǒng)的隱含模型。為每個Bounded Context命名,并把名稱添加到通用語言中。描述模型之間的接觸點(diǎn),明確每次交流所需的轉(zhuǎn)換,并突出任何共享的內(nèi)容。
畫出現(xiàn)有的范圍。為稍后的轉(zhuǎn)換做好準(zhǔn)備。
兩個重點(diǎn):
Bounded Context 應(yīng)該有名稱,以便可以討論它們。
每個人都應(yīng)該知道邊界在哪里,而且能夠分辨出任何代碼段的Context,或任何情況的Context。
建議:
開發(fā)一個緊密集成產(chǎn)品的優(yōu)秀團(tuán)隊可以部署一個大的、統(tǒng)一的模型、如果團(tuán)隊需要為不同的用戶群提供服務(wù),或者團(tuán)隊的協(xié)調(diào)能力有限,可能就需要采用Shared Kernel (共享內(nèi)核)或Customer/Supplier(客戶/供應(yīng)商)關(guān)系。如果集成并不重要,系統(tǒng)最好采用Separate Way(獨(dú)立自主)模式。大多數(shù)項目都需要與遺留系統(tǒng)或外部系統(tǒng)進(jìn)行一定程度的集成,這就需要使用Open Host Service (開發(fā)主機(jī)服務(wù))或Anticorruption Layer(防護(hù)層)。
模式:Shared Kernel (共享內(nèi)核)
從領(lǐng)域模型中選出兩個團(tuán)隊都同意共享的一個子集,包括代碼子集或數(shù)據(jù)庫設(shè)計的子集。這部分明確共享的內(nèi)容在一個團(tuán)隊沒有與另一個團(tuán)隊商量的情況下不應(yīng)擅自更改它。在進(jìn)行集成時,兩個團(tuán)隊都要運(yùn)行測試。(例子:carbase庫依賴,DTO的共享等)
模式:Customer/Supplier Development Team(客戶/供應(yīng)商開發(fā)團(tuán)隊)關(guān)系
使用場景:一個子系統(tǒng)的主要任務(wù)是服務(wù)于另一個子系統(tǒng)。
在兩個團(tuán)隊之間建立一種明確的客戶/供應(yīng)商關(guān)系。下游團(tuán)隊相當(dāng)于上游團(tuán)隊的客戶。根據(jù)下游團(tuán)隊的需求來協(xié)商需要執(zhí)行的任務(wù)并為這些任務(wù)做預(yù)算,以便每個人都知道雙方的約定和進(jìn)度。
兩個團(tuán)隊一起開發(fā)自動驗收測試,用來驗證預(yù)期的接口。在迭代期間,下游團(tuán)隊成員應(yīng)該像傳統(tǒng)的客戶一樣隨時回答上游團(tuán)隊的提問,并幫助解決問題。
模式:Conformist(跟隨者)
應(yīng)用場景:兩個上下游關(guān)系的團(tuán)隊無法配合工作時,上游團(tuán)隊處于利他主義的考慮,做出他們可能不會履行的承諾,下游出于良好的意愿相信這些承諾,從而根據(jù)一些永遠(yuǎn)不會實(shí)現(xiàn)的特性來制定計劃時。
當(dāng)接口很大而且集成更加重要時,跟隨是有意義的。
在這種情況下,有3種結(jié)局途徑。
完全放棄對上游的利用。(Separate Way(獨(dú)立自主))
根據(jù)上游設(shè)計的質(zhì)量和風(fēng)格,如果上游的設(shè)計很難使用,那么下游必須咖啡其資金的模型,開發(fā)一個轉(zhuǎn)換層。Anticorruption Layer(防護(hù)層)。
根據(jù)上游設(shè)計的質(zhì)量和風(fēng)格,如果上游的設(shè)計質(zhì)量不是很差,風(fēng)格可以兼容,那么可以使用Conformist(跟隨者)模式。
模式:Anticorruption Layer(防護(hù)層)
與遺留系統(tǒng)的交互。
創(chuàng)建一個隔離的層,以便根據(jù)客戶自己的領(lǐng)域模型來為客戶提供相關(guān)的功能。這個層通過其現(xiàn)有接口與另一個系統(tǒng)進(jìn)行對話,而只需對那個系統(tǒng)做出很少的修改,甚至無需修改。在內(nèi)部,這個層在兩個模式之間進(jìn)行必要的雙向轉(zhuǎn)換。
Anticorruption Layer 設(shè)計進(jìn)行組織的一種方法是把它實(shí)現(xiàn)為外觀、適配器這兩種模式和轉(zhuǎn)換器組合。
模式:Separate Way(獨(dú)立自主)
我們必須嚴(yán)格劃定需求的范圍。如果兩組功能之間的關(guān)系并非必不可少,那么兩者完全可以彼此獨(dú)立。
集成代價總是高昂,而有時獲益卻很小。所以獨(dú)立開發(fā)時,聲明一個與其他上下文毫無關(guān)聯(lián)的Bonded Context,使開發(fā)人員能夠在這個小范圍內(nèi)找到簡單、專用的解決方案。
模式:Open Host Service (開發(fā)主機(jī)服務(wù))
定義一個協(xié)議,把你的子系統(tǒng)作為一組Service供其他系統(tǒng)訪問。開放這個協(xié)議,以便所有需要與你的子系統(tǒng)集成的人都可以使用它。當(dāng)有新的集成需求時,就增強(qiáng)并擴(kuò)展這個協(xié)議,但個別團(tuán)隊的特殊需求除外。滿足這種特殊需求的方法是使用一次性的轉(zhuǎn)換器來擴(kuò)充協(xié)議,以便使共享協(xié)議簡單且內(nèi)聚。
模式: Published Language(公開發(fā)布的語言)
如XML,JSON等用于兩個系統(tǒng)或者模型之間的交互響應(yīng)。
與現(xiàn)有領(lǐng)域模型之間進(jìn)行直接的轉(zhuǎn)換可能不是一種好的解決方案。這些模型可能過于復(fù)雜或者設(shè)計得較差。如果把其中一個模型作為數(shù)據(jù)交換的語言(如Facade模式提供接口交互),那么他實(shí)質(zhì)上就被固定住了,而無法滿足新的開發(fā)需求。
把一個良好文檔化的、能夠表達(dá)出所需領(lǐng)域信息的共享語言作為公共的通信媒介,必要時在其他信息與該語言之間進(jìn)行轉(zhuǎn)換。
“大象”的統(tǒng)一(從盲人摸象看模型集成統(tǒng)一)
這一節(jié)很重要。
雖然盲人共享更多的大象信息可以得到更大的價值,但沒有人愿意放棄自己的模型而采用別人的模型。
第一等到盲人們認(rèn)識到這是在對一個更大整體的不同部分進(jìn)行描述和建模時:下面這時候得到的模型還是簡陋的,缺乏內(nèi)聚性,也沒有形成一個底層的領(lǐng)域模型。如大象是可以移動的,移動起來樹理論上就不成立了,而應(yīng)該是腿的概念。
第二是去掉各個模型中那些偶然或不正確的方面,并創(chuàng)建新的概念。成功的模型應(yīng)該盡可能做到精簡,寧“少”勿多。如大象寧可缺少噴水功能,也不用包含不正確的蛇的毒牙特性。
承認(rèn)多個互相沖突的領(lǐng)域模型實(shí)際上正是面對現(xiàn)實(shí)的做法。通過定義每個模型都適用的上下文,可以維護(hù)每個模型的完整性,并清除地看到要在兩個模型創(chuàng)建的任何特殊接口的含義。
最重要的是,每個人都要承認(rèn)每個模型各自的理解是不完整的。作為出發(fā)點(diǎn)去改善模型。
由于很多時候我們不是從頭開發(fā)一個項目,而是改進(jìn)一個正在開發(fā)的項目。這時候第一步是根據(jù)當(dāng)前的狀況來定義Bounded Context.Context Map必須反映出團(tuán)隊的實(shí)際工作,而不是反映那個通過遵守以上描述的指導(dǎo)原則而得出的理想組織。
遺留系統(tǒng)設(shè)計得越好,它就越容易被淘汰。(就像離亂麻)
疑問
什么是集成利益?
大型系統(tǒng)領(lǐng)域模型的完全統(tǒng)一是怎么個統(tǒng)一法?其實(shí)在分模塊上的模型在總的來說不也是統(tǒng)一的么?大家都從這個模塊上獲取數(shù)據(jù)計算、調(diào)用統(tǒng)一接口什么的,比如電商中的客戶管理系統(tǒng)?
怎么理解連續(xù)集成?
上游團(tuán)隊與下游團(tuán)隊是怎么個定義法?什么叫上下游?
A:上游:上游一般指本企業(yè)的材料,產(chǎn)品供應(yīng)商 ;下游:一般就是企業(yè)生產(chǎn)品的經(jīng)銷、分包單位 .
以Service層為例:他的上游就是Dao;下游就是Controller。下游團(tuán)隊的代表類似于用戶代表,發(fā)起請求的客戶端。下游團(tuán)隊依賴于上游團(tuán)隊。
15、精煉
模型就是知識的精煉。
像化學(xué)蒸餾一樣,精煉的主要動機(jī)就是把最有價值的部分提取出來,正是這部分使我們的軟件區(qū)別于別的軟件,這部分叫做Core Domain.
領(lǐng)域模型的戰(zhàn)略精煉包括以下部分:
幫助所有團(tuán)隊成員掌握系統(tǒng)的總體設(shè)計及協(xié)調(diào)。
找到一個具有適度規(guī)模的核心模型并把它添加到通用語言中,從而促進(jìn)溝通。
指導(dǎo)重構(gòu)。
專注于模型中最有價值的那部分。
指導(dǎo)外包、現(xiàn)有組件的使用以及任務(wù)委派。
模式:Core Domain(系統(tǒng)中最有價值的部分)
注意,在設(shè)計大型系統(tǒng)時,有很多有用的組件,他們很復(fù)雜且絕對有必要把它們做好,這導(dǎo)致真正的業(yè)務(wù)資產(chǎn)——領(lǐng)域模型被掩蓋和忽略了。
在制定項目規(guī)劃時,必須把資源分配給模型和設(shè)計中最關(guān)鍵的部分。而不能只是讓技術(shù)能力最強(qiáng)的開發(fā)人員只是去搗鼓技術(shù)基礎(chǔ)設(shè)施,反而把業(yè)務(wù)模型設(shè)計交給不熟悉對象技術(shù)的新人手中。
對模型進(jìn)行提煉。最有價值和最專業(yè)的概念要輪廓分明。盡量壓縮Core Domain.
讓最有才能的人來開發(fā)Core Domain。如果某個設(shè)計部分需要保密以便保持競爭優(yōu)勢,那么它就是Core Domain。
項目團(tuán)隊中,技術(shù)能力 最強(qiáng)的人員往往缺乏豐富的領(lǐng)域知識。
模式:Generic Subdomain(通用子領(lǐng)域)
提取通用子領(lǐng)域,在開發(fā)過程中,通用子領(lǐng)域的優(yōu)先級應(yīng)低于核心領(lǐng)域的優(yōu)先級,且不要分派核心開發(fā)
對于通用子領(lǐng)域,應(yīng)該能把它們識別出來。在開發(fā)過程中,其優(yōu)先級應(yīng)低于核心領(lǐng)域的優(yōu)先級,不派發(fā)給核心開發(fā)人員來完成,可以考慮使用現(xiàn)成的解決方案或公開發(fā)布的模型。
1、現(xiàn)成的解決方案。購買解決方案或使用開源代碼。
優(yōu)點(diǎn):
減少代碼開發(fā)。
維護(hù)負(fù)擔(dān)轉(zhuǎn)移到了外部。
代碼在其他公司等地方使用過,可能較為成熟,因此比自己開發(fā)的代碼更可靠和完備。
缺點(diǎn):
使用前仍然需要花時間評估和理解它。
就業(yè)內(nèi)目前的質(zhì)量控制水平而言,無法保證它的正確性和穩(wěn)定性。(如開源的常常有些坑)
它可能設(shè)計得過于細(xì)致了(遠(yuǎn)超自己想要的目的),集成的工作量可能比開發(fā)一個最小化的內(nèi)部實(shí)現(xiàn)更大。
外部元素的集成常常不順利。可能上下文完全不同,或者難以引用其他軟件包中的Entity.
它可能引入對平臺、編譯器版本的依賴等。
通用子領(lǐng)域最好是被打包成框架的形式,實(shí)現(xiàn)了非常抽象的模型,從而可以與我們的應(yīng)用程序集成來滿足特殊需求。
子組件越通用,其模型的精煉程度越高,它的用處可能就越大。
2、公開發(fā)布的設(shè)計或模型
優(yōu)點(diǎn):
比自己開發(fā)的模型更為成熟,并且反映了很多人的深層知識。
提供了隨時可用的高質(zhì)量文檔。
缺點(diǎn):
- 可能不是很符合你的需要,或者設(shè)計得過于細(xì)致。
在領(lǐng)域建模中,特別是在攻克通用子領(lǐng)域時,通過抄襲留意別人的成果和工作來復(fù)制其設(shè)計和模型,并把這叫做研究。因為當(dāng)有一個廣泛使用的模型時,這些模型不僅健壯和流暢,且被人們廣泛理解,減輕了培訓(xùn)負(fù)擔(dān)。意思就是如果沒有必要,不要去重復(fù)造輪子了。
3、把實(shí)現(xiàn)外包出去
優(yōu)點(diǎn):
使核心團(tuán)隊可以脫身去處理core domain,這是最需要知識和經(jīng)驗積累的部分。
開發(fā)工作的增加不會使團(tuán)隊規(guī)模無限擴(kuò)大下去,同時又不會導(dǎo)致core domain知識的分散。
強(qiáng)制團(tuán)隊采用面向接口的設(shè)計,有助于保持子領(lǐng)域的通用性。
缺點(diǎn):
需要核心團(tuán)隊花費(fèi)一些時間與外包人員商量接口、編碼標(biāo)準(zhǔn)和其他重要方面。(聯(lián)調(diào)溝通實(shí)在效率太低了)
需要消耗大量精力來理解這些代碼。
代碼質(zhì)量不一,取決于兩個團(tuán)隊的能力的高低。
這里自動測試在外包中可能起到重要作用,要求交付的代碼附有單元測試。最有效的是為這些組件指定甚至編寫自動驗收測試。第二點(diǎn)和第三點(diǎn)可以結(jié)合在一起。
4、內(nèi)部實(shí)現(xiàn)
優(yōu)點(diǎn):
易于集成。
只開放自己需要的,不做多余的工作。
可以臨時把工作分包出去。
缺點(diǎn):
需要承受后續(xù)的維護(hù)和培訓(xùn)負(fù)擔(dān)。
很容易低估開放這些軟件包所需的時間和成本。
案例:項目時區(qū)問題的處理方式(p307)
通用不等于重用,不需要特別關(guān)注子領(lǐng)域代碼的可重用性,因為這會違反精煉的基本動機(jī)——盡可能把大部分精力投入到core domain工作中。
注意,如果是通用子領(lǐng)域,那么其設(shè)計則必須嚴(yán)格地限定在通用概念的范圍之內(nèi)。
項目風(fēng)險管理
敏捷過程通常要求通過盡早解決最具風(fēng)險的任務(wù)來管理風(fēng)險。
項目一般面臨兩方面的風(fēng)險,有些項目的技術(shù)風(fēng)險更大,有些項目則是領(lǐng)域建模的風(fēng)險更大一些。
除非團(tuán)隊技術(shù)精湛且對領(lǐng)域非常熟悉,否則第一個雛形系統(tǒng)應(yīng)該以CORE DOMAIN的某個部分作為基礎(chǔ)。
模式: Domain Vision Statement(領(lǐng)域前景說明)
做法:寫一份Core Domain 的簡短描述以及它將會創(chuàng)造的價值,那些不能將領(lǐng)域模型與其他領(lǐng)域模型區(qū)分開的方面就不要寫了。展示出領(lǐng)域模型是如何實(shí)現(xiàn)和均衡各方面利益的。盡量精簡,盡早寫出來,等到獲得新的理解后再修改它。
對比:
標(biāo)明Core
對于擁有詳細(xì)“領(lǐng)域模型”的文檔,我們應(yīng)該從中大幅刪減,找到一個小的core domain 并重構(gòu)它,再逐步添加其他細(xì)節(jié)。標(biāo)識出core domain ,弄出個模型的導(dǎo)航圖。
把模型的主要存儲庫中的core domain 標(biāo)記出來,而不要特意去闡明其角色。使開發(fā)人員很容易就知道什么在核心內(nèi),什么在核心外。
模式:Cohesive Mechanism(內(nèi)聚)
對比于策略模式
Cohesive Mechanism用來滿足規(guī)則或者用來完成模型指定的計算。
注意:算法與領(lǐng)域模型應(yīng)該分離。
模式:Segregated Core(隔離核心)
p319示例
模式:Abstract Core(抽象核心)
深層模型精煉
盡管任何一次突破都會得到一個有價值的深層模型,但只有Core Domain 中的突破才能改變整個項目的軌道。
選擇重構(gòu)目標(biāo):
如果采用“那兒痛治哪”這種重構(gòu)策略,要觀察一下根源問題是否涉及core domain 或core與支持元素的關(guān)系。如果確實(shí)涉及,那么就要接受挑戰(zhàn),首先修復(fù)核心。
當(dāng)可以自由選擇重構(gòu)的部分時,應(yīng)首先集中精力把core domain 更好地提取出來,完善對core的隔離,并且把支持性的子領(lǐng)域提煉成通用子領(lǐng)域。
疑問
16、大比例結(jié)構(gòu)
在一個大的系統(tǒng)中,如果因為缺少一種全局性的原則而使人們無法根據(jù)元素在模式中的角色來解釋這些元素,那么開發(fā)人員就會陷入“只見樹木,不見森林”的境地。
“大比例結(jié)構(gòu)”是一種語言,人們可以用它來從大局上討論和理解系統(tǒng)。
模式:evolving order
使用場景:
一個沒有任何規(guī)則的隨意設(shè)計會產(chǎn)生一些無法理解整體含義且很難維護(hù)的系統(tǒng)。但架構(gòu)中預(yù)先規(guī)定的假設(shè)又會使項目變得束手束腳,而且會極大地限制應(yīng)用程序中某些特定部分的開發(fā)人員、設(shè)計人員的能力。很快,開發(fā)人員就會為適應(yīng)結(jié)構(gòu)而不得不在應(yīng)用程序的開發(fā)上委曲求全,要么就是完全推翻架構(gòu)而又回到不協(xié)調(diào)的開發(fā)的老路上來。
使用:
應(yīng)該允許這種概念上的大比例結(jié)構(gòu)隨著應(yīng)用程序一起演變,甚至可以變成一種完全不同的結(jié)構(gòu)風(fēng)格。有些設(shè)計決策和模型決策必須在掌握了詳細(xì)知識之后才能確定,這樣的決策不必過早的指定。
寧缺毋濫原則。
模式:System Metaphor(系統(tǒng)隱喻)
模式:Responsibility Layer(職責(zé)分層)
待閱讀。
疑問
17、領(lǐng)域驅(qū)動設(shè)計的綜合應(yīng)用
待閱讀。
結(jié)束語
檢驗軟件成功與否的最有效的方法是讓它運(yùn)行一段時間。
雖然開發(fā)最前沿的項目并體驗有趣的思想和工具會帶來巨大的成就感,但如果軟件得不到有效的應(yīng)用,那么一切都將成為空談。
對自己的設(shè)計不要持有守舊情結(jié),隨著大量的深層領(lǐng)域知識和經(jīng)驗的積累,便需要根據(jù)這些理解對模型和設(shè)計進(jìn)行轉(zhuǎn)換,一個成功的設(shè)計并不一定要永遠(yuǎn)保持不變。變更是軟件的固有性質(zhì)。
開發(fā)小的,確保能夠交付的應(yīng)用程序,并堅持用最簡單的設(shè)計來實(shí)現(xiàn)簡單的功能。這種保守的方法有它自己的用武之地,可以使項目范圍保持精簡,并且使項目具有快速響應(yīng)的能力。但集成的、模型驅(qū)動的系統(tǒng)所提供的價值是那些拼湊起來的系統(tǒng)無法提供的。我們應(yīng)該采用的做法是使用領(lǐng)域驅(qū)動的設(shè)計構(gòu)建一個深層的模型和柔性設(shè)計,這樣,具有豐富功能的大型系統(tǒng)就能逐步增長。
是否采用了領(lǐng)域驅(qū)動設(shè)計的標(biāo)志性的特征是“把理解目標(biāo)領(lǐng)域并把學(xué)到的知識融合到軟件中當(dāng)做首要任務(wù)。團(tuán)隊成員在項目中有意識地使用通用語言,并且不斷對語言進(jìn)行精化。
雖然掌握了一些初級技術(shù)的眾多編程人員可以開發(fā)出特定種類的軟件,但他們絕對無法開發(fā)出能在危急關(guān)頭拯救公司的軟件。
工具構(gòu)建人員必須確保他們開發(fā)出的工具能夠提高那些優(yōu)秀軟件開發(fā)人員的能力和工作效率。
領(lǐng)域驅(qū)動設(shè)計提供了一種標(biāo)準(zhǔn)化,讓我們能更加通用得使用、維護(hù)和理解使用了領(lǐng)域驅(qū)動設(shè)計的軟件,就像豐田、本田車的標(biāo)準(zhǔn)化生產(chǎn)和維修一樣,而不像標(biāo)致一樣,不通用也別人不同。
領(lǐng)域開發(fā)缺乏標(biāo)準(zhǔn)的設(shè)計元素,因此每個領(lǐng)域模型和對應(yīng)的實(shí)現(xiàn)都很奇怪且難以理解。
以標(biāo)準(zhǔn)的模式元素為基礎(chǔ),可以避免把精力浪費(fèi)在那些已經(jīng)存在了解決方案的問題上,從而集中精力關(guān)注我們的特殊問題。根據(jù)傳統(tǒng)的模式來建立自己的設(shè)計可以避免產(chǎn)生一個過于特殊化的、難交流的設(shè)計。
模式名稱應(yīng)該作為團(tuán)隊語言中的術(shù)語來使用。
P375 術(shù)語表
疑問:
什么樣的公司文化才有利于迭代開發(fā)?