王垠:半年來的工作感受

發表於2013-06-19

好久沒有寫部落格,一方面因為工作太忙,另一方面是因為沒有發現什麼好寫的。可是後來發現沒什麼好寫的原因其實也是因為工作太忙了。忙得不正常,所以沒有很多時間和精力來研究和欣賞自己喜歡的東西了。

我在一家叫做 Coverity 的公司工作,我住在舊金山(San Francisco)。Coverity 是一個奇怪的公司,舊金山是一個奇怪的城市。

Coverity 製造一種叫做“靜態分析”(static analysis)的軟體。這種軟體可以在不執行程式的情況下,經過對程式碼的分析,自動的找到程式裡面可能出現的問題。這有點像我之前給 Google 做的那個 Python 分析器,只不過針對另外的語言(C,C++ 和 Java 等),分析的側重點不同,能處理程式碼的規模也貌似大一些。還有就是這麼多年了,久經沙場考驗了。

Coverity 具有世界上最先進的一些技術,所以麻雀雖小,卻讓很多人離不開它。恐怕很少有人知道,這小小的公司的忠實客戶,包括了一系列的大拿:美國宇航局, 波音, 洛克希德馬丁,雷神(Raytheon),BAE Systems,豐田,歐洲原子能中心(CERN)…… 貌似幾乎所有對程式碼質量不敢有絲毫差錯,又不得不用像 C++ 這樣毛病眾多的語言的公司,都購買了 Coverity 的產品。比如最近的火星好奇者號上的所有200多萬行程式碼,都經過了 Coverity 的靜態分析。當然,如此精密的裝置不可能光靠 Coverity 查一下錯就能確保萬無一失,它必須依靠很多其它的技術,但 Coverity 確實是這些東西的開發過程裡面比較重要的部分。

我必須承認,Coverity 給了我足夠的啟發,甚至間接的讓我發現了自己之前做的 Python 靜態分析裡面存在的一些問題。Coverity 的產品在大規模的程式碼上面的成功,也讓我意識到了自己在 Python 分析器裡的一些突發奇想的設計的正確性和價值。如果我現在做一個新的 Python 分析器,它將比原來的精確和高效(也可以推廣到其它語言比如 JavaScript)。我也清楚的看到,Coverity 自發研製的一些“不大嚴謹”的做法,其實比程式語言領域裡面一些看似高深的“邏輯”還要“正確”。這些微妙的“提示資訊”,讓我把多個領域的知識串通了起來。所以我覺得跟這公司還有點臭味相投,加入 Coverity 也是不枉此行的。

然而我也發現,Coverity 缺少我擁有的程式語言理論知識。絕大部分的 Coverity 工程師沒有系統的學習過 lambda calculus 和函數語言程式設計。在我的 Python 分析器中,其實包含了 Coverity 還沒有的技術。Python 的靜態分析本來就比 C++ 和 Java 之類的難,然而我的實現卻異常的簡單。這些微妙的技術,貌似很多人都可以說他“會做”,但是他們卻很難把它做對。這就像“CPS 轉換”一樣,很多人都說他會做,可是真正做對的只有極少數人(我是其中之一)。這些技術源自於我對程式語言本質的理解,源自於 Dan Friedman, Kent Dybvig 和 Amr Sabry 等老師的教誨,也源自於我自己辛勤的實驗,實驗,再實驗…… 在我簡短而優雅的程式碼中,包含了許多人需要花費好幾倍的程式碼長度才能達到的目標。所以雖然 Coverity 的工程師們技術實力很強,但在程式碼的簡單程度和對程式語言語義的理解上,真的很難達到我的程度。

這就是為什麼我經常能夠一眼就看出 Coverity 產品裡存在的問題,並且很快的修正錯誤。舉一個簡單的例子,有一天我修改了一行程式碼,使得產品在某些 benchmark 上的記憶體使用量減少了一半。我為什麼可以做到這一點呢?因為在我的 Python 分析器裡,這個問題是從一開頭就不存在的。它源自於一種幼稚的直譯器寫法,有點像 GoF 的《Design Patterns》裡的那種。Coverity 的程式碼裡面有好些類似的問題,都是我自己根本不可能犯的錯誤,我都沒有機會給他們改進。我不是想貶低同事們的水平,他們都是 Stanford, Berkeley 等學校畢業的高手,可是我也很清楚自己的技術地位。

所以我就經常發現這樣的麻煩事:我順手改掉了一個自認為很顯然的問題,或者一個我根本不會犯的錯誤,然後就發現有大批的測試需要被修改,我也會被要求寫出“regression test”,用以防止同樣的錯誤再次發生。某些同事對於測試的戰戰兢兢的態度,其實跟我當年在 Google 實習的時候沒有什麼兩樣。看到這裡的問題了嗎?這些我“根本”不會犯的錯誤,幾分鐘時間順手就改掉了,但是我卻要花成天的工夫去修改和建立測試,防止它“再次”發生。我不得不說,在這些測試上所花費的工夫,佔用了比我修改程式碼多好幾倍,甚至幾十倍的工夫!

想想這六個月以來我幹了些什麼,再比較一下在 Google 實習的那六個月獨自從頭做出來的東西,我發現自己簡直什麼也沒有幹。這就是我不喜歡“測試驅動開發”(TDD)的原因。在 Google 的六個月裡,我無視同事對於測試的要求,從無到有的做出瞭如此精密的系統,一個測試都沒有寫照樣做得好,為什麼呢?因為我的程式碼非常的簡單清晰,我隨時都可以把它們完整的呈現在頭腦裡面,從而讓“心靈之眼”可以看到可能出現的錯誤。也許這就是所謂的“邏輯思維”。

對測試過分依賴的人,往往不具有這樣的思維能力。他們不能夠看到程式碼最簡單的本質,所以需要做很多試探,以求達到“近似解”。為了不至於偏差很多,就寫很多測試,用以捕捉和防止每一次的錯誤。這就像一個初學畫畫的人,一點一點的描,用橡皮反覆的擦,可總也抓不住事物的精髓。這些人對“錯誤”的記憶能力特別強,往往深入的追究一塊程式碼是“如何”錯的,“為什麼”是錯的,下次如何才能不犯同樣的錯誤。

然而我卻沒法記住之前的程式碼是如何錯的,我也不想知道為什麼它是錯的,我只記得“正確”的程式碼是什麼樣子。錯誤的方式有千萬種,可是正確的卻往往只有一個。把腦力浪費在記憶錯誤的東西,這就是為什麼很多人不能寫出真正優美而正確的程式碼。我受到的訓練讓我可以直接得到正確的結果,所以測試對於我來說分量沒有那麼重。當我的程式碼需要大量的測試才能確保正確的時候,那就是它該被推翻重寫的時候。所以我的程式碼往往沒有任何補丁和變通,可以說是無懈可擊。這就像是一個真正會畫畫的人,他閉目沉思,然後一氣呵成。當然,優美的程式碼並不是一蹴而就的,有的程式碼被我推翻重來幾十次才最後成功,但我最後的程式碼不留下絲毫錯誤的痕跡。所以我覺得,看一個程式設計師的水平,不要看他留下來多少行程式碼,而要看他刪掉了多少行。

我覺得做 Coverity 的工程師真累。這種累不止在於以上的技術層面的繁瑣,而且在於管理層對工程師的缺乏尊重以及不必要的壓力。這讓我在受到了足夠的“啟發”之後,開始懷疑是否還有繼續為它工作的價值。對於公司管理,以及對於 IT 行業總體的看法,我還是以後再講吧。

相關文章