理想中,每個重要設計決策都封裝在單一類別裡。
但現實系統不可避免會有跨多個類別的設計決策。
例如:網路協定的設計同時影響發送端與接收端,而這兩端可能在不同地方實作。
跨模組決策通常複雜且微妙,是 bug 的高發地帶——好文件至關重要。
最大的挑戰#
找一個「開發者自然會發現」的位置放這份跨模組文件。
解法 1:放在自然的中央位置#
例如:RAMCloud 系統定義了一個 Status 列舉,每個請求回傳它表示成功 / 失敗。
新增一個 Status 值需要修改多個檔案:
- 一個檔案把
Status對應到例外 - 一個檔案提供每個
Status的人類可讀訊息 - ……
幸運的是,新增 status 值的開發者一定會打開 enum 宣告——所以把所有需要連動修改的地方寫在那裡:
typedef enum Status {
STATUS_OK = 0,
STATUS_UNKNOWN_TABLET = 1,
...
STATUS_INVALID_PARAMETER = 30,
STATUS_MAX_VALUE = 30,
// Note: if you add a new status value you must make the following
// additional updates:
// (1) Modify STATUS_MAX_VALUE to have a value equal to the
// largest defined status value, and make sure its definition
// is the last one in the list. STATUS_MAX_VALUE is used
// primarily for testing.
// (2) Add new entries in the tables "messages" and "symbols"
// in Status.cc.
// (3) Add a new exception class to ClientException.h
// (4) Add a new "case" to ClientException::throwException to map
// from the status value to a status-specific ClientException
// subclass.
// (5) In the Java bindings, add a static class for the exception
// to ClientException.java
// (6) Add a case for the status of the exception to throw the
// exception in ClientException.java
// (7) Add the exception to the Status enum in Status.java, making
// sure the status is in the correct position corresponding to
// its status code.
} Status;新值會被加在現有列表結尾 → 註解放在結尾最容易被看到。
解法 2:沒有自然中央位置時 → designNotes 檔案#
很多時候找不到自然的中央位置。例如 RAMCloud 處理 zombie 伺服器的程式碼牽涉多個互相依賴的模組——沒有一處特別適合放總體說明。
兩個有問題的選項:
- 在每個地方都重複文件 → 笨拙、難隨系統演化保持同步
- 放在某一個地方 → 開發者不知道去哪找
作者試驗中的做法#
中央 designNotes 檔,按主題分節,例如:
...
Zombies
-------
A zombie is a server that is considered dead by the rest of the
cluster; any data stored on the server has been recovered and will
be managed by other servers. However, if a zombie is not actually
dead (e.g., it was just disconnected from the other servers for a
while) two forms of inconsistency can arise:
* A zombie server must not serve read requests once replacement
servers have taken over; otherwise it may return stale data that
does not reflect writes accepted by the replacement servers.
* The zombie server must not accept write requests once replacement
servers have begun replaying its log during recovery; ...
RAMCloud uses two techniques to neutralize zombies. First,
...然後在所有相關程式碼處放短註解:
// See "Zombies" in designNotes.
優缺點#
| 優點 | 缺點 |
|---|---|
| 文件只有一份 | 文件離程式碼較遠 |
| 開發者需要時容易找到 | 程式碼演化時較難確保文件同步更新 |
「跨模組設計決策的文件」沒有完美解;選個方法,並建立團隊習慣去找它。