Chapter 25 - 層與邊界

如果我們將系統看作是由三個元件組成的:UI、業務規則跟資料庫。假設我們要設計一個簡單的電腦遊戲,UI處理玩家到遊戲規則的所有訊息,遊戲規則則以某種資料結構儲存遊戲的狀態。讓我們以這個遊戲最簡單的形式為基底,我們將在這樣的架構上加點東西。

假設我們要保留基底文字的UI,但要將遊戲規則解耦開來,以便我們可以在不同國家的版本上使用不同的語言。如果原始碼的依賴關係被正確管理,則會如下圖顯示,任何數量的UI都可以重複使用同一套的規則。


再來,假設我們想要遊戲可以切換儲存的硬體機制,或許是儲存在RAM,或許是儲存在雲端上。我們不希望遊戲規則知道任何有關硬體儲存機制的事情,所以依賴關係必須按照依賴規則進行適當的定向,如下圖。


簡潔的架構?

顯而易見的,我們可以將「簡潔的架構」的設計應用在這個地方,但我們是否真的找到了所有重要的架構邊界呢?

例如,語系並非是UI發生變化的唯一要素,或許我今天需要將文字顯示在聊天視窗、或是遊戲的文字對話筐中。這意味著我們的架構中存在一個潛在的邊界,或許我們應該建構一個跨越邊界的API,將語系及通訊機制隔離開來,如下圖所示。


虛線框定義了API的抽象元件,如果我們先去除各種抽象元件的實作部分,單純專除在API抽象元件上去簡化圖表,我們可以得到下圖。


注意上圖的箭頭方向,所有的箭頭都使指向上方的,這個方向是相當合理的,因為GameRules是包含最高層級策略的元件。

這個設計有效的將資料流化劃分為兩個流,左邊關注於使用這資訊,右邊關注於資料的持久性。兩個留在頂端GameRules相遇,GameRules作為兩個資料流的最終處理器。

跨越流

考慮相同的例子,有可能因為需求的改變使得架構的設計並不能只是資料流。試想一下,我們可能需要跟其他玩家一同在網路上通同遊玩這款遊戲,在這種情況下,我們需要一個網路元件,如下圖所示,我們把資料流分成了三個流,並且全部都由GameRules控制。


所以,隨著需求越來越複雜,元件結構可能會分割成許多這樣的流。

分割流

事實上,當然不可能所有的狀況下所有的流都會在對頂端相遇,假設除了GameRules以外我們還存在著一組更高級的策略,一套用來判斷玩家血量的策略。

較低級的機制策略向更高級的策略宣告事件,而高級的策略將管理玩家的各種狀態。如下圖所示。


這樣就功德圓滿了嗎?如果需求繼續更動,這個遊戲變成一個大型多人線上遊戲,MoveManagement在玩家的電腦本地端進行處理,PlayerManagement由伺服器進行處理。PlayerManagement為連接過來的MoveManagement提供一個微服務的API,這種情況下PlayerManagement與MoveManagement之間存在一個完整的架構邊界,如下圖。


結論

如上述各種情況,其實因應需求的更動我們必須做出相對應的架構更動,以及更新我們原本設計的架構邊界,這些例子的目的主要是想表示,處處都存在架構的邊界

如果我們忽略邊界存在的必要性,而延後了加入邊界的時機,那將會付出比較大的代價。而我們又不應該預設各種架構邊界的抽象性,通常來說,過度的工程設計會比不足的工程設計還要來得糟糕

總結來說,我們必須反覆觀察,仔細判斷,權衡成本。讓架構邊界伴隨著產品去成長。