1. Palmerston 勳爵的名言#

英國首相 Lord Palmerston 曾經談到 Schleswig-Holstein 問題時說:「只有三個人真正理解這個問題——已故的 Prince Consort、一位已經發瘋的德國教授,還有我自己——而我已經忘了。」

Joel 借用這個典故來說明一個類似的現象:程式設計中有些概念是真的很難,不是因為教學方法不好,也不是因為學生不夠聰明,而是因為問題本身就是複雜的

這篇文章的核心訊息並非「放棄學習困難的東西」,而是「承認有些東西確實困難」——這是一種誠實,也是邁向真正理解的第一步。

2. 程式設計中「真正困難」的概念#

Joel 列舉了一些在電腦科學教育中讓大量學生跌倒的概念。這些不是因為教材寫得差,而是因為它們需要一種特殊的抽象思維能力:

2.1 指標(Pointers)#

指標是 C/C++ 程式設計的核心概念,也是最常讓學生絆倒的地方:

  • 你需要同時思考「一個東西」和「指向那個東西的地址」——兩個層次的間接引用
  • 指標的指標(**p)更是讓人腦袋打結
  • 動態記憶體配置中的指標操作,需要在腦中維護一個記憶體布局的心智模型
  • 一旦搞錯,產生的 bug(dangling pointer、memory leak、buffer overflow)極難追蹤

2.2 遞迴(Recursion)#

遞迴要求你接受一種看似矛盾的邏輯——「用自己來定義自己」:

  • 理解遞迴需要能在腦中展開多層呼叫堆疊
  • 要同時思考 base case 和 recursive case
  • 更進階的遞迴(如樹的遍歷、動態規劃的遞迴解法)需要更深的抽象能力

2.3 其他公認困難的概念#

  • 併發與多執行緒(Concurrency):Race condition、deadlock、memory visibility——這些問題不是直覺能解決的
  • 函數式程式設計(Functional Programming):高階函數、閉包(Closure)、Monad——需要跳脫命令式思維
  • 型別系統(Type Systems):泛型(Generics)、協變與逆變(Covariance / Contravariance)、型別推斷——每一個都是一場心智體操

3. 接受複雜性,而非逃避#

Joel 的核心主張是:面對程式設計中真正困難的問題,正確的態度是接受並擁抱這種複雜性,而非尋求過度簡化的解決方案。

3.1 過度簡化的危害#

當我們試圖把真正複雜的概念簡化到「人人都能懂」時,往往會:

  • 遺漏關鍵的細節與邊界條件
  • 建立一種虛假的理解感——學生以為自己懂了,但遇到實際問題時完全束手無策
  • 培養出只能處理「教科書範例」但無法應對「現實世界問題」的工程師

3.2 Fred Brooks 的「本質複雜度」#

Joel 的觀點與 Fred Brooks 在《No Silver Bullet》中的概念呼應。Brooks 區分了兩種複雜度:

  • 偶然複雜度(Accidental Complexity):由工具、語言、框架的不完善所造成,可以透過更好的工具消除
  • 本質複雜度(Essential Complexity):問題本身固有的複雜性,無論用什麼工具都無法消除

指標、遞迴、併發等概念之所以難,不是因為 C 的語法設計不好,而是因為底層的問題本身就是複雜的。換一種語言或框架,也許可以隱藏一部分複雜性(例如用 Garbage Collection 代替手動記憶體管理),但核心的概念性困難依然存在。

沒有 silver bullet 可以消除本質複雜度。試圖用「更簡單的工具」來迴避這些概念的人,最終會在遇到真正困難的問題時付出代價。

4. 對教育與職業發展的啟示#

4.1 教育應該誠實面對難度#

  • 不要因為怕嚇跑學生就假裝一切都很簡單
  • 明確告訴學生:「這個概念很難,大多數人第一次不會完全理解,需要反覆練習」
  • 提供足夠的練習機會和漸進式的學習路徑

4.2 開發者應該主動挑戰自己#

  • 不要只停留在舒適區——如果你從來不碰指標、從來不寫併發程式、從來不深入型別系統,你的成長會有上限
  • 理解困難概念的過程本身就是一種訓練——它鍛鍊的是你的抽象思維能力,這種能力可以遷移到其他領域

4.3 區分「我不需要用」和「我不需要懂」#

  • 你可能在日常工作中不需要直接操作指標,但理解指標能讓你更好地理解記憶體模型、效能特性、甚至高階語言的行為
  • 你可能不寫函數式程式碼,但理解函數式的概念能讓你寫出更好的命令式程式碼
如何攻克困難的程式設計概念

Joel 雖然沒有提供具體的學習方法,但從文章精神可以推導出以下策略:

  • 多角度學習:同一個概念,用不同的教材、不同的程式語言去接觸。每次都會理解得更深一點
  • 動手實作:光看書不夠,必須親手寫程式碼。遞迴只有在你自己寫過並 debug 過之後才會真正「點開」
  • 接受不適感:學習困難概念時的困惑是正常的。不要因為困惑就放棄或跳過——那種「快要懂了但還差一點」的感覺,往往意味著你正處於突破的邊緣
  • 給自己時間:有些概念需要「沈澱」。今天不懂的東西,過一週再看可能就豁然開朗了

如果你發現某個程式設計概念很難理解,不要急著怪自己或怪教材。先問問:「這個東西是不是本來就很難?」如果答案是肯定的,那你需要的不是一個更好的解釋,而是更多的時間和練習。