上一篇:《IDDD 實現領域驅動設計-一個簡單業務用例的回顧和理解》
在《實現領域驅動設計》第二章的前半部分內容中,提到領域和子域的概念,並且作者把這兩者又進行了細致的區分,其實在《領域驅動設計》書中,也有進行詳細說明,只不過是在第十五章《精煉》中,章節比較靠后,我先是讀了《實現領域驅動設計》這部分的內容,但讀完之后,完全沒有任何的感覺,或者說我自己和作者沒有產生一些共鳴,也記不起來自己到底讀了什么內容,但是在讀《領域驅動設計》對應這部分內容的時候,我覺得有些內容是我想要的,也產生了一些共鳴,這讓我對之前短消息項目也有了一些新的思考,我覺得還是蠻有價值的,下面是自己的一些理解。

一張很重要的圖,引自:《實現領域驅動設計》
Domain 領域
首先,領域(Domain)不是領域模型(Domain Model),不要把他們兩個畫等號,從字面上進行理解,“領”的意思,可以理解為領土、領地或屬於的某一區域,但不管它包含的是什么,它總是有一個界限,也就是說這個界限要進行明確,如果不進行明確,就會產生一些麻煩,比如“領地糾紛”等等,這個界限其實就可以看作是“領”的意思,“域”的意思,就是一個方面的具體稱謂,加上“領”,領域的意思,其實就是明確某一方面的稱謂。可能有點暈,我們開發某一套業務系統,比如快遞行業的業務系統,那么這個快遞業務系統之內的所有業務都包含在領域中,這個領域稱之為快遞業務領域,其中可能有很多的子領域,或者是業務模塊,但都屬於這個領域之內,如果超出這個領域之外,那么業務模塊將不包含在快遞業務領域之內了。在上一篇中有說到領域專家,其實,就是對某一領域精通的人,關鍵詞是某一領域,而不是所有領域,強調的是界限的重要性。
從上面圖中可以看出,業務領域中所有東西構成了這個業務的領域概念,也就是說它是唯一的,你開發什么業務系統,首先需要明確的是,你業務系統的領域是什么?如果連這個都確定不了,那么領域驅動設計也就沒有再進行下去的必要了。讓我自己來考驗自己一下,之前開發的消息項目(MessageManager),這個消息項目的領域是什么?我想你應該會和我一樣,腦海中首先想到的應該就是消息領域(Message Domain),其實我覺得這個答案沒什么問題,消息項目不圍繞消息領域開展,那圍繞什么開展呢,你可能會有一些疑問,比如消息項目中會有一些用戶模塊,用戶模塊不應該屬於用戶領域嗎?如果消息項目只有一個消息領域,那它們倆不相違背嗎?其實這個答案,可以從上面的圖中找到,消息領域是一個大的概念,它包含了這個消息項目中所有的業務領域概念,消息項目中的用戶模塊,只不過是消息領域的內部的一部分而已,不要被消息領域中的“消息”字眼所迷惑。
對於開發者來說,理解領域的概念是有一些歧異的,比如消息領域,我們開發者該怎么去描述它,或者表達它呢?我想你應該和我一樣,首先,新建一個 Message.Domain 類庫項目,然后把所有的業務操作都在這個類庫中進行實現,實現完成之后,你告訴領域專家,說這個 Message.Domain 項目就是消息領域,仔細一想,好像也確實有些道理,對於開發者來說,消息領域的表達就是項目代碼的實現,這樣做也無可厚非。但是,有一點非常重要,在消息領域確定的過程中,不是只有開發人員的參與,最重要的還要有領域專家的參與和討論,其實,對消息領域的最理解的人,不是開發者自己,而是領域專家,消息領域的表達也不只是代碼表現這么簡單,而是之前提到的通用語言,消息領域在開發者和領域專家之間的傳遞和確定,這個介質其實就是通用語言,之前有說到通用語言是開發者和領域專家共同創建的,它的表現形式可以是一個白板,也可以是一堆文件,又或者是一個項目代碼等等,但不論是什么東西,它能在開發者和領域專家正確傳遞領域所包含的業務概念即可。
在上面圖中,領域中有一個核心域(Core Domain)的概念,核心域是什么?它是領域中最重要的一塊,你可以把它看作是人體中的心臟,也就是說是最核心的東西,開發者和領域專家花費最多的精力都是在它上面,一個業務系統一般有且只有一個核心域,但是一般核心域的精煉工作是需要花費很多的時間和精力,而且也很容易出錯,如果業務系統中核心域的精煉出現了問題,那么這個業務系統注定是失敗的,因為當一個核心域確定下來之后,開發者和領域專家剩余的工作,都是圍繞着核心域進行展開的,比如一個人得了心臟病,而醫生在診斷的時候,卻認為是肝臟出了問題,然后他就對這個病人的肝臟做了手術,可想而知后果會怎樣。。。這個看似簡單的問題,但其實中間也蘊含了一些重要東西,首先,我們可以把它抽離出來,有三個人物:病人、診斷醫生和手術醫生,再想一下,我們業務系統開發,也有三個重要對象:業務系統、領域專家和開發者,然后,你再對它們進行對比下,就可以得出一些東西了,診斷醫生是最了解病人的,由他來確定病人得了什么病,就好比領域專家把業務系統的核心域精煉出來,手術醫生只不是實施者,用的是手術刀,而開發者用的是代碼,但和看病不一樣的是,核心域的精煉是領域專家和開發者共同探討決定的,這就避免了診斷醫生和手術醫生所產生一些不必要的“沖突”,說了這么多,總而言之,核心域的精煉很重要,需要領域專家和開發者共同參與。
回到我們的消息領域上,那在消息領域中,核心域是什么呢?我的個人想法是發消息業務操作,這是消息領域中最重要的一個業務操作,消息的存在就是為了傳遞信息,在現實生活中,對於消息相類似的就是寄信,對於寫信的我來說,我其實就是寄信的領域專家,為什么?因為我自己就是用戶,對於寄信用戶來說,我寫信的目的就是讓收件人可以收到我的信,具體這封信是怎么寄出去的,公路、鐵路、飛機等等,這些我都不關心,我只關心的是現在這封信有沒有到收件人手里。按照這個思路進行理解,對於消息領域來說,領域專家所能描述出來的核心域描述就是:發消息,這個和之前我們提到的待定項提交到沖刺一樣,最簡單的業務描述就是這樣,至於消息發送限制、或者發送之后要不要郵件通知,這都是發消息具體的內部實現,對於消息領域以后的業務變化來說,變的也只是核心域的內部而已,我們只需要改變具體的實現就可以了,有點以不變應萬變的意思,不變的是核心域,變的是核心域的內部實現。
描述這么多,可能有點暈,只需要記住兩個概念就可以了,領域和核心域,具體的深入理解,只有運用后才可以真正體會到。
SubDomain 子域
什么是子域(SubDomain)呢?理解子域的概念,必須和核心域對應起來,子域也是領域的一部分,只不過它的重要性沒有核心域那么大,它們之間的關系,你可以看作是人體器官中,心臟和其他器官的關系,在《領域驅動設計》中,其實並沒有子域的概念,而是通用子域(Common Subdomain),而在《實現領域驅動設計》中,作者把子域拆分成了支撐子域(Generic Subdomain)和通用子域(Common Subdomain)。對於領域來說,除了核心域,用來支撐核心域的子域,就可以稱之為支撐子域,在整個領域中,可以被公用的子域,稱之為通用子域,通用子域還有一個理解是,在某一個業務領域中,它可能是被看作是通用領域,但是在另外一個業務領域中,它可能就被看作是核心域了,舉個例子,比如在團購業務系統中,地圖服務可能就被看作是通用領域,而對於地圖服務商來說,毫無疑問,地圖服務將是他們的核心域。
這些概念性的東西可能理解起來很費勁,我們再回到消息領域中,在上面分析中,我們已經確定了“發消息”是核心域,插一句,有人說,那回復消息是什么啊?難道有兩個核心域?其實發消息就包含回復消息,因為回復消息也是發消息的一種信息,回到正題上,我們在消息領域中精煉一下支撐子域和通用子域,我現在可以想到的就是消息驗證服務領域,就是在發消息之前對發件人、收件人、以及對消息內容進行驗證,就好比你去郵局寄一封信,工作人員需要驗證一下收發件地址一樣,消息驗證服務領域用來支撐發消息核心域,所以可以把它單獨精煉出來進行探討,還有就是,對於支撐子域來說,在整個領域中,可能會有多個,但大部分都是圍繞核心域進行展開的,這也就是“支撐”的具體含義吧,說到這,我現在腦子里面有閃現一個,那就是消息發送之后的通知服務,這個也可以看作是支撐子域,需要記住的是,支撐子域雖然沒有核心域那么重要,但它也是領域的一種,也是非常重要的,不要完全忽略它。
說了支撐子域,再來分析一下,消息領域中的通用子域,其實就是用戶領域,用戶的概念會貫穿整個消息領域,因為一切都是用戶進行操作完成相關業務,用戶領域的概念其實和上面說到的地圖服務領域是一樣的,在用戶業務系統中,用戶領域就不是通用子域了,而是核心域,對於非用戶業務系統來說,用戶領域在其他業務系統中,都可以被看作是通用子域。可能還有一點內容容易造成誤解,就是消息領域中,“用戶”的概念是很重要的,發消息是用戶進行發送,那用戶領域是不是應該被看作是核心域呢?我記得當時在開發消息項目的時候,曾經就把發消息業務操作放在了用戶模型中,認為用戶才能發消息啊,那如果是這樣的理解思路,所有的業務系統中的業務操作,都應該是放在用戶模型中,因為只有用戶才能進行這些操作,但好像並不是這么回事,我們有點過於“面向對象”了,應用軟件中和現實生活中的用戶概念是不太一樣的。
在業務領域中,對於通用子域來說,是比較容易精煉的,但是對於支撐子域來說,精煉它是有些難度的,難點就在於它和核心域的區分,有時候,我們可能會從核心域中剝離支撐子域,當然,最重要的,還是領域專家和開發者之間如何確立通用語言並與之溝通。
啰里八嗦的,就記錄到這!