理想中,每個重要設計決策都封裝在單一類別裡。

但現實系統不可避免會有跨多個類別的設計決策。

例如:網路協定的設計同時影響發送端與接收端,而這兩端可能在不同地方實作。

跨模組決策通常複雜且微妙,是 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.

優缺點#

優點缺點
文件只有一份文件離程式碼較遠
開發者需要時容易找到程式碼演化時較難確保文件同步更新

「跨模組設計決策的文件」沒有完美解;選個方法,並建立團隊習慣去找它