English· Español· Deutsch· Nederlands· Français· 日本語· ქართული· 繁體中文· 简体中文· Português· Русский· العربية· हिन्दी· Italiano· 한국어· Polski· Svenska· Türkçe· Українська· Tiếng Việt· Bahasa Indonesia

un

guest
1 / ?
back to lessons

已存在的理論

每項 MOAD 缺陷在 2026 年系統性偵測之前數十年就已有已知的解決方案。這些缺陷之所以持續存在,並非因為無人知曉更好的做法,而是因為「知道」與「偵測」並不相同。

MOAD 持續惡化時間軸:五項缺陷的理論已知與偵測時間

MOAD-0001:O(N²) list.contains

Donald Knuth,1973 年。 《電腦程式設計藝術,第三卷:排序與搜尋》。雜湊表用於 O(1) 查詢已在 1973 年完整說明,並附有分析。O(N) 線性搜尋與 O(1) 雜湊查詢之間的差異——已文件化、形式化且被廣泛引用。Java 在 1.0 版(1996 年)即提供 HashSet。Python 在 2.4 版(2004 年)將 set 作為一等型別提供。此修正方案在成為各生態系統的預設慣用法之前,已存在 30 年。

Richard Hamming, 1986. Bell Labs lectures(後來出版為 The Art of Doing Science and Engineering, 1997)。Hamming 明確講授演算法複雜度、正確與效率的差異,以及建立「小規模可行、大規模失效」系統的風險。他稱之為「只針對今天看得見的問題設計,而非明天會遇到的問題」。

MOAD-0002: 共享全域狀態耦合

David Parnas, 1972. 〈On the Criteria To Be Used in Decomposing Systems into Modules〉。CACM,1972 年 12 月。Parnas 主張模組應以資訊隱藏原則進行分解——每個模組擁有自己的狀態,不允許共享可變的全域變數。這正是 Intertangle 修正的理論前身。Parnas 明確指出:全域共享狀態會產生測試無法發現的隱形耦合。

MOAD-0003: ThreadLocal 身分洩漏

Java 1.2, 1998. ThreadLocal 作為 Java 標準函式庫類別發行。當執行緒池與 ThreadLocal 同時存在時,洩漏機制即已形成。缺陷是結構性的:其生命週期綁定在執行緒,而非工作單元。Java EE 早期文件即已對此提出警告。

MOAD-0004: 記錄憑證

RFC 1945, 1996. HTTP/1.0 定義了 Authorization 標頭。自 Authorization 標頭出現之日起,憑證記錄缺陷即已存在。OWASP 於 2001 年成立,並在其第一版指南中將憑證記錄列為漏洞類別。典型模式為:Authorization 標頭 → 日誌中介軟體 → 明文憑證寫入磁碟。自第一份 HTTP 認證規格起即可預見。

MOAD-0005: 雷鳴群集 / 快取雪崩

Unix 核心,1993 年。 「雷鳴群問題」(thundering herd problem)—— N 個行程同時被同一共享事件喚醒 —— 在 1990 年代初期的 Unix 核心開發討論中已出現。Doug Schmidt 於 1994 年提出的 Reactor 模式以及 1995 年的 Half-Sync/Half-Async 模式,皆在基礎架構層級處理同步問題。快取雪崩變體(N 個執行緒在快取未命中時計算相同值)則於 2001 年被記錄於分散式系統文獻中。 [BLOCK_TYPE knowable/theory_exists]

--- [BLOCK_TYPE knowable/theory_exists]

理論:已完整。偵測工具:不存在。「可知」與「已偵測」之間的差距,依缺陷而定,介於 28 至 54 年。

可知性差距

時間軸顯示,每個 MOAD 缺陷在被系統性偵測前,至少已有 28 年的已知解決方案。最短的差距(MOAD-0003)為 28 年。最長的差距(MOAD-0002)為 54 年。

這不是關於無知的敘述。Knuth、Parnas、Hamming —— 這些都是電腦科學中最常被引用的作者。他們的著作曾被大學指定為教材。他們的詞彙(Big O、資訊隱藏、演算法複雜度)已成為標準課程。

為什麼知道這些缺陷類別,卻未能防止缺陷持續存在?請選擇一個 MOAD,並追蹤「可知解決方案」與「實際偵測」之間的具體差距。

程式碼為何持續惡化:五個條件

缺陷並非偶然持續存在。當五個結構性條件同時存在時,就會形成惡化環境。只要移除其中任何一個,偵測就變得可能。

程式碼惡化的五個條件:從理論到惡化的因果 DAG

條件 1:正確輸出

清單與集合對成員資格的回答完全相同。list.contains(x)set.contains(x) 會回傳相同的布林值。ThreadLocal 帶有過時的身份,仍帶有 一個 身份——只是它屬於錯誤的請求。已記錄的憑證被正確記錄——憑證無誤地到達日誌檔。缺陷並非功能失常。它只在成本或安全性後果上構成失常。檢查輸出的測試通過。檢查成本或安全性後果的測試:大多未撰寫。

條件 2:CI 中沒有複雜度測試

Dijkstra 曾說:「測試顯示缺陷的存在,而非其不存在。」Hamming 進一步指出:我們測試的缺陷,就是我們會找到的缺陷。2026 年的 CI 管線測試:正確性、型別安全、API 合約、功能行為。它們不測試:每次操作的演算法複雜度、每次呼叫的記憶體成長、授權標頭的清理、執行緒身份的生命週期。

沒有測試被執行。沒有測試失敗。管線顯示綠燈。缺陷不可見。

條件 3:小 N 起源

程式碼在開發環境中撰寫與審查。開發圖形有 50 個節點。開發請求負載有 10 個並行執行緒。開發快取未命中率低(暖快取、少量鍵值)。在 N=50 時,O(N²) 成本為 2,500 次運算。不可見。在 N=50,000 時,成本為 2,500,000,000 次運算。建置時間從 1 秒變成 17 分鐘。

撰寫程式碼的作者從未見過 N=50,000。核准程式碼的審查者從未見過 N=50,000。缺陷在撰寫時的規模下並未顯現。

條件 4:複製傳播時未帶上下文

正確的演算法具有啟發性。教學文件會用正確的範例來教學。文件則展示可運行的程式碼。同樣的 Tarjan SCC 骨架 — visited = [],內層 if n not in visited — 出現在 GHC、Maven、Python pip、Cargo、TypeScript 編譯器、Kotlin 編譯器、Scala 編譯器,以及 javac 中。不同的團隊、不同的語言、不同的年代。同樣的化石。原始作者的 N=50 並未隨程式碼一起傳播。傳播的是正確的輸出。留下來的是效能假設。

條件 5:規模在凍結程式碼周圍成長

程式碼不會退化。基礎設施會擴展。2003 年為 200 個套件撰寫的依賴解析器,在 2024 年運行於 50,000 個套件。沒有人重寫它——它能運作。沒有人分析它的效能——CI 顯示綠燈。讓 O(N²) 成本變得災難性的 N 值,會逐漸地、隱形地,在生產規模中出現。到那時,原始作者早已離開。程式碼成為依賴。沒有人會去碰運作正常的依賴。

診斷:五個條件

這五個條件:正確的輸出、沒有複雜度測試、源自小 N、複製時未帶上下文、規模在凍結程式碼周圍成長。

這五個條件同時出現在每一個 MOAD 中。這不是巧合——這是沉積式缺陷類別的結構特徵。

在這五個潛伏條件中,哪一個最難消除?為什麼?要從真實軟體組織的管線中移除它,需要什麼條件?

Hamming 所說的話

Richard Hamming 於 1986 年在貝爾實驗室的演講——後於 1997 年出版為 The Art of Doing Science and Engineering——其中包含的警示,讀來就像對 MOAD 缺陷模式的直接描述。他當時並非在描述 MOAD,而是描述工程系統在局部正確的決策下逐漸僵化,最終導致整體成本高昂的結構性傾向。

Hamming 論複雜度:「運算的目的在於洞察,而非數字。但你必須使用正確複雜度的演算法,否則數字永遠不會出現。一個在 N=100 時可運行的 O(N²) 演算法,在 N=1,000,000 時你退休前都跑不完。」

Hamming 論複製:「優秀的工程師不會只是複製解決方案。他們理解為什麼這個方案有效、在什麼條件下成立,以及什麼情況會讓它失效。沒有附帶條件的複製解決方案,就是一顆定時炸彈。」

Hamming 論測試:「測試你所測量的東西,並不等於測量真正重要的東西。我們為自己選擇要測試的屬性建立詳盡的測試套件,卻忽略了我們沒有選擇測試的屬性。我們忽略的那些,正是日後在生產環境中讓我們吃驚的原因。」

Hamming on scale: 'The error you make in the first year of a project is the error you are still correcting in the tenth year. Early assumptions calcify. The project scales around them. Nobody rewrites the foundation.'

警告與操作化之間的落差

Hamming 的警告是正確的。它們被教授、被引用、被納入課程。但警告並不是偵測器。Hamming 描述了缺陷的形狀,卻沒有建立能在 CI 中執行、標記 O(N²) 熱路徑、ThreadLocal 身份洩漏或憑證記錄的工具。「可知」與「可偵測」之間的落差,就是理論與其作為自動化基礎設施的操作化之間的落差。

MOAD 的存在,是因為這個領域建立了正確性基礎設施,卻未在相同層級建立效能或安全性基礎設施。單元測試:自 1970 年代以來已是標準。基於屬性的測試:自 1990 年代以來已是標準。CI 中的演算法複雜度基準:到了 2026 年仍屬實驗性質。

操作化警告

Hamming 警告過複雜度固化、未經測試的屬性、未附帶條件就複製的解決方案,以及規模壓垮早期假設。他給了我們詞彙,卻沒有給我們偵測器。

MOAD 管線填補了這個落差:掃描 → 建立工單 → 修補 → 單元測試 → 揭露 → PR → 上游合併。這就是操作化的 Hamming:不只是警告,而是自動化偵測與修復管線。

Hamming 說:「我們未測試的東西,就是在生產環境中讓我們驚訝的東西。」請舉出軟體產業系統性未測試的一項屬性,並描述自動化偵測會是什麼樣子。

The Fester Signature

MOAD 類缺陷具有可辨識的 signature。所有五個條件同時存在。這五個條件都可在撰寫任何掃描程式之前進行檢查:

1. 輸出正確嗎? 執行標準測試套件。如果通過,則該缺陷屬於效能或安全性屬性,而非正確性問題。這表示標準 CI 無法捕捉它。

2. 沒有複雜度測試? 檢查 CI 設定檔。是否有基準測試階段?是否比較演算法行為(而非僅比較執行時間)與先前提交的差異?若否:條件成立。

3. 小 N 起源? 檢查 git blame 與原始提交。首次實作時的資料集大小為何?該大小是否比目前生產負載小 100 倍以上?若是:條件成立。

4. 複製傳播? 在整個程式碼庫與生態系中搜尋此模式。相同結構模式是否出現在 N≥3 個無共同祖先的獨立程式碼庫中?若是:化石已傳播。每個複製:一個新的潰爛點。

5. 規模成長? 檢查生產指標。目前的 N 與首次部署時的 N 相比如何?成長率是否持續?在何種 N 值下,此缺陷會變得在操作上關鍵?

若五項皆已檢查並確認:你已發現 MOAD 級缺陷。修復永遠只需一行或一個方法的替換。發現才是困難的部分。修復則是簡單的部分。

這正是 Hamming 所指:工程不在於修復。修復一旦看見就很直觀。工程在於建立讓你能看見它的系統。

套用特徵

MOAD 潰爛特徵:正確輸出 + 無複雜度測試 + 小 N 起源 + 複製傳播 + 規模成長。

此特徵並不僅限於五種 MOAD 缺陷。它描述了一類缺陷,只要系統僅以正確性測試作為自動化品質閘門,這類缺陷就會持續存在。

請舉出一個不在五種 MOAD 之內的缺陷類別,並符合「fester」特徵。請指出其中符合的五項條件,以及自動化偵測器應有的樣貌。