工程哲學:Donald Knuth,程式設計是一門藝術

重點摘要
- 程式設計是一門藝術,不只是工程。 Knuth刻意把畢生之作命名為《The Art of Computer Programming》,以一套任何測試套件都無法衡量的美感標準來要求程式碼。
- 程式碼是寫給人閱讀的文學。 第一位讀者是下一個讀這支程式的人,編譯器只是第二位。可讀性是頭等的工程要求,而非一種客套。
- 只在真正重要之處投注嚴謹;其餘之處則投注克制。 證明演算法、精確分析其成本、把工藝雕琢到最後一個字符——同時拒絕把心力傾注在那97%無關緊要的程式碼上。
- 「過早最佳化」的意思是先量測。 這句名言是一種量測紀律,而非為慢程式碼開脫的藉口:透過剖析找出那關鍵的幾個百分點,只攻打那些地方,其餘則保持可讀。
核心原則
「與其想像我們的主要任務是指示電腦做什麼,不如把心力集中在向人類解釋我們想要電腦做什麼。」——Donald Knuth1
一句話便概括了整個立場。對Knuth而言,程式並非首先是一串指向機器的指令;它是一篇寫給人看的文章——寫給下一位讀者,而那通常就是半年後、早已把一切忘光的你自己。編譯器是次要的讀者。第一位讀者是人,程式對這位讀者而言要嘛是文學,要嘛就是失敗,無論它執行得多麼正確。
這正是Knuth把畢生之作命名為《The Art of Computer Programming》、而非《The Science》或《The Engineering》的緣由。他說的藝術是字面意義上的:一門為了成品本身的品質而追求的工藝,以一套任何測試套件都衡量不了的美感標準來要求。隨之而來的紀律以一種非常特定的方式嚴苛。它說:去做那少數真正重要的事,並把它們做到分毫不差。證明你的演算法正確。精確分析其成本,而非用猜的。把版面排好,讓它能毫無滯礙地被閱讀。而且——人人引用、卻幾乎人人誤讀的那部分——不要把工藝耗在那97%無關緊要的程式碼上,因為傾注於錯誤之處的心力不是工藝,而是裝扮成勤勉的浪費。
於是這個原則有兩張看似對立、實則合一的面孔。在重要之處處處嚴謹;在不重要之處處處克制。本領就在於分辨何者為何——而Knuth對於你如何分辨的答案,正是貫穿整個系列的同一個答案:你量測。那句關於過早最佳化的名言,並不是寫慢程式碼的許可證。它要求你先憑證據找出那關鍵的幾個百分點,然後才動手——這與效能是你內建並量測出來的屬性,而非最後再補上的一道關卡是同一份信念。
背景脈絡
Donald Ervin Knuth於1938年1月10日生於威斯康辛州的密爾瓦基。2他在凱斯理工學院取得學士與碩士學位——凱斯印象深刻到在1960年將碩士學位與學士學位同時頒給他——並於1963年在加州理工學院取得數學博士學位。2他於1969年加入史丹佛教職,1977年成為Fletcher Jones電腦科學講座教授,並在1990年取得一個他基本上是為自己發明的頭銜:The Art of Computer Programming教授。2他擔任史丹佛榮譽教授已有多年,至今仍以手寫與通信的方式,持續投入這項佔據他六十餘年的同一個專案。
這項專案始於一場規模上的意外。1962年,Addison-Wesley委託年輕的Knuth寫一本關於編譯器的書。3他動筆後得出一個結論:若不先奠定底下的基礎理論——排序、搜尋、資料結構、演算法實際耗時的分析——他便無法誠實地說明如何打造一個編譯器。原本的一本書於是成了一套規劃中的系列。第一卷《Fundamental Algorithms》於1968年問世。這套計畫最終擴展為七卷,而這項工作至今尚未完成。3《American Scientist》後來將它列為形塑了一個世紀科學的約莫百本書之一,《紐約時報》則稱它為「這個行業的奠基性論著」。3依合理的共識而言,它是電腦科學最接近聖經的存在。
1974年,Knuth獲頒ACM A.M.圖靈獎——計算領域的最高榮譽——「以表彰其在演算法分析與程式語言設計上的多項重大貢獻,尤其是透過他那一系列著名著作對『程式設計藝術』所做的最重要貢獻」。4他的圖靈講座一如其人地命名為「Computer Programming as an Art」。4

主要成就
《The Art of Computer Programming》與演算法分析
Knuth被稱為演算法分析之父,而這個稱號是他實至名歸的。2在TAOCP之前,程式設計師大多以非正式的方式推敲演算法——這個感覺比較快,那個似乎比較浪費。Knuth的專案,是要把那種推敲建立在嚴謹的數學基礎之上:精確推導出一個演算法執行多少次運算、作為輸入的函數,並以數學家證明定理時所帶的同等精度去做。他推廣了如今每位程式設計師都用來描述成本如何隨規模變化的漸進「大O」記號。2重點從來不在記號;而在於那份信念:一支程式的成本是一個你應該計算出來的可知量,而非一種你應該擁有的感覺。
這幾卷書以一種近乎執著的完整性聞名——每個論斷都經過證明、每個演算法都經過分析、每個邊界情況都被處理——也以Knuth為任何被找到的錯誤所提供的獎金支票聞名。支票面額是2.56美元,他稱之為「一枚十六進位美元」,因為256美分在十六進位裡就是100。5金額是個玩笑;支撐它的紀律卻不是。Knuth拿出真金白銀押注他的著作是正確的,並邀請全世界來證明他錯了。TAOCP歷經數十年依舊精雕細琢、權威不墜的狀態,有一部分正是這份長期賭注的產物。5(他在2008年因銀行詐騙而停止寄出實體支票,如今改開立一張對著虛構的「Bank of San Serriffe」的證書——嚴謹存續了下來;紙本軌跡則換了地方。)5
過早最佳化與關鍵的3%
軟體工程中被引用最多的一句話出自Knuth,而它幾乎總是被引錯——被剝去了賦予它意義的那個子句。以下是完整的段落,出自他1974年發表於《ACM Computing Surveys》的論文〈Structured Programming with go to Statements〉:
「程式設計師浪費了大量時間去思考、或擔憂程式中非關鍵部分的速度,而當把除錯與維護納入考量時,這些對效率的嘗試其實帶來了強烈的負面影響。我們應該忘掉那些小小的效率,大約97%的時候都該如此:過早最佳化是萬惡之源。然而,我們不應放過那關鍵3%裡的機會。」6
完整讀來,它並不是一個反對效能的論點。它是一個支持量測的論點。Knuth的重點是經驗性的:一支程式幾乎把所有時間都花在它一小部分的程式碼裡,而去最佳化另外那97%——那些幾乎不執行的部分——要付出實實在在的心力,換來的卻幾近於零,還讓程式碼更難閱讀、更難信任。「萬惡」的不是最佳化。萬惡的是在你還不知道時間花在哪裡之前就去最佳化——把工藝耗在信念而非證據上。他所開出的紀律與懶惰恰恰相反:透過剖析找出那關鍵的3%,然後狠狠地攻打它。
關於出處,要說一句,因為對任何誠實引用這句話的人來說這很重要。這句話出現在Knuth 1974年的論文裡,是他自己的文字。但十五年後Knuth本人卻把它稱作「Hoare的格言」,歸給Tony Hoare——而當Hoare被直接問到時,他也撇清了關係,暗示它或許是Dijkstra的,並認為最好把它當成「共有的文化或民間傳說」來看待。7因此最乾淨而準確的說法是這樣的:我們大家引用的那個措辭是Knuth的,由Knuth在1974年發表;而那個想法,他則大方地拒絕將其據為己有。那份拒絕本身就很符合他的性格。一個付錢請你找出他錯誤的人,並不熱中於去攬下他不確定自己應得的功勞。
TeX、METAFONT,以及作為工藝的數位排版
1976年,Knuth收到了第2卷第二版的校樣,大為震驚。曾讓第一版如此精美的熱金屬排版,正被早期的照相排版取代,而結果很醜——尤其是數學部分看起來都不對勁。3換作另一個人,大概會把這當成進步的代價而接受。Knuth無法忍受自己的書被排得這麼糟,於是在1977年決定花一點時間打造一個更好的東西。這「一點時間」最後變成了將近十年。成果就是排版系統TeX,以及用來設計字體本身的姊妹系統METAFONT;兩者都在1986年完成並以書籍形式出版。3
他生涯中沒有哪一段岔路比這更能說明問題。一位數學家為了從第一原理出發、解決把美麗的字符放上一頁的問題,中斷了他的鉅著八年——因為在他心中,版面的外觀與作品的品質是無法切割的。歷經四十年,TeX至今仍是全世界數學排版的標準。它是最清楚不過的一份聲明:對Knuth而言,成品一路延伸到最後一個字符的最後一個像素:工藝不止步於程式碼。這是工程師版的把圍籬的背面也做好——讀者從未刻意留意的那部分,正是他拒絕草率對待的部分。

文學化程式設計
如果一支程式注定是要讓人閱讀的,那麼我們撰寫它的方式——依編譯器的順序、把註解當成事後才補上的東西——就是顛倒的。1984年,在《The Computer Journal》的一篇論文裡,Knuth提議把它反過來。他把這套做法稱為文學化程式設計,並打造了一個叫WEB的系統來實踐。1
在文學化程式設計裡,你依人類思考的順序寫成一份單一的文件——以散文解釋你的意圖,並在解釋需要之處,以最適合閱讀的任意順序把程式碼片段交織其中。接著有兩個工具來處理它:tangle依編譯器所需的順序抽取程式碼,weave則產出供人閱讀、經過排版的格式化文件。8WEB結合了Pascal與TeX;後來與Silvio Levy合作的CWEB,則為C語言做了同樣的事。8Knuth自己的描述是:「一支程式最好被想成一張網……程式設計師的任務,是以最有利於人類理解的任意順序,陳述出那些部分與那些關係。」8
文學化程式設計從未成為主流實踐,這一點值得誠實面對。但支撐它的那份信念——解釋並不是關於程式的文件,解釋本身就是程式;可讀性是頭等的工程要求,而非一種客套——卻已悄然勝出。這正是讓我們珍視那些自我解釋的程式碼的同一份直覺,也是Knuth對於程式設計所為何來這個問題所給出的最深刻答案。
方法
這套方法跨越六十年、橫貫四個領域——演算法、排版、語言設計,以及書寫本身——始終如一。
先為人類讀者而寫。 機器是第二位讀者。一支程式,就像一則證明或一個段落,是以下一個人能否跟得上來評判的。文學化程式設計就是這份信念化為的工具。18
先證明它,再測試它。 「當心上面這段程式碼裡的臭蟲;我只證明了它正確,還沒實際試過。」Knuth在1977年的一份備忘錄裡這樣寫道——這句話之所以好笑,正因為他是那種真的會去證明自己程式碼的稀有人物。9這個玩笑裡藏著紀律:正確性是論證出來的,不是假定的,而證明是必要、卻仍不充分的。兩者你都欠著。
分析成本;別用猜的。 一個演算法的執行時間,是一個要靠數學推導出來的量,不是一種預感。這是演算法分析的奠基之舉,也是「大O」掛在每位程式設計師嘴上的緣由。2
動手最佳化前先量測。 過早最佳化之所以是萬惡之源,因為它把工藝耗在信念上。憑證據找出那關鍵的3%;只在那裡最佳化;其餘保持可讀。6
讓工藝貫徹到最後一個字符。 為打造TeX而把畢生之作擱下八年,是這套方法最純粹的展現:成品的品質,不會在程式碼結束的地方停下。它止於頁面的邊緣。3
守護深度專注。 Knuth在1990年1月1日放棄了電子郵件——「從那以後我一直是個快樂的人,」他寫道——其推理是:電子郵件適合那些工作就是要掌握全局的人,而他的工作則是去待在事物的底層,把一個主題鑽研得夠深,才能把它解釋得好。10拒絕被打斷不是怪癖;那是工作的前提。
影響鏈
形塑他的人
數學傳統,尤其是組合數學與數論。 Knuth是以數學家的身分走進程式設計的,而他把數學家那不容妥協的標準——一個論斷在被證明之前還算不上知識——帶進了一個一直靠直覺勉強應付的領域。(奠基性影響)
Addison-Wesley在1962年的委託。 那場定下了軌跡的意外。受託寫一本關於編譯器的書,Knuth卻順著問題一路追到它的根基,再也沒回頭;演算法分析之所以以其現代形貌存在,正因為他拒絕去寫那本人家請他寫的、容易的書。(直接影響)
熱金屬排版與印刷書籍。 他對一個排版頁面該長什麼樣子的標準,是由更早一個印刷年代的工藝所塑成的——這正是為什麼1976年那些照相排版的校樣令人無法忍受、而TeX變得勢在必行。(奠基性影響)
他形塑的人
每一位在職的程式設計師。 大O分析、對演算法的嚴謹研究,以及TAOCP本身,都是基本素養。整整一代人,不論他們有沒有翻開過他的書,都從Knuth那裡學到了一個演算法要付出什麼代價。
全世界的數學與科學出版。 TeX與LaTeX,是過去四十年來幾乎每一篇數學論文、物理預印本與技術書籍排版的底層基礎。Knuth那八年的岔路,變成了基礎設施。
正確性與可讀性的文化。 文學化程式設計、獎金支票、「證明了它正確,還沒試過」——這些定下了一種基調。認真的程式碼應當既可被證明正確、又讀來令人愉悅,這份期待有一部分正是Knuth的遺贈。
貫穿主線
Knuth與Edsger Dijkstra是本系列中兩位偉大的正確性使徒,而兩人之間那富有成效的張力,正是其中最具啟發性的東西。兩人都以手寫作,都不信任機器作為真理的仲裁者,都堅持一支程式應當被推敲,而不只是被執行。但Dijkstra主張測試只能顯示臭蟲的存在、永遠無法顯示其不存在——並重重倒向以證明作為唯一真正的根基——而Knuth那句「我只證明了它正確,還沒試過」卻向證明本身的極限眨了眨眼:他既證明又測試,而當兩者都失手時,他付錢給你。嚴謹之中的務實。John Carmack則從另一端坐落在同一條軸線上——剖析熱點、把機器理解到根基、攻打關鍵迴圈——這恰恰就是Knuth的「關鍵3%」,只是瞄準的是硬體的天花板而非證明。而Thompson與Ritchie的Unix,當中C語言之所以被打造出來,是為了讓一個作業系統能被閱讀與移植、而非被手工焊死在一台機器上,正是Knuth所明言的同一份信念:程式是寫給人的。(系列橋接)
我從中汲取了什麼
我留住的這一課是:我這個領域裡被引用最多的一句話,是一種披著格言外衣的量測紀律。「過早最佳化是萬惡之源」被拿來為又慢又懶的程式碼開脫,而那恰恰是Knuth本意的精確反面。他真正要求的,比「全部都最佳化」或「全都不最佳化」都更難:先剖析,憑證據定位出那關鍵的3%,把你的工藝傾注到恰恰是那裡,其餘則保持可讀。這與品質是唯一的變數是同一套標準——問題從來不是「這夠快了嗎?」或「這夠聰明了嗎?」,而是「對於成本實際落在何處,我有證據嗎?」這是證據關卡套用在效能上:對熱點的一個預感,在你量測它之前,還算不上知識。
在我如今打造東西的世界裡——代理、工具迴圈、模型呼叫——Knuth的兩張面孔都是承重結構。那份克制:別去最佳化一個你還沒量測過的提示或檢索路徑;幾乎所有的延遲都活在少數幾次呼叫裡,其餘的是你該保持可讀的雜訊。那份嚴謹:在重要之處,證明它、測試它,並押上某樣東西賭你是對的。而那份文學化程式設計的信念,是我在五十歲時覺得最切題的一個——當一個系統產生程式碼的速度快過任何人能閱讀的速度時,先為人類讀者而寫就不再是一種貼心,而成了讓系統得以被檢視的唯一憑藉。那份信念——品味是一套你量測並捍衛的技術系統,而非一種你信口宣稱的氛圍——從1962年的一紙寫書委託,一路直貫到2026年的一個代理框架。
常見問題
Donald Knuth的工程哲學是什麼?
Knuth把程式設計視為一門藝術,其第一位讀者是人、而非機器:「向人類解釋我們想要電腦做什麼。」1隨之而來的紀律,將嚴苛的嚴謹與刻意的克制配成一對——證明演算法正確、用數學分析其成本、把工藝一路雕琢到排版好的頁面,同時拒絕把心力耗在最佳化程式中無關緊要的部分上。他靠量測來分辨何者為何,而這正是他那句關於過早最佳化的名言的真正含義。6
「過早最佳化是萬惡之源」實際上是什麼意思?
它是一個對量測的要求,而非對效能的否定。1974年的完整引文是:「我們應該忘掉那些小小的效率,大約97%的時候都該如此:過早最佳化是萬惡之源。然而,我們不應放過那關鍵3%裡的機會。」6Knuth的重點是,一支程式幾乎把所有時間都花在它一小部分的程式碼裡;最佳化另外那97%既浪費心力又損害可讀性。這套紀律是:先剖析,找出那關鍵的幾個百分點,只最佳化那些地方。用這句話來為慢程式碼開脫,是把它的意思整個顛倒了。
「過早最佳化」這句引言是Knuth發明的,還是Hoare?
人人引用的那個措辭是Knuth的,發表於他自己1974年的《Computing Surveys》論文〈Structured Programming with go to Statements〉。6然而十五年後,Knuth本人卻把它稱作「Hoare的格言」並歸給Tony Hoare;當Hoare被直接問到時,他也撇清了著作權,暗示它或許可追溯到Dijkstra,並說最好把它當成「共有的文化或民間傳說」來看待。7誠實的總結是:我們所引用的這句話是Knuth的,但他大方地不願將這個想法據為己有。
Donald Knuth創造了什麼?
Knuth撰寫了《The Art of Computer Programming》(始於1962年,第一卷於1968年出版,持續進行中——電腦科學的奠基性論著),並開創了現代的演算法分析,推廣了大O記號。23因不滿自己書籍的拙劣排版,他創造了TeX排版系統與METAFONT字體系統,兩者皆於1986年出版,至今仍是數學出版的標準。3他還開創了文學化程式設計與WEB系統,亦即把程式撰寫成供人閱讀的這套做法。18他獲頒1974年的ACM圖靈獎。4
來源
-
Donald E. Knuth, “Literate Programming,” The Computer Journal 27 (1984). “Instead of imagining that our main task is to instruct a computer what to do, let us concentrate rather on explaining to human beings what we want a computer to do.” See also “Literate programming,” Wikipedia. ↩↩↩↩↩
-
“Donald Knuth,” Wikipedia. Born January 10, 1938, Milwaukee, Wisconsin; Case Institute of Technology (BS/MS 1960); Caltech PhD in mathematics (1963); Stanford faculty (1969 per Wikipedia – some biographical sources give 1968, the year Fundamental Algorithms was published, hence the common conflation), Fletcher Jones Professor of Computer Science (1977), Professor of The Art of Computer Programming (1990), now emeritus; “father of the analysis of algorithms”; popularized asymptotic (big-O) notation. ↩↩↩↩↩↩↩
-
“The Art of Computer Programming,” Wikipedia. Addison-Wesley commissioned a compilers book in 1962; the project expanded to a planned seven volumes; Volume 1 published 1968 and the work remains ongoing; named by American Scientist among the books that shaped a century of science and called by the New York Times “the profession’s defining treatise”; the 1976 phototypesetting frustration led Knuth to begin TeX in 1977 and return eight years later; TeX and METAFONT published as books in 1986; the $2.56 “one hexadecimal dollar” reward checks. ↩↩↩↩↩↩↩↩
-
“Donald E. Knuth – A.M. Turing Award Laureate,” ACM (the official page blocks automated requests; see the bot-accessible primary-source mirror below). The verbatim 1974 citation, as read at the ceremony and reprinted with the lecture: “The 1974 A.M. Turing Award is presented to Professor Donald E. Knuth of Stanford University for a number of major contributions to the analysis of algorithms and the design of programming languages, and in particular for his most significant contributions to the ‘art of computer programming’ through his series of well-known books.” Turing lecture: Donald E. Knuth, “Computer Programming as an Art,” Communications of the ACM 17, no. 12 (December 1974): 667–673 (full text, which also reprints the award citation). ↩↩↩
-
“The Art of Computer Programming,” Wikipedia, and “Knuth reward check,” Wikipedia. The reward check worth “one hexadecimal dollar” (256 cents = $2.56) for each error found; literal checks discontinued in 2008 after bank fraud, replaced by certificates drawn on the imaginary “Bank of San Serriffe.” ↩↩↩
-
Donald E. Knuth, “Structured Programming with go to Statements,” ACM Computing Surveys 6, no. 4 (December 1974): 261–301. “Programmers waste enormous amounts of time thinking about, or worrying about, the speed of noncritical parts of their programs… We should forget about small efficiencies, say about 97% of the time: premature optimization is the root of all evil. Yet we should not pass up our opportunities in that critical 3%.” Paper citation also at “Structured programming,” Wikipedia. ↩↩↩↩↩
-
On the attribution: Knuth referred to the line as “Hoare’s dictum” roughly fifteen years after his 1974 paper, and when asked directly Tony Hoare disclaimed it, suggesting Dijkstra and “common culture or folklore.” See discussion and Hoare’s reply documented at “Programming Myths and Folklore: The Origin of ‘Premature optimization is the root of all evil’,” and the attribution note at “Donald Knuth,” Wikiquote. ↩↩
-
“Literate programming,” Wikipedia. Knuth’s 1984 Computer Journal paper; the WEB system (Pascal + TeX) and later CWEB (with Silvio Levy, for C); tangle extracts compilable code and weave produces typeset documentation; “a program is best thought of as a web… the programmer’s task is to state those parts and those relationships, in whatever order is best for human comprehension.” ↩↩↩↩↩
-
Donald E. Knuth, “Notes on the van Emde Boas construction of priority deques: An instructive use of recursion” (memo, 1977), as documented at “Donald Knuth,” Wikiquote. “Beware of bugs in the above code; I have only proved it correct, not tried it.” ↩
-
Donald E. Knuth, “Knuth versus Email,” Stanford homepage. “I have been a happy man ever since January 1, 1990, when I no longer had an email address.” Email suits people whose role is to be on top of things; Knuth’s role is to be on the bottom of things, studying a subject deeply before explaining it. ↩