轉載: http://www.goldendoc.org/2012/07/somethings_i_ve_learnt_about_programming/
原文位址:Some things I’ve learnt about programming —- By John Graham-Cumming
我已經從事程式設計 30 年了,用過的機器包括從現在看來很差的(基于 Z80 和 6502)到最新的,用過的語言包括 BASIC,彙編語言,C,C++,Tcl,Perl,Lisp,ML,occam,arc,Ruby,Go等等。
下面是我學到的一些關于程式設計的事兒:
0. 程式設計是一門手藝而不是科學或工程
程式設計更接近于一門手藝而不是科學或工程。它是技能和經驗的組合,它需要通過工具來表達出來。一個手藝人會選擇特定的工具(有時候他們會自己去做)然後學習用它去創造。
在我看來這就是手藝。我認為最好的工程師更加接近于鐘表匠而不是橋梁建築師或者是實體學家。當然因為對邏輯和數學的應用,程式設計看起來像是科學或工程,但是本質上它就是你拿你手上的工具去做東西。
既然程式設計是一門手藝,那麼我們就不難了解為什麼在程式設計中經驗,工具,直覺很重要。
1. 誠實是最好的方針
程式設計的時候我們經常為了看看發生了什麼或者讓一個程式跑起來去試試一些代碼,但是卻并不真正地了解到底發生了什麼。比如:你決定要調用一個 API,僅僅因為它神奇地讓 Bug 消失了;再比如,在程式中插入一行
printf
,因為它讓程式不再崩潰。
這些都是對自己不誠實的例子。你必須問自己:“我是否知道我的程式到底做了什麼事情?為什麼做這個事情?”。如果你不知道,你遲早會陷入麻煩。明白一個程式做了什麼是程式員的責任,計算機隻會精确地做它被告訴去做的事情,而不是你想要它做的事情。
誠實需要你對自己非常嚴格。你必須非常嚴格地确定你已經知道你的程式幹什麼,為什麼這麼幹。
2. 簡化,簡化,再簡化
Tony Hoare 說過:
有兩種方式建構軟體設計:一種把軟體做得非常簡單以至于明顯沒有缺陷,另一種是把它做得非常複雜以至于找不到明顯的缺陷。第一種方法要難得多。
簡化,重構,删除。
我把 Hoare 的話改了一下:“在每一個大型複雜的程式裡面,都是一些小而優雅的程式在把同樣的事情做對。”
和這個相關的是“小塊松散組合”哲學。通過一些互相通信的部分去建構一個程式,而不是建構一個單獨的大程式。這也是 UNIX 如此成功的部分原因。
3. 不要依賴調試器,但是性能分析器不一樣
我幾乎從來不用調試器。我的程式會列印日志,我知道我的程式到底幹了什麼。大部分時候我可以從日志中看出發生了什麼而不用借助調試器。
我不用調試器的原因是因為我認為它會導緻你懶于思考。當遇到一個 Bug 的時候,很多人都會去設定斷點,然後檢查記憶體或者變量的值。我們很容易被這樣迷人的工具所吸引,因為思考看起來會花費更多的時間。如果你的程式非常複雜,你必須需要一個調試器,那麼你或許應該回去看看第二點。
(題外話:盡管說了這麼多,但是一個我非常尊重的程式員,John Ousterhout,似乎會把整天的時間都花在 Windows 調試器上)。
另一方面,如果你需要了解你的程式的性能,那麼性能分析器是非常重要。你不會被一個性能分析器所吸引。
4. 代碼重複會讓你很受傷
不要重複你自己。你的代碼中的每一件事情應該隻做一次。
這是第二點的一個特例。甚至是一點小小的代碼重複都會在将來給你帶來麻煩。
5. 對語言要随便一點
有些人對一門特定的語言很着迷,所有的東西都用它去做。這是一個錯誤。沒有一門語言是适合所有的程式設計任務的。
關鍵是你要明白當你遇到問題的時候你要從你的工具箱裡面拿什麼語言去處理。工具箱中的工具當然是越多越好。試試不同的語言,試着用它做些東西。
如果你用下 Python 或者 ML,你會覺得 List Comprehension 很強大;或者你可以嘗試下 Go,看看它是如何處理并發的;或者你可以用用 Perl,看看它處理字元串是多麼地靈活;或者你可以用 PHP 去快速搭建一個動态網頁。
我讨厭語言戰争。失敗者才會參與語言戰争,因為這個争吵的東西本身就是個錯誤。比如說,在我的手上,PHP 就是個悲劇,但是在别人會用得很爽。對于 C++ 也是一樣的道理。
6. 發展一個軟體要比建構一個容易
這也和第二點有關。從一個小的部分出發,然後慢慢發展起來。如果你正在解決一個問題,那麼從你要解決的問題的一個部分開始發展要比在問題的基礎上設計一個龐大的架構容易。
當你從一開始就建立了一個龐大的架構,你就錯了,你做了一個拜占庭式的複雜而死闆的迷宮,你會發現自己很難去改變它。反過來,如果你從一些互相協作的小的部分出發,那麼當你意識到從一開始你就把一個問題搞錯了以後,重構起來将會非常容易。
這個的根本是你無法知道一個正确的架構到底長什麼樣子。這是因為你很難知道你的程式的外部輸入會是什麼樣子。你也許認為你知道,比如,你的郵件伺服器所需要處理的 TCP 流,或者是收件人的個數是多少,或者是垃圾郵件長什麼樣子。有些外部的資料會讓你的假設失效。如果你的假設已經融合在一個大的,複雜的,難以改變的程式裡,那麼你真是麻煩大了。
7. 學習計算機的每一個層次
我覺得對從 CPU 到你所用的語言有一個認識是非常重要的。了解計算機的每一個層次非常重要。
當你需要處理性能問題的時候這就非常有用。我想起一個事兒,這個事情我依然記得很清楚,一個客戶給我們公司發了一個 Window 2000 的崩潰截圖,圖上有一些記憶體和寄存器的資訊。當我們知道他所用的程式的版本後,我們就找到了是一個空指針的問題導緻了這個現象。
8. 我還不夠年輕至足以知道一切
我依然有很多的東西要去學。有一些語言我想要接觸還沒有怎麼接觸過(Erlang,Clojure);有些語言我有所涉獵但是并不精通(JavaScript);有一些知識點我根本就不懂(monads)。
PS:我還沒有提到過測試。我應該加上這一點,因為我确實認為對任何不是馬上就扔掉的代碼,測試用例都是非常重要的。也許再寫 30 年的代碼我就可以對“單元測試提升了軟體品質嗎?”這個問題有了一個答案。我寫代碼有時候寫單元測試,有時候不寫,我不知道這個問題的答案,盡管我更傾向于寫單元測試。