領域驅動設計之實踐與反思

jdon007發表於2013-03-30
領域驅動設計之實踐與反思

一、引言

前兩三年,在這裡我先後寫過三個帖子,分別闡述了對三個問題的思考。
1)什麼是程式?結論是:程式=資料結構+演算法+設計模式。
2)什麼是領域模型?結論是:人對領域的認知,即其心智模型。
3) 如何描述領域模型?結果是提出一套建模原語:模型、結構特徵、行為特徵和場景。

這些帖子都曾引起了一些爭論或批評,之後我也在不斷實踐和反省,今天我決定把最近一兩年實踐的經驗,加以總結,在此歡迎各位的討論和質疑。

二、正文

[img index=1]
首先,對上面這個圖進行解釋。
1、業務模型 = 業務物件 + 業務規則。
2、業務場景:在業務場景中,業務物件在業務規則的約束或指導下,呈現依賴於場景的行為特徵和結構特徵。
2.1)行為特徵:比如監聽請求事件、反序列化操作、請求引數校驗、丟擲異常等等,主要描述業務物件在特定的業務場景下的行為。
2.2)結構特徵,比如獲取事件處理結果、序列化操作、響應資料格式、業務物件狀態顯化等等,主要是描述業務物件在特定的業務場景下的結構。
3、介面層:介面層向上為業務場景提供服務,向下使用資料庫提供的服務。領域模型透過介面層與外界互動。
4、REST API: 如果說介面層是業務模型與Web服務內部其它部分的交界處;那麼REST API則是Web服務與外界的交界處,REST API描述如何開放Web服務給Web應用。REST API呼叫,使得應用端進行“表述性狀態的轉移”,服務端進行“業務場景的切換”。

接著,描述這個圖的用法,這也是我目前使用的設計與實現的方式。
1)從面向應用或使用者代理的API開始(粗粒度的REST API,HATEOAS);
2)接著是場景設計,包括結構特徵和行為特徵,一個REST API可以表示一個或多個類似的場景;
3) 根據場景,設計業務物件和業務規則(關注點:如何保證其在場景過程的可用性)
4)根據場景,設計資料表結構(關注點:如何場保證對場景結果的永續性)
5)介面層的設計,last but not least, 考慮在業務場景、業務模型(業務物件和業務規則)、業務資料(表結構)之間,如何有效地將資訊流(資料流和控制流)進行傳遞或轉移。

注:步驟3和4,設計的先後的順序沒有關係,事實上兩者可靈活交替設計都無妨。因為兩者的關注點是有差別的,但又相互補充。業務資料的設計追求永續性和無冗餘性,而業務模型的設計著眼於可用性和直觀性。

三、反思

1、關於ORM
如何將表的關聯(one-to-one, one-to-many, many-to-one, many-to-many)對映到物件上,如何將物件的繼承對映到表(single table、joined、table per class),這種費腦子的事情且不說。ORM的效能也是大大的問題,比如當我們只要記錄的某幾個屬性的資料,且不需要級聯的資料,ORM卻不分青紅皂白,把所有資料都返回給我們。
JPA是ORM的集大成者,巔峰之作,也並沒有從根本解決上物件和關係的天然阻抗。當我看到業務物件填滿了各式各樣的annotation,總覺得該是哪裡出錯了。
ORM真的是對程式設計師智力的極大浪費。不管正向設計(從物件到表),還是逆向設計(從表到物件),都是錯誤的方向,這條路不適合再走下去了。
事實上,在資料的訪問上,我們需要的,僅僅是一個小小的庫, 幫助我們完成連線的管理和結果集資料的自動提取而已。
在我的設計中,介面層可以直接讀寫取資料庫,如果業務場景需要的話,也可以使用非同步的方式進行讀寫。

2、關於MVC和DCI正規化
在經典J2EE三層架構,MVC一般在表現層應用,jsp為檢視,servlet為控制器,java bean為模型。jsp是in-out的servlet,是服務端的指令碼,把資料的展示,客戶端該乾的活都幹了,真是越俎代庖呀。Ajax的出現,這一問題得以緩解, 服務端只要給客戶端資料即可。jsp等服務端的渲染技術,該進博物館,退出歷史舞臺了。
MVC在Web架構中為什麼會被這樣誤用呢? 事實上,MVC在桌面軟體或客戶端應用的構建上非常非常好用。我猜測,J2EE架構的最初設計者,並沒有認真考核其是否適合構建Web服務。
那麼DCI適合構建Web服務嗎?恐怕也不太適合,其適用於指導業務場景的設計與實現,而Web服務的整體架構,還是REST風格比較合適。

3、Web服務不是Database應用
在jdon上可能存在這樣一個誤區,老是想把資料庫給遮蔽了。ORM這條路已經行不通了,現在開始換另一條路NoSQL。可是諸君可見?所謂的NoSQL, 卻追求著SQL-style query interface。從使用上說,API style是給我們最直接的感受,至於底層是使用key-value方式還是relation的方式實現,對我們的影響到底有多大呢?
事實上,一味地追求遮蔽資料庫,極有可能走向另一個極端:我們所構建的Web服務不過是一個Database的應用。
我想說的是,不要像ORM那樣試圖去遮蔽資料庫,記住Web服務的真正使命: 為Web應用提供服務,其它東西任何都要在其之下;與其浪費精力去遮蔽資料庫,不如將其視為構建Web服務的一部分,發揮其最擅長的能力;而將更多地精力花在如何給Web應用提供更友好的API的設計上。

相關文章