
在上一篇文章《不要臉的業(yè)務構件》中,談到了建筑師馮果川在一席中的演講《我今天講的所有建筑都是不要臉的建筑》,說中國的公共建筑都是龐然大物,前面有一個超尺度的廣場,是為了留出足夠的距離讓你欣賞他正面的臉面,這種要臉的建筑以大塊的空間,阻礙了和人、和自然之間的順暢交流,空間層次單一而呆板。
而馮果川他們的設計,把大塊的地塊切碎,讓人能夠走進去,設計成不要臉的建筑,把整體的單一建筑分割成可以隨意布置的多個小的建筑,不僅豐富了內外的層次和變化,而且也便于和人、和自然的交流。
在上一篇文章中,把要臉的業(yè)務構件拆分成了更小單位的不要臉的構件,不僅可以靈活提供給外部調用者,而且精細化的、標準化的構件切分,也為以后工業(yè)化、自動化生產(chǎn)業(yè)務構件打下了良好的基礎。
上篇文章的最后,提到了可能由于設計不合理,把不應該屬于該構件的對象放進了該構件中,該構件也許應該拆分為多個構件,這個問題的根本原因實際上是在模型設計時帶來的。
1.要臉的物理模型圖
曾經(jīng)見過一個系統(tǒng)的物理模型PDM,按住Ctrl+鼠標滾輪往下滾了半天,才看到了全貌,而且每滾一次,鼠標的進度條圓圈要轉幾圈圖才能出來。下面這張圖已經(jīng)縮小到最小了,據(jù)說有幾百上千張表。這張模型就像一座大山,要看清全貌,真的得后退一個上??萍拣^前面的廣場的距離才行。要找到一張表,如果不用搜索,恐怕很難找到。這樣的物理模型設計把所有的表都集中在一起,看似統(tǒng)一管理了,實質上卻很難維護,維護這種PDM的同學可真算得上是勇攀珠峰的英雄??!

2.要不要對象模型?
對很多研發(fā)來說,對象模型完全是多余的,一張PDM在手,實現(xiàn)系統(tǒng)需求分分鐘就有。
我也曾經(jīng)是這類研發(fā)人員中的“佼佼者”。拿到需求,讀上幾遍,總共需要幾張表,哪些表是怎么關聯(lián)的,一張基本完整的PDM,就已然浮現(xiàn)在腦海了。然后再根據(jù)表去設計對應的對象,加上增刪改查對應的功能,一個需求就算完成了。
甚至跟客戶、同事間的交流、培訓,全靠一張PDM圖。有的PDM的表之間連一根線都沒有,感覺交流起來確實是無法下嘴啊。
經(jīng)過一段時間的刻苦學習SID和領域建模技術,特別是做完一版產(chǎn)品管理的模型建模,尤其是輸出文檔需要對每個概念進行精確定義之后,深刻體會到了通過對象模型進行領域建模的好處,兩個對象之間的關系連線到底應該是用什么類型的線、線兩邊的數(shù)量到底是0還是1還是N,都體現(xiàn)了問題領域的需求本質,通過概念模型去和別人交流時,當時怎么設計的、為什么要這么設計、可以滿足那些業(yè)務場景,都能夠說得頭頭是道。

3.要臉的對象模型
因此,對象模型是個好東西,希望大家都能擁有。
但設計對象模型時,也會將概念模型設計成一個龐大的、要臉的對象模型圖。
上面那張龐大的物理模型,如果不采取什么優(yōu)化的設計策略的話,要畫成對應的對象模型圖,一樣也會很龐大。
又比如下面這張客戶的概念模型圖:

這張圖只描述了部分主要的對象,其他對象以及對象的子對象再往下的關系沒有在此進一步描述,如果全部描述出來的話,這張圖就很龐大了。
對象圖并不僅僅是我們了解和交流業(yè)務需求的,更重要的是應用系統(tǒng)的實現(xiàn)應該基于對象圖,否則設計和實現(xiàn)就脫離了,實現(xiàn)的系統(tǒng)必然失真,偏離了需求,最后做成了客戶不需要的系統(tǒng)。


上篇文章中說,我們需要構建不要臉的構件,不需要一個龐然大物,因此業(yè)務構件的來源——對象圖,也就需要拆分為不要臉的對象圖。
這就涉及到領域設計的問題。
4.如何設計不要臉的模型
說到領域建模,當然離不開DDD,即領域驅動設計(Domain Driven Design)的方法,?是Eric Evans在他的同名經(jīng)典著作中提出來的。
Vaughn Vernon在《Implementing Domain-Driven Design》中說,從廣義上講,領域是一個組織所做的事情以及其中所包含的一切,商業(yè)機構通常會確定一個市場,然后在這個市場中銷售產(chǎn)品和服務,每個組織都有他自己的業(yè)務范圍和做事方式,這個業(yè)務范圍以及在其中所進行的活動就是領域。
4.1領域拆分為子域
Vaughn Vernon說,由于領域模型包含了領域這個詞,我們可能會認為應該為整個系統(tǒng)創(chuàng)建一個單一的、內聚的、全功能的模型,但這并不是DDD的目標。恰恰相反,在DDD中,一個領域被分成若干子域,領域模型在限界上下文中完成開發(fā)。
SID將一個電信運營商的支撐系統(tǒng)分成了以下領域:

4.2將子域內散列的對象進行聚合
前面所講的客戶模型概念圖,看上去挺合理的,客戶擁有賬戶、訂單、合同、地址等信息,這些信息都是屬于特定客戶的,離開客戶這些都不可能存在。
但是作為CRM系統(tǒng),也就是客戶關系管理系統(tǒng),有多少對象又不屬于客戶呢?難道和客戶相關的所有對象都必須在這一張圖里面描述清楚嗎?那這張概念模型圖又將是難以維護的、要臉的、龐然大物了。
因此,我們需要把整個子域的設計圖進行拆分,拆分到更小的粒度。
將大的領域拆分為很多小的子域后,子域內包含了很多用來表達業(yè)務對象的實體或者值對象,很多對象或值對象可以聚合在一起,來完成一個業(yè)務目的,這就是聚合(Aggregate)。聚合中有一個核心業(yè)務對象,叫做聚合根。聚合根通過禁止外部對象保持對其成員的引用來保證聚合內所做更改的一致性。
下圖是SID客戶領域內的聚合,包括了客戶、客戶訂單、客戶問題、客戶交互、客戶賬單等。

4.3聚合的粒度合適嗎?
下圖是SID的客戶聚合的對象圖。

可以看到,客戶賬戶是客戶聚合的部分。
按照DDD的原則,聚合根通過禁止外部對象保持對其成員的引用來保證聚合內所做更改的一致性。
那么客戶賬戶是否具有獨立的業(yè)務能力呢?客戶賬戶信息和客戶信息是否必須保證一致性呢?客戶是否只是定位賬戶和在對賬戶進行操作時需要作為校驗規(guī)則使用的一個關鍵因素呢?這些問題的答案決定了我們是否需要把賬戶從客戶聚合中獨立出來作為一個單獨的聚合來處理。
我們分析和討論了電信運營商的業(yè)務場景,認為維護客戶賬戶信息和維護客戶信息,是可以分離的,賬戶具備很多獨立的業(yè)務能力,每次對賬戶操作時,并不需要把客戶對象裝載出來再進行賬戶的操作,因此客戶賬戶應該可以獨立成一個單獨的聚合。
你看,我們又成功地拆分了一個聚合,也即拆分了一個業(yè)務構件,把一張小臉改成了不要臉。
4.4公共領域的對象是獨立的聚合嗎?
我們在業(yè)務建模的過程中,就公共部分到底是不是獨立的業(yè)務構件,討論了很多次,爭吵了很多次,最后暫時不認為是獨立聚合的意見占了上風。
但看看SID的領域和聚合圖,公共部分顯然是九大領域中的一個,包含了很多聚合。

事實上,在實踐過程中,我們也發(fā)現(xiàn),這些公共部分如果獨立出來作為單獨的構件,會具有更高的可復用性、可維護性和可擴展性。
5.結束語
我們從一張要臉的、龐大的物理模型圖開始,引出了我們不僅需要對象模型,而且需要設計不要臉的、粒度合適的領域對象模型。
通過把領域拆分為多個子域、子域內的散列對象以聚合根為中心形成聚合、公共部分單獨抽象成聚合等多種技術手段,把領域的一張龐大的對象圖拆分為不要臉的、多領域多聚合的對象圖。
以拆分后的細粒度的對象圖為基礎,實現(xiàn)不要臉的業(yè)務構件就很容易了,有了這些被拆分的業(yè)務構件,再根據(jù)業(yè)務需求,挑選合適的業(yè)務構件,組裝成一個個滿足客戶需求的端到端業(yè)務場景,這些業(yè)務場景就組成了一個應用。
由于不要臉的業(yè)務構件的細粒度、高內聚、低耦合,因此可以靈活組裝以滿足不同應用的需求。