天天看點

Newbe.Claptrap項目周報1-還沒輪影,先用輪跑

Newbe.Claptrap項目周報1,第一周代碼寫了一點。但主要還是考慮理論可行性。

第一次接觸本架構的讀者,可以先點選此處閱讀本架構相關的基礎理論和工作原理。

周報是啥?

成功的開源作品,離不開社群貢獻者的積極參與。作為一個新啟動的輪子項目,項目聯合創始人【月落】有交代:

“我知道你代碼能力也不怎麼樣,你就把你的想法每周的交代清楚。讓他人看到項目的價值。等待越來越多的人發現項目價值所在的時候,自然就會給予更多的關注,甚至于參與的項目的開發當中。是以你要每周都寫一下周報。周報最好側重于講解項目的概念,以及通過項目如何解決實際問題。當然也可以包含一些關于項目如何設計的内容,但要注意适度,通常大家不會太注意項目怎麼實作。而更關注項目帶來的價值。記住:隻有産生了價值,項目才會成功。”

于是筆者就隻能每周寫一下周報,勉強維持生活這樣子。

輪有輪樣

新輪要有新輪的樣子,“項目開張篇”中介紹了本架構相關的基礎理論和工作原理。鑒于相關的理論内容對于剛剛接觸的讀者較為生疏,是以本節将前文最為關鍵的内容羅列如下以激發讀者的回憶。

Actor特性一:Actor的狀态是通過外部調用Actor而改變的。

Newbe.Claptrap項目周報1-還沒輪影,先用輪跑

Actor特性一補1:Actor的狀态不與外部進行共享。

Newbe.Claptrap項目周報1-還沒輪影,先用輪跑

Actor特性一補2:外部可以讀取Actor狀态。

Newbe.Claptrap項目周報1-還沒輪影,先用輪跑

Actor特性二:Actor是“單線程”工作的,每次隻能處理一個請求。

Newbe.Claptrap項目周報1-還沒輪影,先用輪跑

Actor特性二補1:并發讀取狀态可以不是“單線程”。

Newbe.Claptrap項目周報1-還沒輪影,先用輪跑

架構定義的Actor類型——Claptrap:通過事件模式,産生事件并通過事件改變自身狀态的Actor。

Newbe.Claptrap項目周報1-還沒輪影,先用輪跑

架構定義的Actor類型——Minion:與Claptrap對比,Minion不産生事件而是讀取對應Claptrap的事件來改變自身的狀态。允許存在多個Minion對應一個Claptrap。

Newbe.Claptrap項目周報1-還沒輪影,先用輪跑

通過Claptrap和Minion配合完成“轉賬”業務。

Newbe.Claptrap項目周報1-還沒輪影,先用輪跑

月落大佬名言警句1:世界上本也不存在“銀彈”。一套架構解決不了所有問題。

月落大佬名言警句2:業務複雜度是不會因為系統設計變化而減少的,它隻是從一個地方轉移到了另外的地方。

還沒輪影,先用輪跑

現在我們擁有了 Claptrap 和 Minion 的概念。接下來,結合一些業務場景,實驗一下架構能否應對各種各樣的業務需求。

再美的技術手段無法應對現實的需求與變化,那也隻能技術花瓶。——剛剛學完賽博坦XII量子計算機指令集的月落

業務場景

這是一個簡單的電商系統:

  1. 隻賣一種綠色的水晶,為了友善描述,将這個商品命名為“原諒水晶”。
  2. 使用者可以使用自己賬号中的餘額購買原諒水晶。餘額是通過外部支付系統充值進來的。充值部分,暫時不是業務場景需要考慮的。
  3. 每個使用者還有一個積分,很巧,這個積分的圖示也是綠色的,是以,将這個積分命名為“原諒積分”。
  4. 原諒積分的擷取方式有很多,例如:使用者注冊;邀請其他使用者注冊;被邀請使用者進行了消費,邀請者也可以獲得;原諒即挖礦;現實中獲得了原諒;等等其他的一些方式,這部分可能需要配合後續的活動持續增加獲得方式。
  5. 原諒積分可以在進行購買原諒水晶時,抵扣一部分需要支付的金額。
  6. 原諒積分在未來很可能有其他的用途。
  7. 購買原諒水晶的支付方式未來很可能不止餘額和原諒積分兩種。

以上就是對于這個電商系統的一部分需求描述。需求未來肯定是會變化的。

要素察覺

電商系統,最為主要的業務場景自然是和商品的交易有關的業務場景。不論其他的需求場景多麼的複雜,交易相關的業務場景必然是首當其沖需要分析解決的。

那麼首先,我們将“使用者确認購買原諒水晶”這個場景用簡單的語言描述一下程式需要執行的業務内容:

  1. 需要檢查使用者的餘額是否足夠
  2. 假如使用者選擇了積分抵扣,需要檢查使用者的積分是否足夠
  3. 需要檢查庫存是否足夠
  4. 需要扣減使用者的餘額
  5. 需要扣減庫存
  6. 假如使用者選擇了積分抵扣,需要扣減使用者的積分

如果采用直接操作資料表的方式實作以上六個要點,對于絕大部分開發者來說應該是十分簡單的。開啟一個資料庫事務,至少具備行級鎖,将資料進行檢查和更新,便可以完成這個業務。那麼現在使用本架構進行實作,根據“業務複雜度不減少”的基本事實,也同樣需要實作以上六個要點。

未蔔先知

首先,在不太讨論依據的前提下,筆者圍繞上文提到的一些主體概念,設計了以下這些Claptrap:

概念 英文命名 縮寫 代表顔色
原諒水晶 SKU S ■■■■■
原諒積分 UserPoint P ■■■■■
使用者餘額 UserBalance B ■■■■■

依轱辘畫輪

按照前篇的“轉賬”業務場景的流程設計,此處采用相同的方式設計一下購買的邏輯。如下圖所示:

Newbe.Claptrap項目周報1-還沒輪影,先用輪跑

分析一下這個設計方案:

依照業務邏輯的順序,完成了庫存檢查、庫存扣減、餘額檢查、餘額扣減、積分檢查、積分扣減的業務步驟。

注意 Client 和 Claptrap S 之間的調用線的存在時間,隻有在一開始的時候,也就是說,用戶端僅需要稍作等待,便可以得到響應。

Claptrap S 将事件推送給 Minion S 之後便可以繼續響應新的請求。確定了多個使用者進行并發購買商品即確定了商品不會超賣,也確定了響應事件足夠短。

整個業務邏輯的入口是S、這樣可以確定使用者在鎖定庫存的前提下進行支付,避免了使用者付了錢沒有辦法買到商品的情況。

基于形狀上的原因,這種設計方案被命名為 “鍊形設計(Chain-Like Design)”。

一樣的材料,不一樣的輪子

也存在另外一種設計方案。如下圖所示:

Newbe.Claptrap項目周報1-還沒輪影,先用輪跑

分析一下這個設計方案:

引入了一個新的 Claptrap W(What a amazing that I get a forgiven-crystal)作為業務的入口,這個 Claptrap W 通過調用其他的 Claptrap 實作這個業務過程。

相比與上節的設計方案,Minion S、P、B 都不再參與業務的流轉控制,因為這些業務的流轉控制已經由 Claptrap W 進行控制。

并且由于 Minion W 的存在,這個設計方案也可以将部分的調用交由 Minion 來進行,是以這個方案也可以是以下兩種形式。

Newbe.Claptrap項目周報1-還沒輪影,先用輪跑
Newbe.Claptrap項目周報1-還沒輪影,先用輪跑

基于形狀上的原因,這種設計方案被命名為 “樹形設計(Tree-Like Design)”。

那麼此處就出現了選擇,既然有出現了選擇,那麼此處就使用《月老闆的軟體開發小妙招三十二則》中記載的“WhyNot對比分析法”來決定使用哪種設計方案:

選項 為什麼不? 為什麼!不!
鍊形設計 業務流轉過程的控制通過 Minion 相連接配接,這是一種緊耦合的設計。這相當于 Minion 和 Claptrap 這次操作業務的上下文。一個明顯的問題:客戶是否選擇了積分支付,這個邏輯,要麼在 Minion B 中判斷,要麼在 Claptrap P 中判斷,但不論哪種方式其實都不合理。這樣的設計在應對流程失敗的時候,會特别難以處理。例如在最後一步客戶如果積分不足,那麼可能就需要逐漸復原,這可能會非常困難。
樹形設計 這種設計,把業務的核心流程控制内容集中的一對相關的 Claptrap W 和 Minion W 中。這是一種高内聚的表現。基于這種設計方案,很容易基于 Claptrap S、P、B 建構出更加複雜的過程。

其實讀者很容易發現,對于這個選擇的WhyNot對比分析表,其實是一邊倒的。這裡明顯就是要選擇樹形設計。

《月老闆軟體開發小妙招三十二則》,是月落大佬在日常開發過程當中對軟體開發過程用到的一些小方法的收集和歸納。這些方法大多不是新發明的内容。月落大佬隻是将這些方法收集在一起,為了啟示後來者,在分析判斷一些問題的時候,用一些小方法有時就能讓事情變得有條理一些。除了“WhyNot對比分析法”之外,還有較為知名的“5W1H需求描述法”;非常簡單的“CheckList備忘錄”;被廣泛提及的“艾森豪威爾法則”等。

WhyNot對比分析法,簡單來說就是要講選擇多個主體進行并排對比,分别列舉“應該選擇它”和“不應該選擇它”的理由,然後進行綜合判斷進而做出決定的方法。它特别适用于多人對某一選擇争執不休時采用的方法,通過表格的形式分别記錄陳述的理由,確定了不缺不漏有理有據。在方法上的基礎,還衍生出了“理由權重計量”、“人員話語權計量”等其他的一些變種。此方法與“優劣對比法”、“異同對比法”等對比法,以及“機率選擇法”、“經驗選擇法”等選擇法有一定的聯系與差別。此方法的命名據說是月落大佬首創,是一個文法梗。在中文當中,可以采用“為什麼不?”這樣的反問句來表示選擇一個對象的理由,可以用“為什麼!不!”這個的祈使句來表示不選擇一個對象的理由。 WhyNot 其實就是對“為什麼不”四個字的直譯。

好輪子外觀也好看

初見 WhyNot 對比分析法的讀者可能會有疑問:難道就沒有選擇鍊形設計的理由?

需要解釋的是, WhyNot 對比分析法是對固定場景的分析法,是以如果場景變了,分析的結果也會變。也就是說,在某些特定的場景下,鍊形設計有其必要性。

那麼在解釋之前,我們采用另外的方法來解讀鍊形設計與樹形設計:

  • 将 Claptrap 和對應的 Minion 合并
  • 用“因為…是以…”的句式來代替圖形中的實線調用
Newbe.Claptrap項目周報1-還沒輪影,先用輪跑

那麼結合上圖的鍊形設計就可以表述為:

  • 因為S,是以B
  • 因為B,是以P

展開的語義可以是:

  • 因為購買而扣除了庫存,是以進一步扣減餘額
  • 因為購買而扣減了餘額,是以要進一步扣減積分
Newbe.Claptrap項目周報1-還沒輪影,先用輪跑

上圖樹形設計就可以表述為:

  • 因為W,是以S
  • 因為W,是以B
  • 因為W,是以P

展開的語義可以是:

  • 因為購買,是以扣減了庫存
  • 因為購買,是以扣減了餘額
  • 因為購買,是以扣減了積分

即使筆者這裡解釋的不太清楚,但是讀者仍然可以觀察“因為購買而扣減了餘額,是以要進一步扣減積分”這句其實不太合理,這兩者在業務上其實不應該有明顯的前因後果。

這其實也是鍊形設計在這個場景下不能适用的原因:如果兩者的調用關系沒有明顯的前因後果,而将兩者設計為前後調用的鍊形關系。那麼很可能得到的是不合理的設計。

那麼反過來說:如果要應用鍊形設計。兩者之間必須存在合理的前因後果。

不過,在需求分析過程中,目前可能必然存在的前因後果,過後可能就已經不太合理。業務場景的多變和需求的不完全穩定,導緻了事實上,采用樹形設計能夠應對更多的問題。

讀者可以嘗試對上文業務場景中剩餘的幾點需求進行一下設計。

另外,讀者可以重新思考一下開張篇中所采用的“轉賬”場景的設計,采用樹形設計是否更為妥當。

其實就是新輪子

在開張篇中,我們将 Actor 模式與 CRUD 模式進行了簡單異同點比較。而現在還存在另外一類比較常提到的設計方案,就是“領域驅動設計”。

領域驅動設計的概念此處不多做介紹,對此内容比較陌生的讀者可以參看微軟MVP湯雪華老師的文章《領域驅動設計之領域模型》

那麼,當讀者了解了領域驅動設計之後,再結合本篇前面提到的 Claptrap W、S、P、B。或許 Claptrap S、P、B 就是聚合根?或許 Claptrap W 就是應用服務?筆者認為 Actor 模式其實是對領域驅動設計的一種進一步發揮:

  • 領域驅動設計沒有在設計模型内考慮業務并發,而 Actor 模式作為一套并發程式設計模型其實就彌補了這部分的缺失。
  • 絕大多數(筆者所知到的)領域驅動架構仍然采用了“從倉儲還原聚合根,操作完畢後儲存”的一般過程。而以 Orleans 為例的 Actor 架構會将已經激活的 Actor 在記憶體中保留一段時間,也就是說,聚合根可以在記憶體中不斷的修改,而不需要重複的從倉儲中還原。

總的來說,讀者可以沿用領域驅動設計的思路模組化,然後嘗試将原有的聚合根和應用服務設計為 Actor ,從理論上嘗試一下自己所熟悉的領域,能否采用 Actor 進行實作。或許讀者可以從中發現一些不一樣的體驗。

不過,本架構由于采用了 Actor 模式和事件溯源模式,是以設計方法與領域驅動模型相比有所繼承又不完全相同,還有一些其他需要注意的内容,會在後續整理出相應的文章。

結篇

本篇希望通過一個業務場景的設計,讓讀者了解到如何采用本架構的理論概念來實作業務。其中包含有一些作者的臆造詞,是以可能需要花費讀者更多的時間進行了解。

由于作者的工作經驗有限,缺乏豐富的行業領域知識,是以對于架構的設計理念是否符合特定行業特性的問題無法給出準确的判斷,還需要讀者多加思考。若有任何需要協助的問題,歡迎聯系本項目組。

歡迎對此感興趣的朋友關注項目,參與項目。