1. DDD是什么莺掠?解決什么問題?
1.1 軟件開發(fā)的困境
- “隨著業(yè)務(wù)的擴(kuò)展,軟件開發(fā)投資越來越大” 團(tuán)隊(duì)的規(guī)模也開始變得越來越大战秋,軟件系統(tǒng)的投資和維護(hù)的成本變得越來越高。
- “業(yè)務(wù)人員不懂架構(gòu)讨韭,架構(gòu)師不懂代碼脂信,開發(fā)人員不不懂業(yè)務(wù)模型” 當(dāng)團(tuán)隊(duì)中的關(guān)鍵角色誰也不懂誰的時(shí)候,問題來了透硝。狰闪。。
- “重構(gòu)是好的濒生,但什么時(shí)候要重構(gòu)埋泵?重構(gòu)到什么樣的架構(gòu)就是夠?的了?” 每個(gè)有追求的團(tuán)隊(duì)都在做重構(gòu)罪治,但管理者更關(guān)心丽声,什么時(shí)間必須要重構(gòu)?重構(gòu)的目標(biāo)在哪觉义?
1.2 DDD的來源及簡介
?? 2004年Eric Evans 發(fā)表Domain-Driven Design –Tackling Complexity in the Heart of Software (領(lǐng)域驅(qū)動(dòng)設(shè)計(jì))恒序,簡稱DDD,DDD是一套綜合軟件系統(tǒng)分析和設(shè)計(jì)的面向?qū)ο蠼7椒ā?br>
?? Eric的著名書籍《領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)》的副標(biāo)題是“軟件核心復(fù)雜性的應(yīng)對(duì)之道”谁撼,這個(gè)其實(shí)點(diǎn)出了DDD的來源和目標(biāo)歧胁,很多因素會(huì)使軟件的開發(fā)復(fù)雜化滋饲。軟件是從現(xiàn)實(shí)世界到數(shù)字世界的一種建模和映射,軟件復(fù)雜性的根本原因還是業(yè)務(wù)本身復(fù)雜性喊巍,軟件開發(fā)者無法回避這種復(fù)雜性屠缭,所能做的是去控制這種復(fù)雜性。
怎樣才能讓軟件和領(lǐng)域和諧相處呢崭参?最佳方式是讓軟件成為領(lǐng)域的一個(gè)映射呵曹。軟件需要包含領(lǐng)域里重要的核心概念和元素,并精確實(shí)現(xiàn)它們之間的關(guān)系何暮。也就是說奄喂,軟件需要對(duì)領(lǐng)域進(jìn)行建模。
?? 領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)分為兩個(gè)階段:以一種領(lǐng)域?qū)<液M荨⒃O(shè)計(jì)人員跨新、開發(fā)人員都能理解的通用語言作為相互交流的工具,在交流的過程中發(fā)現(xiàn)領(lǐng)域概念坏逢,然后將這些概念設(shè)計(jì)成一個(gè)領(lǐng)域模型;第二個(gè)階段是由領(lǐng)域模型驅(qū)動(dòng)軟件設(shè)計(jì)域帐,用代碼來實(shí)現(xiàn)該領(lǐng)域模型。
?? 從DDD提出到開始流行是整,感覺經(jīng)過了10年左右的時(shí)間肖揣,巧的是XP和敏捷從提出到流行也差不多10年左右的時(shí)間「∪耄可見一套方法論從出現(xiàn)到成熟確實(shí)是有一定規(guī)律并需要成長時(shí)間的龙优。
?? 按Martin Fowler在PoEAA一書中給了一個(gè)圖。說明當(dāng)軟件在開發(fā)初期事秀,以數(shù)據(jù)驅(qū)動(dòng)的架構(gòu)方式非常容易上手彤断,但是隨著業(yè)務(wù)的增長和項(xiàng)目的推進(jìn),軟件開發(fā)和維護(hù)難度急劇升高秽晚。領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)則在項(xiàng)目初期就處在一個(gè)比較難以上手的位置瓦糟,但是隨著業(yè)務(wù)的增長和項(xiàng)目的推進(jìn),軟件開發(fā)和維護(hù)難度平滑上升赴蝇。
2. 模型和建模
2.1 什么是模型
- 模型是對(duì)客觀世界事物的一種抽象和簡化菩浙。
- 它是從某個(gè)角度反映人對(duì)客觀世界事物的一種認(rèn)識(shí)。
- 它用于對(duì)事物的本質(zhì)進(jìn)行深入細(xì)致的研究句伶。
2.2 模型的例子
2.2.1 地圖的例子
?? 地圖就是一種典型的模型【Ⅱ撸現(xiàn)實(shí)世界的地理信息往往很復(fù)雜,一個(gè)地理位置上會(huì)包括非常多的信息考余,例如有位置信息先嬉,地形,氣候等信息楚堤,也有城市疫蔓,道路含懊,綠化,管網(wǎng)衅胀,建筑等這些城市建設(shè)信息岔乔,還可能會(huì)有擁堵情況,商場(chǎng)滚躯,文化等各種附加于地理信息的各種信息在里面雏门。如何表達(dá)一個(gè)地圖信息其實(shí)并不容易,如何表達(dá)一個(gè)地圖信息是一件非常復(fù)雜的事情掸掏。
?? 我們常見的地圖茁影,一般都會(huì)縮小尺寸,忽略很多細(xì)節(jié)丧凤,分不同類型的地圖募闲,現(xiàn)在還有圖層的方式來表達(dá)不同地理信息。地圖其實(shí)就是一種模型息裸,而且地圖很多建模方式在軟件設(shè)計(jì)中也能找到映射蝇更。
?? 看兩個(gè)地圖例子沪编,建模從古至今就存在呼盆,而且隨著人們認(rèn)知水平和建模能力還會(huì)不斷的演進(jìn)。
?? 回到軟件研發(fā)的話題,軟件的研發(fā)也是一種建模的過程相嵌,傳統(tǒng)的方法中腿时,從問題空間到解決方案的空間,會(huì)經(jīng)過需求采集和分析饭宾,概要設(shè)計(jì)批糟,詳細(xì)設(shè)計(jì)再到編碼的過程。正如我們國家“系統(tǒng)分析師” 和“系統(tǒng)設(shè)計(jì)師” 兩種職稱考試一樣看铆,系統(tǒng)分析和系統(tǒng)設(shè)計(jì)是分離的徽鼎,“系統(tǒng)分析師” -BA屬于業(yè)務(wù)專家,“系統(tǒng)設(shè)計(jì)師”-SA是系統(tǒng)專家弹惦。隨著信息不斷傳遞的過程否淤,信息也在不斷的失真,導(dǎo)致可能到了最后交付階段才發(fā)現(xiàn)很多功能不是客戶想要的棠隐,或者客戶需求變化太快石抡,軟件的變更也不能快速跟隨需求變化。
?? 再舉一個(gè)常見的例子:一個(gè)函數(shù)寫了幾千行助泽,里面的if-else寫了一大堆啰扛,計(jì)算各種業(yè)務(wù)規(guī)則嚎京。另一個(gè)人接手之后,分析了好幾個(gè)月隐解,才把業(yè)務(wù)邏輯徹底理清楚挖藏。從表面來看,這是代碼寫的不規(guī)范厢漩,要重構(gòu)膜眠,把一個(gè)幾千行的函數(shù)拆成一個(gè)個(gè)小的函數(shù)。從根本上來講溜嗜,就是“重要邏輯”隱藏在代碼里面宵膨,沒有“顯性”的表達(dá)出來。這里可以引用一個(gè)觀點(diǎn):建模的本質(zhì)就是把“重要的東西進(jìn)行顯性化炸宵,并進(jìn)而把這些顯性化的構(gòu)造塊辟躏,互相串聯(lián)起來,組成一個(gè)體系“土全。
?? DDD通過建立一個(gè)業(yè)務(wù)域到軟件域的通用模型捎琐,把問題空間同解決方案空間聯(lián)系在一起,真正把領(lǐng)域的知識(shí)挖掘出來裹匙,讓領(lǐng)域?qū)<铱梢匀ヲ?qū)動(dòng)軟件的實(shí)現(xiàn)瑞凑。
3. 統(tǒng)一語言(UBIQUITOUS LANGUAGE)
?? 解決問題首先要從理解問題入手,很多事情的難點(diǎn)不在于解決問題概页,而在于認(rèn)知問題籽御。關(guān)于統(tǒng)一語言必要性,有一個(gè)經(jīng)典的通天塔故事惰匙,人類想建一座通天塔技掏,進(jìn)度很快,上帝害怕了项鬼,于是上帝讓建造者說不通的語言哑梳,這樣通天塔就再也沒有能建起來了。統(tǒng)一語言是一件事情能順利開展的基礎(chǔ)绘盟。
?? 由于語言上存在鴻溝鸠真,領(lǐng)域?qū)<覀冎荒苣:孛枋鏊麄兿胍臇|西,開發(fā)人員雖然努力去理解一個(gè)自己不熟悉的領(lǐng)域但也只能形成模糊的認(rèn)識(shí)奥此,結(jié)果就是各說各的話弧哎,或者都是一知半解,最后到上線前才會(huì)發(fā)現(xiàn)漏了這個(gè)漏了那個(gè)稚虎。
?? 通用語言也并不是像UML撤嫩,XML Schema或Java這樣的語言,它是一種自然的但經(jīng)過濃縮的領(lǐng)域語言蠢终,它是一種開發(fā)與用戶共享的語言序攘,用來描述問題和領(lǐng)域模型茴她。通用語言不是把從用戶那里聽到的內(nèi)容翻譯為開發(fā)的語言,而是為了減少誤解程奠,讓用戶更容易理解的草圖丈牢,從而可以真正的幫助糾正錯(cuò)誤,幫助開發(fā)獲取有關(guān)的領(lǐng)域新知識(shí)瞄沙。
?? 那么統(tǒng)一語言到底長什么樣子己沛?對(duì)DDD的UL沒有標(biāo)準(zhǔn)的定義,可以是圖距境,也可以是文字申尼,UML的各種圖依然是常見的表達(dá)方式,以DDD書中例子來說明下UL的一個(gè)應(yīng)用垫桂。
?? 示例:制定貨運(yùn)路線师幕,比較兩個(gè)圖和兩段溝通交流的方式
-
場(chǎng)景1:最小化的領(lǐng)域抽象
-
場(chǎng)景2:用領(lǐng)域模型進(jìn)行討論
- 兩種溝通方式的比較
最小化的領(lǐng)域抽象 | 用領(lǐng)域模型進(jìn)行討論 | |
---|---|---|
用戶 | 那么,當(dāng)更改清關(guān)(customs clearance)地點(diǎn)時(shí)①诬滩,需要重新制定整個(gè)路線計(jì)劃啰霹粥。 | 那么,當(dāng)更改清關(guān)地點(diǎn)時(shí)疼鸟,需要重新制定整個(gè)路線計(jì)劃啰后控。 |
開發(fā)人員 | 是的。我們將從貨運(yùn)表(shipment table)中刪除所有與該貨物id相關(guān)聯(lián)的行愚臀,然后將出發(fā)地忆蚀、目的地和新的清關(guān)地點(diǎn)傳遞給Routing Service矾利,它會(huì)重新填充貨運(yùn)表姑裂。Cargo中必須設(shè)立一個(gè)布爾值,用于指示貨運(yùn)表中是否有數(shù)據(jù)男旗。 | 是的舶斧。當(dāng)更改Route Specification(路線說明)的任意屬性時(shí),都將刪除原有的Itinerary(航線)察皇,并要求Routing Service(路線服務(wù))基于新的Route Specification生成一個(gè)新的Itinerary茴厉。 |
用戶 | 刪除行?好什荣,就按你說的做矾缓。但是,如果先前根本沒有指定清關(guān)地點(diǎn)稻爬,也需要這么做嗎嗜闻? | 如果先前根本沒有指定清關(guān)地點(diǎn),也需要這么做嗎桅锄? |
開發(fā)人員 | 是的琉雳,無論何時(shí)更改了出發(fā)地样眠、目的地或清關(guān)地點(diǎn)(或是第一次輸入),都將檢查是否已經(jīng)有貨運(yùn)數(shù)據(jù)翠肘,如果有檐束,則刪除它們,然后由Routing Service重新生成數(shù)據(jù)束倍。 | 是的被丧,無論何時(shí)更改了Route Spec的任何屬性,都將重新生成Itinerary绪妹。這也包括第一次輸入某些屬性晚碾。 |
用戶 | 當(dāng)然,如果原有的清關(guān)數(shù)據(jù)碰巧是正確的喂急,我們就不需要這樣做了格嘁。 | 當(dāng)然,如果原有的清關(guān)數(shù)據(jù)碰巧是正確的廊移,我們就不需要這樣做了糕簿。 |
開發(fā)人員 | 哦,沒問題狡孔。但讓Routing Service每次重新加載或卸載數(shù)據(jù)會(huì)更容易些懂诗。 | 哦,沒問題苗膝。但讓Routing Service每次重新生成一個(gè)Itinerary會(huì)更容易些殃恒。 |
用戶 | 是的,但為新航線制定所有支持計(jì)劃的工作量很大辱揭,因此离唐,除非非改不可,我們一般不想更改航線问窃。 | 是的亥鬓,但為新航線制定所有支持計(jì)劃的工作量很大,因此域庇,除非非改不可嵌戈,我們一般不想更改路線。 |
開發(fā)人員 | 哦听皿,好的熟呛,當(dāng)?shù)谝淮屋斎肭尻P(guān)地點(diǎn)時(shí)褐墅,我們需要查詢表格鄙才,找到以前的清關(guān)地點(diǎn),然后與新的清關(guān)地點(diǎn)進(jìn)行比較凛虽,從而判斷是否需要重做。 | 哦偿短。那么需要在Route Specification添加一些功能欣孤。這樣,當(dāng)更改Route Specification中的屬性時(shí)昔逗,查看Itinerary是否仍滿足Specification降传。如果不滿足,則需要由Routing Service重新生成Itinerary勾怒。 |
用戶 | 這個(gè)處理不必考慮出發(fā)地和目的地婆排,因?yàn)楹骄€在此總要變更。 | 這一點(diǎn)不必考慮出發(fā)地和目的地笔链,因?yàn)镮tinerary在此總是要變更的段只。 |
開發(fā)人員 | 好的,我明白了鉴扫。 | 好的赞枕,但每次只做比較就簡單多了。只有當(dāng)不滿足Route Specification時(shí)坪创,才重新生成Itinerary炕婶。 |
?? 很明顯,這兩段對(duì)話有意使用了相似的結(jié)構(gòu)莱预,第一段對(duì)話顯得更啰嗦柠掂,對(duì)話雙方需要不斷對(duì)應(yīng)用程序的特性和表達(dá)不清的地方進(jìn)行解釋。第二段對(duì)話使用了基于領(lǐng)域模型的術(shù)語依沮,因此討論更簡潔涯贞,表達(dá)了領(lǐng)域?qū)<业母嘁鈭D。在這兩段對(duì)話中危喉,用戶都使用了“itinerary”這個(gè)詞宋渔,但在第二段中它是一個(gè)對(duì)象,這使得雙方可以更準(zhǔn)確姥饰、具體地進(jìn)行討論傻谁。他們明確討論了“route specification”,而不是每次都通過屬性和過程來描述它列粪。