作者簡介:張剛,軟件工程博士,阿里云云效資深技術專家,ALPD方法學核心成員。
讀者福利:前往,免費領取阿里爆款架構師課程《DDD高手進階12講》(原價98元)。
引言
領域模型是重要的概念。但是,真正瞭解並能熟練運用它的人並不多。這實在是殊為可惜的一件事情。
軟件開發中的許多問題,例如需求難於溝通,軟件難以演化,都和領域模型緊密相關。更關鍵的是,掌握這個概念並不難。通過練習,一個團隊只需要一兩個小時,就可以習慣領域模型的建模思路,並且開始從中受益。
那麼,什麼是領域模型?如何理解領域模型的本質?為什麼領域模型能給軟件開發帶來巨大幫助?如何表達它,如何應用它?本文將依次展開這些概念。
什麼是領域模型?
首先我們來看什麼是領域模型。
領域模型定義了領域內的關鍵的概念以及這些概念之間的關係。
為什麼要強調“領域內”?是因為模型(或者說概念)只在它所處問題空間中才有意義。這分為兩種情況:
1)一個概念只在某個特定領域有意義。例如,“應收賬款”,就只是在財務領域,更嚴格的說是會計領域才有意義。
2)一個概念必須通過領域限定,才有具體的意義。例如,“軌道”這個概念,它可能是天文學領域的行星運動軌道,也可能是鐵路領域的火車軌道,必須得先限定領域,這個概念才有真正的價值。
關鍵信息1:領域模型最重要的是概念,領域模型也被稱為概念模型。
雖然有人說“領域模型是領域內的概念的可視化表示”,但是, “可視化”並不本質,雖然它也重要。相比較而言,“概念”才是根本。
關鍵信息2:“語言的邊界就是思想的邊界”—— 一個好的領域模型,必然承載了有用的知識。
對一個不熟悉特定領域的人來說,理解概念,往往是進入一個領域最快的方式。例如,小時候的兒歌:太陽大,地球小,地球繞著太陽跑。地球大,月亮小,月亮繞著地球跑。它就可以認為是一種概念模型的表達。在這個模型中,包括了3個概念實體:太陽,地球和月亮。而太陽和地球的關係是地球繞著太陽運動,地球和月亮的關係是月亮繞著地球運動。用一張圖畫下來就是:
這張圖其實是UML的對象圖,當然即使你不熟悉UML,就是作為線框圖,也能很容易理解。
同樣,在各種業務領域,都有自己的關鍵概念。這些概念的表達也不一定是圖。例如,剛才所講的會計領域,我們可以使用一張表來表達下列的幾個關鍵概念:
會計主體(本方)->對方 |
|
應收賬款 |
貨物已經發給對方,但是尚未收到貨款 |
應付賬款 |
已經收到對方貨物,但是尚未支付貨款 |
預收賬款 |
已經收到對方貨款,但是尚未發貨 |
預付賬款 |
已經支付對方貨款,但是尚未收到貨物 |
通過這樣一張表格,相信即使對會計領域不甚瞭解對小夥伴,也能快速掌握相關的知識。如果我們更進一步,能夠理解到,應收和預付,本質上是本方的債權,而預收和應付,本質上是本方的債務。用一張圖表示就是:
在這裡我們使用了UML類圖來表示。對於不熟悉UML的小夥伴,可能需要解釋一下三角形箭頭的意思,它代表“是一種”,例如,應收賬款是一種債權。
更嚴格的,如果一筆應收賬款的帳期已經很長,例如5年,那麼這種賬款有很大概率已經收不回來了,所以需要計提壞賬。有一些通用的壞賬計提策略,例如:一年以內5%,一到二年20%,二到三年50%,三年以上100%等。所以,面向剛才的應收賬款,我們可以用下面的圖來表達這樣的概念:
圖是一種視圖,它不需要面面俱到。例如,本圖中,並沒有顯示一切和會計科目相關的信息,而只是集中於壞賬的計提。其中,我們在應付賬款和壞賬之間引入了一個新的符號,認識UML的小夥伴知道我們表達的是”應收賬款中包括壞賬“。圖中的帳期、金額等,我們成為“屬性”,用於詳細的說明應收賬款、壞賬這些概念還包括哪些內容。
由於領域模型本質上傳遞的是概念,是知識性的信息,所以,對於軟件開發的場景來說,把這些知識顯式化,能快速對齊不同角色、不同參與方之間的概念,加速溝通,避免誤解。
領域模型是重要的業務資產
領域概念沉澱業務知識,而且非常穩定。
一家在某個領域深耕多年的企業,和一個新入行的企業,差別是什麼?差距可能是多方面的,但是最大的差距應該是“認知”。——所以我們常常會看到,新入行的企業追趕深耕多年的企業的辦法,常常是去成熟的的企業高薪“挖角”。按道理說,挖來的這些人既不能把原公司的客戶帶來,也不可能把原公司的系統帶來,那麼本質上他們給新企業帶來了什麼呢?他們對新公司最大的幫助,是對特定領域的認知。在業務領域,認知非常值錢,而且非常穩定。我們也會看到,一些在某個領域建立了優勢的企業,特別是諮詢類企業,單靠業務領域的諮詢,就能給企業帶來客觀的收入。如果有良好維護的領域模型,那麼領域模型就是這些認知沉澱的最佳位置所在。
更重要的是,儘管業務常新,但是領域模型卻相當穩定。我們以商品交易為例。我們知道買家、買家、商品、交易這些概念,都是商品交易領域的核心概念。這些概念並不會隨著業務的演進發生劇烈的變化,無論是B2C業務,C2C業務,C2M業務,拼團業務還是秒殺業務。不同的業務,體現的只是對這些業務概念的不同組織方式。當然,真正的領域模型要遠遠比上述概念複雜的多。我們這裡只是舉一個簡單的例子,說明領域概念的穩定性。
領域模型的躍遷和生長
當然,我們說領域模型穩定,並不是說它一成不變。優秀的領域模型都一定會持續生長,甚至有時候會發生本質的躍遷。
一旦一個模型被推翻,我們會認為,我們對某個領域的認知,一定發生了非常本質的躍遷。例如,前述的兒歌“太陽大,地球小,地球繞著太陽跑。地球大,月亮小,月亮繞著地球跑。”並不是一開始就是這樣認知的。無論中外,在幾百年前,我們都曾經認為,地球是宇宙的中心,太陽、月亮都是繞著地球運行的。那麼,這個模型畫出來就是下面這個樣子:
地心說對象圖
地心說到日心說,是我們宇宙認知到巨大進步,以為日心說模型徹底否定了地心說模型。在軟件領域也是這樣。我曾經經歷過幾次領域模型躍遷的場景,每次都伴隨這業務認知的巨大進步。
當然,在現實生活中,躍遷並不多見。更多的時候都是在原有的模型上穩定發展,逐步增入各種新的概念和各種細節。模型的生長過程,本質上也是業務能力積累的過程。
穩定的領域模型帶來軟件的適應性
需求是不穩定性的,而領域模型是穩定的,這啟發我們,如果以領域模型為中心去構造軟件,那麼我們就會構造出很多穩定的積木塊。新的需求,就可能通過這些穩定的積木塊,通過不同的搭建方式,形成豐富多彩的應用。在這種情況下,我們的軟件對於變化的適應力最強,開發成本最低。
領域模型存在於哪裡
用類圖表示領域模型
UML類圖是表達領域模型的非常好的工具,雖然並不存在如何表達領域模型的標準。因為在UML中,“類”並不簡單是軟件設計中的“類”,它代表的其實是“概念”,所以,把類圖用在領域模型的表達上,是非常恰切的。而且,UML已經約定了概念和概念之間的關係,例如:類、屬性、關聯、關聯的多重性、泛化、聚合、組合、依賴等等。
對於不熟悉UML的人來說,使用UML也完全沒必要有什麼心理負擔。UML是一個高度靈活的結構,它具有漸近的能力。你沒有必要掌握所有複雜的概念才開始工作,根據我的經驗,只要一開始能把類(代表概念)、類的屬性和它們的關係描述出來,最多再知道多重性怎麼表示,就足以應付大多數的場景。
有些小夥伴有面向對象的經驗,在這裡會糾結於要不要對“方法/操作”進行建模。在“領域模型”是一種“業務概念”這個上下文中,方法是完全多餘的東西,暫時不需要在這個階段進行建模。我認為在實現階段補足它們更合適。
在交流和文檔中使用領域模型
領域模型寫在紙上並不是最關鍵的。作為概念模型,它反映了這個領域的最重要的概念,也構成了表達業務概念的詞彙。所以:
最好的領域模型,應該時刻存在於團隊成員的心中,存在於日常的交流活動中。
為了做到這一點,我對自己的團隊和輔導過的團隊,都有一個要求,這個要求也被成為交流活動中的“統一語言”:
任何在需求描述中出現的概念,都必須出現在領域模型中。如果需求描述中存在概念之間的關係,領域模型中也必須有這個關係
這個要求看似簡單,實際做到會比較困難。特別在剛開始的時候,團隊成員可能並不適應這種做法,常常就忘記了這個準則,需要經常糾正。但是一旦習慣,大家會發現,在日常交流活動中,因為所有的概念都已經顯式化,誤解大大減少,共識更容易達成,導致的後果就是最後團隊成員,都會非常自覺的維護“統一語言”的做法。
出於同樣的原因,編寫文檔時,使用領域模型作為統一語言也成了一個非常自然的結果。
在代碼中使用領域模型
由於領域模型已經被顯式化,所以如果能夠在代碼中使用領域模型,那麼代碼就會獲得更好的易讀性。由於領域模型和代碼對應的更加一致,那麼在領域模型發生演進時,代碼就會變得更容易演進。在這方面,領域驅動設計給出了一組完備的模式,可以幫助架構師和開發人員自然地把領域模型轉化為代碼。本文中我們並不準備展開這些模式。在此,暫時先請讀者們記住下面的結論,後面會有更深入的討論:
代碼和問題域之間的表示差距應該儘量縮小,領域模型是連接現實世界和數字世界的最佳橋樑。使用領域模型作為代碼中的業務概念的基本表達元素,可以大幅提升代碼的易讀性,也可以更好的支持業務的演進。
領域模型來自哪裡
領域模型反映了關鍵的業務認知,但是認知並不會憑空建立。能夠一上來就洞悉一切本質的,要麼是這個人是天才,要麼說明這個領域已經是一個非常成熟的領域,已經無需探索和發現。
大多數時候,認知都來自於業務場景的啟發。所以,領域模型建立的過程,往往是伴隨著需求分析同步產生的。
我畫了下面這張圖,來說明領域模型和業務場景之間的關係:
也就是說,領域模型是在業務場景的激勵下逐漸完善的。而且,反過來因為對領域的認知更加深刻,領域模型還有助於新的業務場景的發現。
探索和發現最好不要一個人獨自進行。更多地時候,應該儘量進行集體建模。集體建模不僅僅利於探索和發現,而且它也有助於達成對於關鍵業務概念的共識。
集體建模的最好工具並不是UML的電子化工具,使用白板,在開放空間中的討論,往往能夠收到最好的效果。
由於領域模型表達的是概念,所以對於概念及時地分解和抽象,是領域建模的基本功。當然,現實中受過嚴格的分解和抽象訓練的人並不多,特別是很多業務人員往往都缺乏這方面的能力。我在實際工作中,觀察到具有面向對象經驗的開發人員,經過一定時間的練習,可以很快掌握這方面的技能。所以,如果有一些具有經驗的開發人員參與建模,往往可以獲得質量更高的模型。
常見誤區
領域模型的概念產生於90年代的面向對象社區。在那個時候,業務變化還不像今天這樣頻繁,迭代的思想也還沒有完全成熟,業務人員和技術人員也沒有像今天這樣密集的交流,所以,無論是從參考書上,還是實踐上,領域模型的概念都難免留下早年做法的影響。其中,有若干誤區,在實踐中是應該儘量避免的:
誤區1: 從開發視角進行領域模型的建模
常常有技術人員問:“領域模型和ER圖有什麼關係?” 對這個問題最直接的回答就是:“沒有關係”。固然,我肯定知道在有了領域模型之後,設計ER圖會更簡單,或者對於一個還缺乏領域模型的遺留系統,研究數據庫結構可以帶來有效的輸入,但是它們的立足點是完全不一樣的。
領域模型一定要從業務視角去看,因為領域模型反映的是業務認知。一旦在領域模型中摻雜了技術的概念,不僅僅是因為它不夠純粹,更重要的是它已經堵死了從業務視角對領域模型進行演進和糾正的機會。因為沒有軟件背景的業務人員,是不可能去看一個充斥著技術概念的模型的。統一語言無法建立,領域模型帶來的價值就已經損失了一大部分。此外,從開發視角進行建模,往往還會忽視業務人員的參與。而實踐一再表明,資深的業務人員在領域建模時,往往能提出深入的洞察。所以,從開發視角對領域模型進行建模絕對不可取。
誤區2: 建立龐大的領域模型
當我們說“領域”的時候,並沒有限定一個“領域”應該有多大。究竟是“航空”作為一個領域,還是“航空”中的“訂票”是一個領域?
當你考慮到“領域的核心是認知”,這個答案就變得非常清楚了。領域越大,越不利於建立認知和共識。我們應該這問題域,把大的領域劃分為小的領域,然後逐個建立這些小的領域的領域模型。那種整整一面牆的領域模型,往往都是不可取的。
誤區3: 重文檔,輕交流和共識
領域模型的核心在於建立共同的共識,所以,如果只是把領域模型作為一種“製品”,作為某個階段的“輸出”,這是非常不合適的。領域模型需要作為交流工具。“統一語言”是避免該誤區的重要方法。
誤區4: 不把領域模型顯式化
很多人認為自己是有“認知”的,甚至是有“領域模型”的,但是,如果你問他們模型在哪裡,這些要麼就是在某個項目曾經有過一些討論,但是現在已經不知所蹤,要麼就是雖然文檔還在,但是團隊的概念表達依舊混亂。沒有顯式化,沒有把領域模型寫下來,沒有形成團隊口口相傳的知識,那麼這種模型,並不真正存在。除了“統一語言”,我們還有一個非常簡便的檢驗方法,就是看這個團隊如何給新人介紹自己的系統。因為領域模型反映了基本的業務概念,是一個非常好的新人培養工具,但凡真正有“領域模型”的組織,是不可能不把領域模型拿出來做介紹的。
總結
本文我們主要介紹了領域模型的基本概念及重要度,領域模型對於“統一語言”的價值以及領域模型應用的常見誤區。
總結一下要點:
- 領域模型的本質是概念和認知,它定義了領域內的關鍵概念以及這些概念之間的關係
- 相對於業務的多變,領域模型相對穩定,優質的領域模型可以低成本的支持業務,領域模型也是統一語言的基礎,能有效提升溝通效率
- 領域模型來自於業務滋養,領域模型生長的過程,也是業務認知建立的過程,協作建模是更有效的建模方法
在你的團隊中,有顯式的領域模型和共同的業務認知嗎?它在指導日常的交流和開發工作嗎?如果還沒有,讓我們開始吧。
課程推薦:《DDD高手進階12講》
本文內容源自阿里云云效推出的《ALPD雲架構師系列——DDD高手進階12講》。這是一門阿里內部的爆款課程,獲得數千阿里工程師口碑推薦,值得每位開發者反覆學習。
掃碼進群,群公告內免費領取阿里爆款架構師課程《DDD高手進階12講》(原價98元)
或PC端前往如下鏈接獲取課程: