1. 程式人生 > 其它 >如何落地業務建模(3) 將模型作為統一語言

如何落地業務建模(3) 將模型作為統一語言

統一語言可以是模型本身嗎

前面討論過統一語言的必要性,因為業務維度在領域模型中被隱藏了,而且需要一個緩衝來發現、描述模型中不存在的概念。但這裡有一個隱藏的前提假設:最終建模結果將是原味面向物件範型的模型,因為這類模型會將業務維度隱藏。

業務是模型的隱藏維度

在極客時間專欄的例子裡,使用者可以擁有多個專欄,而這些專欄可能是自行購買、朋友贈送、抽獎獲得的,而這些都被隱藏在模型的抽象中了。
一方面,這正體現了模型抽象能力的強大,製藥廠是相似的資料關聯,業務邏輯就可以被保證,細節則可以被忽略;而另一方面,這也增加了業務方理解模型的難度。業務方很難從領域模型中感受到業務維度如流程、互動、功能、規則、價值等等。

如果有辦法可以將隱藏在領域模型中的業務維度展開,使業務方能夠理解不同的業務流程是如何作用於領域模型的,那麼業務方就能夠判斷領域模型是否準確捕捉了業務概念,以及技術方是否真正理解了需求;這時候就可以把模型本身作為統一語言了。

這種模型稱為業務友好與可讀的模型,構造這類模型的方法有很多,總體有兩個方向:

  1. 催化劑建模法及其變體(Catalysis Modeling and its variants)
  2. 事件建模法(Event-based Modeling)

催化劑建模法

催化劑建模法或催化劑方法是一種嘗試將流程視角引入物件建模的方法,它產生於DDD之前,1996年前後。
它有一個稱為共享詞彙表的核心實踐,可以看做催化劑版本的統一語言。但與DDD的區別在於,共享詞彙表只包含領域模型的名稱,其餘的業務邏輯都通過模型自身來表達。
催化劑方法更強調對模型本身的構造,而不是像知識消化那樣依賴一個試錯的過程去逼近真相。是一種重設計(Big upfront design)的方法。
然而生不逢時,發表後沒幾年就趕上了敏捷運動,於是迅速被人遺忘了;當催化劑方法在讀進入我們視野的時候,是因為我們需要尋找一種更具業務表現力、可作為統一語言的模型,於是催化劑方法又被重新拾起,作為一種將業務維度在領域模型上展開的方法,被引入到DDD中。但我們還是嫌棄他頗為厚重的建模流程,最後逐步被輕量化,產生了很多變體。

催化劑方法最大的特點在於將互動顯式地建模到物件模型中;互動(interaction)即可以代表業務流程,也可以是用例或者系統功能,通過使用關係(uses)表示在流程或功能點上使用了哪些物件模型,相當於通過角色和互動為物件模型打了標籤(tag),從而將隱藏在模型中的業務維度(流程、功能點)展開了。
使用催化劑方法重新建模極客時間的例子,結構大概是這樣:

通過模型可以看到:訂閱專欄、送朋友專欄都是通過建立Subscription物件實現的;再配合簡單的說明,就可以讓業務方理解系統的功能大致是如何被實現的,哪些模型對哪些業務流程有影響。可見展開了業務維度的領域模型完全可以勝任統一語言的功能。

角色-目標-實體法(Role-Goal-Entity)

催化劑方法將角色與互動直接建模到了領域模型中,從業務維度展開的角度講,的確有很多優點;但從技術上將,也存在難以克服的缺點:互動被直接建模到模型中,那麼要怎麼關聯模型與軟體實現呢?是選擇性地忽略互動與角色,還是將互動實現成某種特定的元件呢?
如果忽略互動與角色,業務維度又被隱藏了,領域模型也就無法擔任統一語言;而如果作為特定元件,互動嚴格意義上又不是領域邏輯。

“角色-目標-實體法”一定程度上解決了這個矛盾。這種方法不再將流程建模到模型中,而是作為發現領域概念的指代。
“角色-目標-實體法”通過一張表格來梳理系統中的角色,他們現在系統上實現的目標,以及在實現這個目標的過程中會接觸哪些領域模型中的實體。以極客時間為例,可以得到這有一張表格:

角色-目標-實體法實際上是催化劑方法的簡化版,因為沒有了互動。它還提供了一種收集需求、結構化進行領域建模與構建統一語言的流程:

  1. 首先與業務方溝通,明確參與系統的所有角色;
  2. 圍繞著這些角色,澄清他們希望通過系統達成的目標;
  3. 將目標中提及的“實體”提取出來,問清楚含義與內涵;
  4. 圍繞這些實體建立領域模型,並與業務方闡述這些模型是如何用以實現目標的。
  5. 當業務方理解了模型之後,模型就成為了統一語言。

這個流程還有一個額外的好處:可以提高業務方對領域模型的認同感。
催化劑方法和角色-目標-實體法,還存在一個缺陷:這些方法得到的是靜態模型,沒有業務流程。比如專欄可以通過”訂閱“得到,那”訂閱“的業務流程是什麼樣的模型裡面沒提到。作為改進,可以為每個互動新增流程描述。

事件建模法(Event-Based modeling)

業務建模中最難的一步並不是獲得模型,而是說服業務方接受模型並作為統一語言,雖然角色-目標-實體法是一種共創方法,但仍然需要經歷收集-建模-說服三步。有沒有一種方法,可以再討論中更自然地完成模型共創呢?
答案就是事件建模法。目前比較有代表性的有:

  • 事件風暴法(Event storming)
  • 四色建模法

事件建模法的基本原則1:通過事件表示互動

催化劑方法中,將互動直接以物件的形式引入到了領域模型中,這雖然在一定程度上展開了隱藏在領域模型中的業務維度,但是在多數情況下,結果的粒度仍嫌太粗。這也是催化劑方法只能用於簡單專案,或專案的初始階段的原因。

模型偏重於資料角度,描述了在不同業務維度下資料的變化;而業務維度中的流程、互動、功能,則更關注行為。那麼如何彌合數據與行為之間的差異呢?
事件是一種有效的方法。可以把事件看做行為的印記。比如支付,不需要直接描述支付這個行為,而是通過捕捉這個行為前後的事件:支付發起、支付完成。事件自身能表達的含義有限,但將一系列事件按照順序排列,就能還原發生過的行為。因而事件發生的時間點就是事件最重要的屬性。

在模型中畫一條時間軸,依據事件發生的時間點,按先後順序將事件標記在時間軸上,這樣一前一後成對出現的支付發起與完成,就表明存在一個成功的支付行為。
接下來可以根據事件去尋找背後的領域模型,可以按照記述文六要素去想:時間、地點、人物、起因、結果、結果。

  • 經過是行為,不需要出現在模型裡;
  • 時間是時間順序的依據
  • 地點、人物、起因、結果,則是尋找領域概念的依據

在支付例子中:

  • 地點,這個場景不重要
  • 人物,買家
  • 起因,訂單,因為需要支付的是訂單,那麼就可以把起因事件(支付發起)和訂單關聯
  • 結果,支付憑證,把它與(支付完成)關聯

於是得到下面更完整的模型:

如上,可以看到事件建模法的優點,這些優點使得事件建模法更容易與業務方完成模型共創:

  • 雖然看起來多了一個額外尋找事件的環節,但對於大多數專案而言,建立業務流程或互動流程都是必需的。那麼在梳理流程的同時發現事件,或者直接通過事件描述流程,都是惠而不費的操作。
  • 通過記述文六要素去尋找領域概念,很自然地就關聯了業務維度,提高了業務方對統一語言的接受度。
  • 事件建模對於最終得到的領域模型並沒有什麼額外的限制,它只是一種更自然地發現領域概念的方式。

事件建模法的基本原則2:通過時間線劃分不同事件

通過事件的記敘性,可以將流程性的業務維度在模型中展開,但如果事無鉅細地將互動都轉化為事件,對模型會有較大幹擾,如何找到合適的粒度呢?
事件建模法通過引入多條時間線來解決這個問題。通常的做法是區分領域事件時間線,和互動事件時間線。
領域事件指的是發生在領域中且值得注意的事件,通常意味著領域物件狀態的改變,這是它與互動事件區分的重要依據。
比如支付發起、支付完成,支付發起不會引起領域物件的變更,而支付完成則意味著會增加一個支付憑證,那麼支付完成就是領域事件。

還可以通過引入時間線來細化事件與上下文的關係,比如當設計跨多子域協同的時候,按子域分離時間線可以幫助我們更好地理解子域間的互動:

凡是可以歸類為事件建模的建模方法在底層邏輯上都是類似的:通過尋找事件,以及事件背後的領域概念,完成對領域概念的挖掘和建模。
不同方法的差異在於:

  • 如何發現事件;
  • 事件如何與模型結合。

事件風暴法

事件風暴法(Event Storming),於2012年被髮明,採用互動式建模工作坊的方式,將不同背景的專案參與方匯聚一堂,集思廣益,從而形成有效的模型。它本質上是一種頭腦風暴方法。

上圖為事件風暴的主要概念:

  • 行動者(Actor)是系統的使用者,可以是人或者別的系統。
  • 命令(Command)是由行動者發起的行為,它代表某種決定,通常是事件的起因,也稱作行動者觸發命令(AIC,Actor Initiated Command);
  • 事件(Event),就是前文討論過的事件;
  • 聚集(Aggregate),DDD中的聚合,在頭腦風暴;
  • 系統(System),指代不需要了解細節的三分系統,可以看做一個整體;
  • 閱讀模型(Read Model)用以支撐決策的資訊,通常與介面佈局有關;
  • 策略(Policy)是對於事件的響應,通常表示不屬於某些聚集的邏輯。通過策略可以觸發新的命令,稱為系統觸發命令(SIC,System Initiated Command)

事件風暴建模的整體流程為:

  1. 首先通過頭腦風暴尋找領域事件;
  2. 根據事件尋找觸發它的命令與行動者;
  3. 通過事件,尋找策略以及由策略觸發的SIC;
  4. 根據命令與事件,尋找產生變化的聚合,以及新生成的閱讀模型;
  5. 根據尋找到的聚合、閱讀模型、事件,完善、細化領域模型。

事件風暴法的建模流程遵循事件建模的大體框架,它的特點在於通過頭腦風暴發現事件,在依賴觸發與響應尋找事件間的關係,通過聚合與閱讀模型尋找領域模型。
以極客時間專欄為例,對於場景:使用者發現了想看的內容,但因為沒有訂閱專欄看不了,於是下單購買,完成支付後,再次訪問之前的內容,就可以看到了。

首先從事件入手,根據以上流程,得到關鍵領域事件有:內容請求、訪問拒絕、訂單確認、訂單支付、內容被訪問。如下圖,事件通常以“名詞+動詞被動式”表示。

然後尋找AIC與SIC,這裡的訪問拒絕、內容被訪問是SIC,其它都是AIC。
接著尋找AIC各自的觸發源、命令,命令通常以“動詞+名詞”的形式表示,策略的命名則按對應的業務邏輯命名即可,在這裡稱為訪問策略。

確定了事件的源頭,接著尋找事件發生過程中,訪問了那些聚集,事件完成後生成了哪些閱讀模型。
在Place Order - Order Placed階段,訪問了聚集Column,生成了閱讀模型Order;
在Pay Order - Order Paid階段,訪問了聚集Order,生成了閱讀模型Payment與Subscription。
閱讀模型是比聚合更為寬泛的概念,既可以是聚合,也可以是為特定介面或報表生成的特定資料資訊。這裡通常會以CQRS實現。
內容訪問策略需要使用Subscription閱讀模型,最終模型如下:

怎麼才能更有效地獲得事件流

頭腦風暴法的不足

像事件風暴法這類通過頭腦風暴獲取事件流的方法,不足在於,其成功與否取決於收斂邏輯。
頭腦風暴是一種通過發散-收斂來薈萃資訊的方法,分為兩個階段:

  • 發散階段:主持人通過引導團隊成員,收集他們的想法,產生事件;
  • 收斂階段,主持人則需要根據某種邏輯過來收集到的事件,形成領域事件;

要想更加有效地獲取領域事件,關鍵在於收斂階段。在發散階段參與者儘可以天馬行空,但在產生有效資訊的同時,也會產生大量的噪音。在收斂階段,則會按照某一邏輯主線,合併相似概念,這個過程中,卻極度依賴主持人的經驗與自覺,最終結果因人而異。

四色建模法(4 color modeling)

四色建模法由thoughtworks CTO徐昊,於2005年左右將事件建模與Peter Coad的彩色建模法結合而發展而成。
四色建模法是一種強分析方法。

四色建模法的核心邏輯:從收入流與成本結構中尋找事件

四色建模法通過三個關鍵邏輯尋找領域事件,這些邏輯源自企業運營與管理實踐:

  1. 如果有現金收入,表示承擔義務。拿錢辦事,需要收集證據,說明義務履約成功;
  2. 如果有現金支出,表示擁有權力。花錢消災,需要檢查對方是否按時履約;
  3. 對於沒有現金往來的,可以通過目標-實際對比,產生類似履約的約束。目標-實際對比,指的是設立一個目標-計劃,追蹤實際執行的結果。

這三個基本邏輯不是從技術視角臆造的,而是現實中真實運營業務的視角出發的,並且是商業規則的底層邏輯。從它們出發,可以更容易地找到與現實業務相符合的事件流。
在實際經營業務時,除了財務視角(1、2條),還有流程視角(第3條),管理理論認為,企業可以將其核心經營行為,轉化為流程(無論是對外的業務活動,還是對內的工作流),然後再通過為流程的執行設定KPI,控制企業經營的效率。支撐KPI考核與收集,也是很多軟體系統的本質目標,也是我們需要關注的領域,用目標-實現對比,作為發現、串聯事件的主邏輯。

總之,我們尋找領域模型、提取統一語言、做分層與隔離,目的都是為了有效地控制變化和傳播。那麼我們更應該從源頭入手,找到業務中相對穩定的部分去建模,而不是選擇一段變化的業務去穩定地構造它的模型。畢竟我們期待DDD能夠為我們帶來的一切優點,都依賴於儘早地從業務側隔離開穩定與易變得部分。
而業務模式,是更穩定地部分,對於一家步入正軌的企業來說,在其生命週期內劇烈變化核心業務模式是小概率事件。

業務模式主要通過收入流和成本結構來體現。四色建模法的核心邏輯就源自收入流和成本價格,通過現金權責識別與收入流有關的事件,通過目標-實際對比發現與成本結構關聯的事件。

四色建模法的具體操作流程

四種物件原型:

  • 粉色,時標物件(moment-interval),憑證、證據、原始單據等,實際上就是領域事件;
  • 黃色,角色物件(role),事件參與方在事件中扮演的角色;
  • 綠色,參與方(party-place-thing),可以是扮演角色的參與方,也可以具體的人,某件東西,或者某個場所;還可以是與憑證有關的標的物;
  • 藍色,描述(description),對於上述三個物件的描述性資訊

具體流程:

  1. 尋找關鍵現金往來,構造一個憑證表示它,然後在憑證上羅列關鍵資料項,主要有發生的時間點、金額;
  2. 針對每一項關鍵資料項,尋找它的來源,來源只能有三個:使用者輸入,由前序憑證提供,根據演算法計算。需要以此為依據去尋找前序憑證;
  3. 回到現金憑證,思考它所對應的權利與責任。這些權利與責任需要哪些憑證證明,並以此為依據,尋找後續憑證;
  4. 無論是何種憑證,必須羅列關鍵資料項,並保證資料項獲取的順暢;
  5. 如果與現金往來關聯不大,那麼尋找關鍵KPI指標,並構造一個驗收憑證表示它。其餘步驟與現金往來一致;
  6. 在獲取了相互關聯的憑證流之後(事件流),可以進入模型細化階段,圍繞每個憑證,尋找參與其中的角色;
  7. 思考哪些參與方可能扮演這些角色,並將他們加入模型中;
  8. 通過描述物件,為模型新增補充說明。

可見四色建模法對最終模型的構造有更為明確的要求:

  • 憑證必須圍繞現金往來或KPI;
  • 憑證間必須通過關鍵資料項明確關聯關係。

這也是四色建模法是一種強分析方法的體現:可經由明確的邏輯推導,不需要依賴於發散-收斂式的探索。

繼續以極客時間舉例:
在極客時間專欄的模型中的現金往來,有讀者購買專欄、專欄作者分成。
把這兩項構造為憑證,它們都有關鍵資料項:時間點、金額。

讀者購買專欄

讀者購買專欄購買憑證中的關鍵資料項:金額,不可能由讀者輸入,而應該由前序憑證提供,這個前序憑證就是訂單,支付的金額應該與訂單相等。訂單的金額也不可能由讀者輸入,它應該來自前序憑證:專欄報價;專欄報價由編輯輸入,到此為止,就形成了一條完整的追溯鏈:

除了憑證的先後順序,還記錄了模型間的計算邏輯和時標順序邏輯。時標順序是非常重要的領域邏輯。比如某專欄目前定價199元,但今天14:00會促銷變成99元。那麼讀者在13:59下單,根據約束Order.placed_at>Column.Quote.available_at,他必須支付199元,如果這位讀者不滿意,我們可以追溯資訊有理有據地告訴他原因。
所有牽扯到財務往來的業務,都必須接受得起這樣的考驗,這樣才能保障業務經營的順暢,這也是在事件發生階段就明確追溯關係的原因。

前序憑證找到了,接下來找後續憑證,即履約憑證。訂單支付後,讀者就有了閱讀專欄的權利,於是引入訂閱憑證,它的關鍵資料項為開始時間,必須晚於支付完成的時間。

專欄作者分成

專欄作者分成具有的關鍵資料項為金額,這裡金額會涉及到規定的分成比例、提取的時間段,這在專欄撰寫合同有規定,在建模圖補上專欄撰寫合同憑證:

到此為止,我們獲得了一條由關鍵資料項彼此關聯的憑證鏈,同時也是領域事件流。這條憑證連結串列示了從作者簽約、專欄定價、讀者付費、作者分成的的全程,捕捉了極客時間專欄這項業務的收入流,可以稱之為業務的脊樑。
在繼續進行下一步之前,可以先來驗證一下這個業務脊樑的有效性,看業務能夠順暢進行。首先可以將所有的憑證轉化為真實的單據;然後通過角色扮演遊戲,讓業務方模擬業務的經營。在嚴重的過程中,除了正常的流程之外,主要需要模擬的是各種業務異常引起的追溯的例子,看看業務脊樑捕捉的資料能保證我們對權責的證明。比如專欄定價修改、作者質疑分成結果等等。

這裡也能看到四色建模法的一大特點:它認為軟體系統是業務流程的加速和優化,但是模型是要用以支撐業務運營的,並不僅僅為了構造軟體而設計,因為更容易被業務方接受、成為統一語言

業務的脊樑被驗證有效後,接下來尋找與憑證相關的角色,以及能夠扮演這些角色的參與者、還有憑證相關的標的物。

最終得到的模型為:

參考資料
極客時間:如何落地業務建模 徐昊