Reactive設計語言與正規化

banq發表於2014-06-02

這是來自Scala語言的TypeSafe公司的Dean Wampler在五月上旬React 2014大會上的演講,演講從物件導向正規化 DDD領域驅動設計到函式程式設計正規化。最後試圖論證Akka是DDD最好的實現,雖然我個人對該觀點有保留觀點,但是想將大意翻譯一下分享其一些精彩觀點。原文PDF點選標題。

Dean主要是以Reactive四個原則為衡量標準,對目前各種技術實現進行比較,這四個原則是:

1.Event-Driven事件驅動,非同步非堵塞
2.Scalable可伸縮擴充套件,松耦合,可組合的,分散式的,網路問題是一等公民。
3.Responsive響應式,必須能有響應,哪怕錯誤。
4.Resilient彈性,失敗恢復是一等公民。

且不論這四個原則是否完全合理,如果一味以這四個標準來衡量一切恐怕有所偏頗,比如從我個人角度瞭解到,Node.js領域的人們對於Scalable的理解就不一樣,Node.js認為程式碼配置一點都不需要修改就能伸縮擴充套件才是真的Scalable,這點Java和Akka都不一定做到,Akka中有remote和local之分,JVM在記憶體增加時至少要修改XMX等引數。Akka將網路問題暴露給程式設計師處理,這本身好像有積極擁抱網路錯誤的態度,但是也造成抽象洩漏,迫使程式設計師對程式碼進行個別定製化,程式通用性也差得多。

好了,廢話不多說,讓我們繼續聽聽Dean的演講。

首先,第一個被衡量的正規化是一種狀態和行為混淆繫結在一起的傳統富模型做法,這是與函式風格將狀態值和行為函式分離完全相反,說白了,Dean提倡貧血模型,狀態和行為捆綁是一種富模型做法。這個正規化在四個標準對比如下:
Event-driven: 好處是事件能產生正常的物件(應該是指事件值物件),但是事件處理邏輯會混淆物件的邊界。
Scalability: 壞的,不好,因為很多沒有必要的領域模型產生過度工程,這使得程式難以劃分為微服務,限制了可擴充套件性,對於高吞吐量系統,將每條記錄初始化為物件是昂貴的。
Responsive: 任何程式碼膨脹和邏輯分散實現都會導致一些隱藏的效能BUG。
Resilient:難於具體化錯誤處理。

這種富模型的問題是,比如有一個Customer客戶物件,客戶在各種場景用例下有各種行為狀態,如果都塞在同一個Customer物件中,那麼無疑使得Customer模型膨脹。(banq注:我個人提倡以DCI或DDD上下文來分解分離)

下面,Dean提出一個重要觀點:

OOP物件導向程式設計最大的錯誤是用OO方式去實現領域模型

我想註解一下,這裡有一個隱含概念,Dean肯定OO分析設計,使用物件導向分析設計是OK,但是你不能用同樣的方式去實現設計,編制程式碼。條條大路通羅馬,OOP只是一條路而已,FP也許才是更便捷的那條路。

Dean認為i使用OOP實現領域模型,會導致大量ad-hoc類,基本包裝的是基礎型別變數或集合,每個用例故事會被切割到大量瑣碎的小物件中,不能集中在一起便於閱讀分析。難於重用。

OOP物件導向程式設計強調可變狀態優先,這與函式程式設計強調不變性優先不同,在大多數OOP庫包中,會將狀態可變重要性超過效能,實現效率低的複製,狀態變化當然可以很快,但是別忘記鎖的存在,必須儘可能使用無鎖的資料結構。

沒有紀律約束的可變狀態使得BUG難於發現,程式碼彈性降低,複用難度增加。

Dean的觀點不是要消滅觀點,而是讓狀態變化得到約束,比如封裝在特定模組中如專門的資料庫,如果想在記憶體中實現狀態可變,那麼也必須有紀律,封裝需要狀態變化的地方,讓其他更多地方是邏輯上不可變的。

Dean引用Alan Kay對 OOP觀點:
OOP僅僅意味著訊息,本地狀態保留和保護,隱藏狀態的處理過程。

Dean認為iKay的這種OOP觀點更接近Reactive.

下面Dean開始談到DDD領域驅動設計了:
DDD是以一種物件導向方式建模,尋找領域中概念模型,領域中事件是第一公民,雖然DDD鼓勵以OO方式實現模型,但是這不一定是必須的,也可以使用FP實現DDD.

DDD中倡導狀態和行為封裝(比如使用聚合根守衛狀態),反對貧血模型,但是Dean認為貧血模型應該是首選的。

Dean然後從FP觀點對DDD中概念進行了點評:

1. 實體Entity: 有狀態,由其唯一標識和生存時間決定。
2.值物件: 封裝不變的狀態
3.聚合Aggregate: 將物件群有邊界的劃分在一起,由根實體控制變化。
4.領域事件: 感興趣的事件,可以作為物件。
5.服務: 一系列不屬於任何物件的操作。
6.倉儲Repository: 資料儲存的抽象
7.工廠: 例項構建的抽象

DEAN認為領域事件 服務和工廠是好的,倉儲是避免ORM,Dean也呼籲不要使用ORM,不要抽象資料儲存,積極面對它和它的細節, 因為你需要利用這些細節獲得最大的效能,ORM破壞效能,限制資料儲存的有效應用。

對於聚合Dean提倡使用集合Collection,不要再建立一個個ad-hoc瑣碎的聚合物件,使用不可變的集合,因為集合支援強有力的流操作如(filter, map, fold, groupby, etc.),你就不必自己再做一套了。

至於實體和值物件就作為不變性的例外,因為它們代表可變的狀態,所有的物件預設應該是不變的,可變是一種例外特殊情況。

關於DDD提倡的統一語言,Dean認為這聽上去很好,但是容易導致臃腫不靈活的程式碼,開發者更關心的是程式碼中領域模型,所以提倡一種“實現語言”可能更合適。

因為DDD是針對設計誕生的,關於實現使用了更多抽象概念,也就是沒有明確如何實現,DDD以一種非OOP方式實現也許更好。Reactive方式很合適DDD實現。

DDD是鼓勵大家去理解業務領域,而不是指定如何實現那些業務領域模型。

Dean在接下來的函式程式設計中對比了幾種函式程式設計在四個標準上的差別,分別是有界的佇列 回撥Callback Rx觀察者和Actor模型。

函式程式設計讓我們用數學方式去思考,計算機需要我們教會它怎麼做,因此我們需要從數學角度告訴它怎麼做。

函式程式設計有組合函式 不可變值以及狀態和行為分離(貧血模型)。

具體詳細可點按標題檢視原文。

[該貼被admin於2014-06-02 11:56修改過]

相關文章