跳轉到

1.2 軟體的複雜性與本質性困難#

為什麼軟體這麼難#

在 1.1 節我們提到,Fred Brooks 把軟體的困難分成本質性和附屬性兩類。這一節我們把這個框架講透,因為它是理解整個軟體工程——以及 AI 對軟體工程的影響——的鑰匙。

軟體開發為什麼這麼難?Brooks 在《人月神話》中給出的答案,與直覺相反:不是因為我們笨,而是因為軟體本身就有某些與生俱來、無法消除的困難。

本質性困難(Essential Complexity)#

本質性困難來自問題本身的特性,是任何方法都無法消除的。Brooks 總結了四個來源:

複雜性(Complexity)#

大型軟體系統的元素極多,而且彼此之間有錯綜複雜的非線性關聯。一片程式碼改了,會影響其他地方——這種「牽一髮而動全身」的特性,是軟體特有的。不像物理實體,軟體中沒有明顯的「規模定律」讓複雜性可以簡單壓縮。兩個模組的交互,比兩個模組本身更難理解。

一致性(Conformity)#

軟體必須與現實世界保持一致,而現實世界充滿了隨意而不一致的規則。為什麼這個日期格式是 MM/DD/YYYY 而那個是 YYYY-MM-DD?為什麼這個協議要這樣設計?很多時候沒有道理可講,軟體只能「順從」這些既有的、不合理的約定。這種一致性是強加的,無法透過更好的設計來消除。

可變性(Changeability)#

軟體被要求「不斷改變」——需求會變、環境會變、業務會變。而且軟體是所有工程實體中最容易修改的,於是所有人都期待它改。一棟橋蓋好了很少再改,一個軟體上線了往往馬上就要改。這種持續變更的壓力是軟體特有的本質困難。

不可見性(Invisibility)#

軟體是看不見的。建築有藍圖、機械有結構圖,但軟體沒有直接對應的幾何表示。我們用各種抽象(流程圖、UML、名稱空間)來試圖「看見」它,但這些都只是近似。因為看不見,就很難溝通、難以驗證、難以管理。

附屬性困難(Accidental Complexity)#

附屬性困難則來自我們用來建造軟體的工具與方法,而非問題本身。例如:

  • 一個笨拙的程式語言語法
  • 繁瑣的樣板程式碼
  • 手動記憶體管理
  • 累人的建置流程
  • 冗長的文件同步

關鍵洞察:附屬性困難是「意外」的,可以被消除或大幅降低。 資料庫取代了自製檔案管理、高階語言取代了組合語言、套件管理器取代了手動下載依賴——這些都是附屬性困難的降低。而 AI 的出現,是消除附屬性困難的革命性一步(見 1.4 節)。

為什麼這個區分很重要#

Brooks 畫出這條界線,是想指出一件令人沮喪卻又重要的真理:

沒有任何單一技術或管理革新,能在十年之內讓軟體的生產力提升一個數量級(十倍),因為大部分的工具都只能解決附屬性困難,無法消除本質性困難。

這就是著名的 「沒有銀彈」(No Silver Bullet) 論點。Brooks 在 1986 年提出這個觀點時,預言未來十年內不會有單一突破能十倍提升軟體生產力。直到今天,這個論點依然值得我們反覆思考——尤其在 AI 時代。

因為這種區分給我們一套思考工具:當我們面對一個困難時,先問自己——這是本質性的(來自問題本身,得靠更深刻的領域理解、更好的架構來面對),還是附屬性的(來自工具,可以透過換更好的工具來消除)?這個判斷,決定了努力的方向。

本質性困難無法消除,只能被管理#

既然本質性困難無法消除,軟體工程的核心工作之一,就是管理它。怎麼管理?透過:

  • 分解:把大問題切成小問題(模組化)
  • 抽象:隱藏細節,只暴露必要介面
  • 層次化:分層設計,控制依賴方向
  • 迭代:小步快跑,持續回饋(後面章節會深入)

這些方法無法讓本質性困難消失,但能讓它「可控制」——讓化為許多小的、可處理的部分。這正是架構、設計、測試等方法論存在的意義。

本章小結#

  • 軟體的困難分為本質性與附屬性兩類
  • 本質性困難的四大來源:複雜性、一致性、可變性、不可見性
  • 附屬性困難來自工具與方法,可以被消除
  • 「沒有銀彈」:沒有任何單一技術能十倍提升生產力,因為本質性困難無法消除
  • 我們能做的是管理本質性困難,透過分解、抽象、層次化、迭代

想一想#

  1. 你能舉出幾個「附屬性困難」在歷史上被消除的例子嗎?(提示:編譯器、垃圾回收、版本控制)
  2. 「軟體是可以被修改的,所以所有人都期待它改。」這句話說明了哪一種本質困難?
  3. 為什麼「軟體看不見」會造成溝通與管理的困難?