本系列的第一篇博文拋磚引玉,大談領域驅動設計的優點,這裏筆者仍是但願以客觀的態度,談談領域驅動設計的缺點及其不適合使用的場景,以讓讀者能夠有選擇性的使用領域驅動設計。程序員
咱們知道,沒有最好,只有最合適,設計也是同樣。所以,所謂設計,就是以你和你的團隊的知識、經驗和智慧,全面充分的考慮各類內外因素後,在大家的設計方案中做出合理的選擇的過程。而這些影響大家選擇的因素主要有:canvas
-
技術框架的特徵和約束(若是你的項目決定使用C語言進行開發,那麼首先在設計方法上,就須要使用面向過程而非面向對象的設計方法)。
-
時間的壓力和約束(你永遠不可能告訴你的老闆,給我10年時間,我和個人團隊將爲你設計出世界上最優秀的軟件)。
-
你的團隊的能力、經驗、性格、價值觀等因素的約束(你不能指望一個長期從事遺留系統維護項目或大部分紅員是缺少經驗的高校畢業生的團隊能很好的按照你的設計意圖去實現你的高度抽象的優秀設計,同時你也別期望一幫家裏經濟條件不錯,本着過來熬時間的傢伙會樂意與你一塊兒刻苦鑽研、精益求精)。
-
你的系統的特徵(若是你想把一個足夠簡單並且在能夠預計的未來都不存在很大規模的需求變動的系統設計得很複雜,很精妙,具備很好的擴展性,但要爲此付出巨大的時間、人力成本,這顯然是一種不理智的過分設計(Over design))。
-
其餘外在因素的約束(你的項目須要參與投標,你必須壓縮人力、時間等以讓你的項目成本成爲巨大的競爭資本)。
固然,上述的考慮因素站在比較高的角度,一般是項目經理、架構師須要考慮的問題,但這當中你應該會獲得一些啓發。回到咱們的主題,咱們首先看看,領域驅動設計相對於傳統的面向過程式的設計,有什麼缺點:架構
- 複雜化:面向過程思惟之因此一直很受歡迎,是由於它很直觀,很是符合大部分人的思惟習慣,大部分人拿到一個問題,一般都是會很直觀的想第一步作什麼、第二步作什麼,若是怎樣,應該怎樣,不然怎樣……,能夠說,任何水平的程序員,都能很好的使用面向過程的方法進行設計和開發。同時,因爲咱們教育水平的落後和總體IT環境的制約,能夠這樣說,真正掌握面向對象思惟和設計方法的程序員的比例很是低(雖然絕大部分都使用面向對象的語言和工具),而自己面向對象思惟要求人有很好的抽象思惟能力,由於你須要把一個複雜的系統一層層的抽象爲簡單的部分,須要把現實世界的事物(有些是可見的,但有些是不可見)合理的抽象爲計算機世界的不一樣元素。這些都不是一些很容易作的事情,要作得好,就更難。
- 團隊的抗拒:若是你的團隊(很大可能)大部分人都習慣於用很直觀的面向過程的方式進行設計和開發,你須要推進你的團隊轉換思惟來採用面向對象的方式進行領域驅動設計,一般會遭到多數人的抗拒。由於人都是有惰性的,他們習慣安於現狀,而改變是痛苦的,他們要付出額外的努力,須要進行學習,但以筆者的經驗,至關一部分程序員,特別是有必定工做年限的程序員,他們從事IT工做都只是爲了得到一份不錯的報酬,所以他們的學習動力很是有限,並且,他們都至關自負,被說服的難度比較大。
- 管理、開發和維護的成本高:複雜度更高,意味着你須要花更多的時間進行設計,同時須要花出額外的時間進行必要的培訓,並且須要有更完善的文檔(設計文檔,API文檔,培訓文檔等)。領域驅動設計的抽象程度比較高,所以必需有良好的文檔,不然,隨着項目的不斷迭代、升級和維護,它很容易由於後來者的誤解而慢慢迴歸面向過程的設計,甚至會變得「四不象」,領域驅動設計的成本優點是隨着時間的推移慢慢體現的(見下圖),若是出現這種狀況,全部前面付出的努力都會付諸東流。

系統的初始階段,領域驅動設計須要付出更大的成本,但隨着時間的推移,領域驅動設計的成本效益優點會逐步顯現
框架
-
性能比較低:使用純面向對象的方式進行領域驅動設計的程序,其系統開銷一般要比面向過程設計的程序高,從而性能相對較低(關於具體的例子,後續的博文會說起)。
那麼,假設咱們在時間、團隊能力及各類資源都容許的狀況下,是否就能夠麻木的全盤使用領域驅動設計呢?正如本博文的標題同樣,答案是否認的,咱們須要有選擇性的使用。讓咱們來看看一些指導性原則:工具
- 使用領域驅動設計,並不表明整個系統的方方面面都必須聽從領域驅動設計的原則,須要根據實際狀況,讓適合的部分使用領域驅動設計,讓不適合的部分使用面向過程的設計。
- 對於那些業務規則很是簡單,一般只有增、刪、改、查的簡單操做,並且也不大可能發生大規模需求變動的模塊,可讓業務實體成爲一個「貧血模型」,例如一些基礎數據:系統參數、商品類型、國家、地址信息(注:對於這點,本人持保留態度,由於這些業務雖然很是簡單,但既然選擇了領取驅動設計,即便把這些業務實體設計爲「充血模型」,即把極其簡單的業務邏輯也封裝在業務實體中,也並不比使用「貧血模型」成本高,而它卻帶來了統一設計風格的好處)。
- 對於查詢操做,特別是複雜的查詢操做,出於性能的考慮,能夠用結構化查詢邏輯一次性完成,並把這些邏輯封裝在Repository(即技術上的DAO)中(這方面的具體例子,後面關於「查詢通道」和「領域對象倉庫」的博文會更具體的闡述)。咱們能夠看到,對於一些業務視圖,以及報表模塊,很明顯不適合使用面向對象的方式設計,由於這些「視圖」和「報表」,本質上就不是業務實體。
- 一樣出於性能的考慮,在業務實體的實現邏輯中,某些操做不適合過分偏執的使用面向對象方式。例如,在「訂單」的「新增訂單明細」(order.addOrderItem(orderItem))中,若是業務邏輯規定一張訂單中包含優惠商品的明細數目不能超過20條,使用面向對象的方式,就須要把訂單中的全部訂單明細所有加載,而後逐個明細判斷其對應的商品是否優惠商品,再統計出優惠商品的數目,這樣很明顯是低效率和高開銷的,這裏只須要使用Repository提供的一個統計方法,用一個結構化查詢邏輯返回統計結果便可,而這就是非面向對象的方式。
本博文給有志於領域驅動設計的讀者潑了一下冷水,提出一些「反模式」(Bitter),是爲了讓讀者冷靜一下,在領域驅動設計過程當中做出更靈活和更合理的選擇。關於這方面的論述,筆者在這裏淺嘗則止,限於水平、經驗和表達能力,不敢胡亂賣弄,建議讀者能夠參考閱讀Martin Fowler的《Patterns of Enterprise Application Architecture》一書的相關觀點。性能