EnriqueMark
設計模式與架構

複雜性與軟體設計

2026-07 繁體中文

將複雜軟體設計類比到生物上,確實極有啟發性。尤其是複雜系統的自組織原則——既然對於一個大型的生物系統來說,它可以在不需要掌握全局資訊的情況下就運作良好,那麼我們為什麼要在各種層面上去不斷的用各種全局資訊進行設計?這的確是一個不錯的角度,也是我之前很少想到的。生物系統、社會系統,實際上都是複雜系統的一個切面式的體現。大型的官僚系統其實在部分層面上

但是這裡其實忽略了一個點,也是為什麼我說是啟發而非能完全套用的地方——邊界。顯然用生物系統來類比的人忽略了邊界,那就是它的石山程度不亞於最不忍卒讀的程式碼。生物體本身不對優美、可維護性和效率負責,它只對功能負責。一個大型的複雜的湧現系統的確可以非常的抗干擾、自修復,但自組織只能表明這個系統內部存在一個讓其維持穩態的內部反饋機制,不代表他就是高效的。這套內部反饋完全可以建立在超級冗餘(不影響功能)的前提之下。比如複雜系統的路徑依賴問題,這裡面的一些搭配在軟體設計上甚至可能是不必要的,生物體幾乎無法重構,但軟體卻可以,就比如說人體內知名的繞了一圈的喉返神經——為什麼不重構?對生物來說沒必要,不影響生存的中性性狀能用就行,對軟體來說不見得。真正意義上的大型軟體可能也幾乎無法重構,成本高到不可接受,這方面反而體現出設計的重要性了。

從這個角度來看,當代的工程實踐反而不是「走向了錯誤的路」,而更像是出於工程可用或者說建築意義上的考量——我不可能真的給一堆完全無法約束的組塊然後讓他們自己跑,自己「湧現」出秩序。湧現從一開始就是難以設計甚至是不可設計的,我這裡所說的設計,指的其實也只是「系統的傾向」,我們希望它至少往這個方向走,以達到某種穩健性,從而對抗複雜所導致的問題——我們需要借鑑複雜系統的特徵,希望他湧現出的至少是秩序而非是混亂。

隨著大型軟體越來越複雜,一定會逼迫工程師去用系統的角度思考問題。路徑依賴在各個軟體系統裡面幾乎普遍存在,微軟的上古石山沒人敢動就是如此。所以,儘量對局部負責而非全局調控一定會成為優秀軟體設計中的要點。因為到了這個規模,必須考慮穩健性。換言之,我需要在這個系統裡面新增一些能讓其自我調控的反饋機制以保持運作順暢,至少不崩潰。這時候過多的全局控制會導致穩健性出問題。

而關於後期繫結這部分確實有點繞,但可以立即為反向的約定而非定義,比如

if (messageName.startsWith("addTo")) {
  const field = messageName.slice(5).toLowerCase(); // "addToBalance" -> "balance"
  return (amount: number) => {                       // ← 这里"造"出来一个函数
    (realState as any)[field] += amount;
    return `${field} 现在是 ${(realState as any)[field]}`;
  };
}

obj.addToBalance(50);   // field = "balance"
obj.addToScore(10);     // field = "score"   —— 又造一个,焊的是 "score"
obj.addToHitPoints(3);  // field = "hitpoints"

比如上面的內容,就是隻捕獲約定好的開頭,其他行為統一進「不懂」分支。這就是隻在執行時才進行判斷的。相較於提前定義好,呼叫方和被呼叫方配合進行的行為控制,後期繫結強調被呼叫方自己的行為控制,而對外部呼叫方無知。 不管你進來的是什麼,我都只按照總計內部的規則走,不知道的就轉內部不知道的流程。無論外部給入什麼,它在我這裡的行為都是我自身來調控,而不是交給外部。 這裡的思想本質上跟前兩個是一樣的,核心關鍵點就是「外部無關」。這裡仔細再想,會發現生物類比還是有一些合理性的,能夠幫助理解。因為這種外部無關最徹底的體現就是細胞。

物件導向程式設計的弊端是什麼? - 知乎