---
# System prepended metadata

title: Chapter 25 層與邊界 LAYERS AND BOUNDARIES

---

# Chapter 25 層與邊界 LAYERS AND BOUNDARIES

我們可以將系統看作是 UI、業務邏輯、Database 這三個 components 所組成的，這對簡單的系統是足夠的，但是對於大多數的系統來說，components 的數量是多過三個的。

例如一個簡單的遊戲可以很容易想出三元件： UI component 處理 player message 並送給 遊戲規則 component，而 遊戲規則 component 會利用某種持久的資料結構儲存遊戲的狀態

## Hunt the Wumpus

還沒玩過的可以先玩一下遊戲
* [Super_Wumpus_Land](https://catseye.tc/installation/Super_Wumpus_Land)
* [Wumpus Adventure](http://christianjhughes.github.io/WumpusAdventure/)

> Hunt the Wumpus 是一個 1972 年開發的古早遊戲(但是 wiki 寫 1973)，這是一款 Text-Based 的遊戲，玩家可以輸入簡單的命名例如 GO EAST 或是 SHOOT WEST，而電腦會回應角色看到、聽到、聞到、體驗到的東西，遊戲的目的就是避開陷阱等危險並在洞穴中找到 Wumpus

> Hunt the Wumpus
> by Gregory H. Coresun
> Debuted: April 1973
> Language: BASIC
> Platform: PDP-8

![](https://i.imgur.com/GDEKYWX.png)



### 25.1 任何數量的UI元件都可以重複使用遊戲規則
![](https://i.imgur.com/2Rugpry.png)

假設我們現在保留 Text-Based 的 UI，並希望和遊戲規則 decouple ，才能讓我們可以有多國語的版本。也就是說遊戲規則和 UI 是用與語言無關的 API 溝通，UI 會把 API 轉換為人類語系。



### 25.2 遵循依賴原則
![](https://i.imgur.com/4J3zRAd.png)

另外我們也假設遊戲狀態可能會保存在 Flash memory 或是雲端上，也不希望遊戲規則知道這些細節，因此我們也會建立一個 API 讓我們可以使用該 API 與儲存 component 進行通訊。

## 簡潔的架構 Clean Architecture
UI 的變化不一定是在語言上，我們可能還會需要改變通訊的機制，例如透過 Console 或是以簡訊、聊天軟體，甚至還有很多其他變化的可能性。
因此我們必需建立新的 API 來隔離語言和通訊機制，建構跨越邊界的 API。


### 25.3 修改過後的圖

![](https://i.imgur.com/a1fUyzc.png)
上圖雖然有點複雜，但是應該不會感覺意外，虛線外框的 component 定義 API，並由實線外框的 component 實作。例如 Language API 就有 Englisth 和 Spanish 兩個實作。

API 是由使用者定義，並不是由實作者來定義。例如 GameRules 想要與 Language 溝通時，會使用 GameRules 定義的 API，但是由 Language 來實作

將不同的實作給去除，只關注在 API 的部份，可以得到下圖：

### 25.4 簡化圖
![](https://i.imgur.com/EgjCqyX.png)
GameRules 是最高層級策略的元件，因此被放到最高處

我們來看資料流的方向，注意圖上的箭頭方向是原始碼的依賴方向，並非資料流的方向。使用者的輸入會先經過 Text Delivery 與 Language 元件，並轉換為 Game Rules 的命令，最終被送往 Data Storage。Data Storage 的資料也會被 Game Rules 送往 Language 轉為人類語言後送到 Text Delivery

這個架構將資料流分成了左右兩個 Stream，左邊專注在與使用者的通訊，右邊則是資料的儲存
## 跨越流 Crossing the Streams


### 25.5 增加一個網路元件
![](https://i.imgur.com/Ad8HWAU.png)

當然我們可能會需要不只兩個 Stream，假設現在是多人連線的遊戲，可能就會增加 Network components 並一樣由 Game Rules 控制。

## 分割流 splitting the Streams

### 25.6 更高層級的 策略是用來管理玩家
![](https://i.imgur.com/7RH6DOj.png)

現實當中很有可能不一定所有資料流都匯集到單一頂點，這邊我們將 Game Rules 分為玩家移動的策略和玩家血量、事件的策略，Move Management 是比較低層級的元件，會向更高級元件 (Player Management) 回報事件，而 Player Management 就會決定遊戲的輸贏

### 25.7 加入一個微服務 API
![](https://i.imgur.com/i3TNt5u.png)
那麼 Move / Player Management 之前是否有 Boundary 呢？

作者這時想要做成大型遊戲多人版本，因此將 Player Management 放到伺服器上運行，而 Move Management 留在 Clietn 端
這時就形成 Player Management 提供 API 給所有 Client 端的 Move Management 使用，而他們之前就有了一個明顯的 Boundary 了

## 總結
本章節透過簡單的例子發展出複雜的架構，目的是為了讓我們理解 Boundary 處處存在，我們必需辨別何時需要有邊界，也要意識到全部實作的代價是很高的，但忽視該有的邊界，日後要再加入也要付出很大的代價。

那麼我們到底該怎麼做呢？

過猶不及的設計都是不好的，身為架構師必須看到未來，權衡成本，聰明的選擇邊界所在的位置

![](https://i.imgur.com/qgCLS5D.png)
> You Aren't Gonna Need It - YAGNI
> Always implement things when you actually need them, never when you just foresee that you may need them.

當然這個決定不是一次性的，在專案發展的初期不能草率的做決定，要觀查專案的發展，在實作的成本與忽略的成本黃金交叉時下手實作

需要神之眼 (watchful eye)