優秀程式設計師眼中的整潔程式碼

jianshu發表於2015-06-16

  有多少程式設計師,就有多少定義。所以我只詢問了一些非常知名且經驗豐富的程式設計師。

  Bjarne Stroustrup,C++語言發明者,C++ Programming Language(中譯版《C++程式設計語言》)一書作者。

  我喜歡優雅和高效的程式碼。程式碼邏輯應當直截了當,叫缺陷難以隱藏;儘量減少依賴關係,使之便於維護;依據某種分層戰略完善錯誤處理程式碼;效能調至最優,省得引誘別人做沒規矩的優化,搞出一堆混亂來。整潔的程式碼只做好一件事。

  Bjarne用了“優雅”一詞。說得好!我MacBook上的詞典提供瞭如下定義:外表或舉止上令人愉悅的優美和雅觀;令人愉悅的精緻和簡單。注意對“愉悅”一詞的強調。Bjarne顯然認為整潔的程式碼讀起來令人愉悅。讀這種程式碼,就像見到手工精美的音樂盒或者設計精良的汽車一般,讓你會心一笑。

  Bjarne也提到效率——而且兩次提及。這話出自C++發明者之口,或許並不出奇;不過我認為並非是在單純追求速度。被浪費掉的運算週期並不雅觀,並不令人愉悅。留意Bjarne怎麼描述那種不雅觀的結果。他用了“引誘”這個詞。誠哉斯言。糟糕的程式碼引發混亂!別人修改糟糕的程式碼時,往往會越改越爛。

  務實的Dave Thomas和Andy Hunt從另一角度闡述了這種情況。他們提到破窗理論4。窗戶破損了的建築讓人覺得似乎無人照管。於是別人也再不關心。他們放任窗戶繼續破損。最終自己也參加破壞活動,在外牆上塗鴉,任垃圾堆積。一扇破損的窗戶開闢了大廈走向傾頹的道路。

  Bjarne也提到完善錯誤處理程式碼。往深處說就是在細節上花心思。敷衍了事的錯誤處理程式碼只是程式設計師忽視細節的一種表現。此外還有記憶體洩漏,還有競態條件程式碼。還有前後不一致的命名方式。結果就是凸現出整潔程式碼對細節的重視。

  Bjarne以“整潔的程式碼只做好一件事”結束論斷。毋庸置疑,軟體設計的許多原則最終都會歸結為這句警語。有那麼多人發表過類似的言論。糟糕的程式碼想做太多事,它意圖混亂、目的含混。整潔的程式碼力求集中。每個函式、每個類和每個模組都全神貫注於一事,完全不受四周細節的干擾和汙染。

  Grady Booch,Object Oriented Analysis and Design with Applications(中譯版《物件導向分析與設計》)一書作者。

  整潔的程式碼簡單直接。整潔的程式碼如同優美的散文。整潔的程式碼從不隱藏設計者的意圖,充滿了乾淨利落的抽象和直截了當的控制語句。

  Grady的觀點與Bjarne的觀點有類似之處,但他從可讀性的角度來定義。我特別喜歡“整潔的程式碼如同優美的散文”這種看法。想想你讀過的某本好書。回憶一下,那些文字是如何在腦中形成影像!就像是看了場電影,對吧?還不止!你還看到那些人物,聽到那些聲音,體驗到那些喜怒哀樂。

  閱讀整潔的程式碼和閱讀Lord of the Rings(中譯版《指環王》)自然不同。不過,仍有可類比之處。如同一本好的小說般,整潔的程式碼應當明確地展現出要解決問題的張力。它應當將這種張力推至高潮,以某種顯而易見的方案解決問題和張力,使讀者發出“啊哈!本當如此!”的感嘆。

  竊以為Grady所謂“乾淨利落的抽象”(crisp abstraction),乃是絕妙的矛盾修辭法。畢竟crisp幾乎就是“具體”(concrete)的同義詞。我MacBook上的詞典這樣定義crisp一詞:果斷決絕,就事論事,沒有猶豫或不必要的細節。儘管有兩種不同的定義,該詞還是承載了有力的資訊。程式碼應當講述事實,不引人猜測。它只該包含必需之物。讀者應當感受到我們的果斷決絕。

優秀程式設計師眼中的整潔程式碼

  “老大”Dave Thomas,OTI公司創始人,Eclipse戰略教父。

  整潔的程式碼應可由作者之外的開發者閱讀和增補。它應當有單元測試和驗收測試。它使用有意義的命名。它只提供一種而非多種做一件事的途徑。它只有儘量少的依賴關係,而且要明確地定義和提供清晰、儘量少的API。程式碼應通過其字面表達含義,因為不同的語言導致並非所有必需資訊均可通過程式碼自身清晰表達。

  Dave老大在可讀性上和Grady持相同觀點,但有一個重要的不同之處。Dave斷言,整潔的程式碼便於其他人加以增補。這看似顯而易見,但亦不可過分強調。畢竟易讀的程式碼和易修改的程式碼之間還是有區別的。

  Dave將整潔繫於測試之上!要在十年之前,這會讓人大跌眼鏡。但測試驅動開發(Test Driven Development)已在行業中造成了深遠影響,成為基礎規程之一。Dave說得對。沒有測試的程式碼不乾淨。不管它有多優雅,不管有多可讀、多易理解,微乎測試,其不潔亦可知也。

  Dave兩次提及“儘量少”。顯然,他推崇小塊的程式碼。實際上,從有軟體起人們就在反覆強調這一點。越小越好。

  Dave也提到,程式碼應在字面上表達其含義。這一觀點源自Knuth的“字面程式設計”(literate programming)5。結論就是應當用人類可讀的方式來寫程式碼。

  Michael Feathers,Working Effectively with Legacy Code(中譯版《修改程式碼的藝術》)一書作者。

  我可以列出我留意到的整潔程式碼的所有特點,但其中有一條是根本性的。整潔的程式碼總是看起來像是某位特別在意它的人寫的。幾乎沒有改進的餘地。程式碼作者什麼都想到了,如果你企圖改進它,總會回到原點,讚歎某人留給你的程式碼——全心投入的某人留下的程式碼。

  一言以蔽之:在意。這就是本書的題旨所在。或許該加個副標題,如何在意程式碼。

  Michael一針見血。整潔程式碼就是作者著力照料的程式碼。有人曾花時間讓它保持簡單有序。他們適當地關注到了細節。他們在意過。

  Ron Jeffries,Extreme Programming Installed(中譯版《極限程式設計實施》)以及Extreme Programming Adventures in C#(中譯版《C#極限程式設計探險》)作者。

  Ron初入行就在戰略空軍司令部(Strategic Air Command)編寫Fortran程式,此後幾乎在每種機器上編寫過每種語言的程式碼。他的言論值得咀嚼。

  近年來,我開始研究貝克的簡單程式碼規則,差不多也都琢磨透了。簡單程式碼,依其重要順序:

  能通過所有測試;

  沒有重複程式碼;

  體現系統中的全部設計理念;

  包括儘量少的實體,比如類、方法、函式等。

  在以上諸項中,我最在意程式碼重複。如果同一段程式碼反覆出現,就表示某種想法未在程式碼中得到良好的體現。我盡力去找出到底那是什麼,然後再盡力更清晰地表達出來。

  在我看來,有意義的命名是體現表達力的一種方式,我往往會修改好幾次才會定下名字來。藉助Eclipse這樣的現代編碼工具,重新命名代價極低,所以我無所顧忌。然而,表達力還不只體現在命名上。我也會檢查物件或方法是否想做的事太多。如果物件功能太多,最好是切分為兩個或多個物件。如果方法功能太多,我總是使用抽取手段(Extract Method)重構之,從而得到一個能較為清晰地說明自身功能的方法,以及另外數個說明如何實現這些功能的方法。

  消除重複和提高表達力讓我在整潔程式碼方面獲益良多,只要銘記這兩點,改進髒程式碼時就會大有不同。不過,我時常關注的另一規則就不太好解釋了。

  這麼多年下來,我發現所有程式都由極為相似的元素構成。例如“在集合中查詢某物”。不管是僱員記錄資料庫還是名-值對雜湊表,或者某類條目的陣列,我們都會發現自己想要從集合中找到某一特定條目。一旦出現這種情況,我通常會把實現手段封裝到更抽象的方法或類中。這樣做好處多多。

  可以先用某種簡單的手段,比如雜湊表來實現這一功能,由於對搜尋功能的引用指向了我那個小小的抽象,就能隨需應變,修改實現手段。這樣就既能快速前進,又能為未來的修改預留餘地。

  另外,該集合抽象常常提醒我留意“真正”在發生的事,避免隨意實現集合行為,因為我真正需要的不過是某種簡單的查詢手段。

  減少重複程式碼,提高表達力,提早構建簡單抽象。這就是我寫整潔程式碼的方法。

  Ron以寥寥數段文字概括了本書的全部內容。不要重複程式碼,只做一件事,表達力,小規模抽象。該有的都有了。

  Ward Cunningham,Wiki發明者,eXtreme Programming(極限程式設計)的創始人之一,Smalltalk語言和麵向物件的思想領袖。所有在意程式碼者的教父。

  如果每個例程都讓你感到深合己意,那就是整潔程式碼。如果程式碼讓程式語言看起來像是專為解決那個問題而存在,就可以稱之為漂亮的程式碼。

  這種說法很Ward。它教你聽了之後就點頭,然後繼續聽下去。如此在理,如此淺顯,絕不故作高深。你大概以為此言深合己意吧。再走近點看看。

  “……深合己意”。你最近一次看到深合己意的模組是什麼時候?模組多半都繁複難解吧?難道沒有觸犯規則嗎?你不是也曾掙扎著想抓住些從整個系統中散落而出的線索,編織進你在讀的那個模組嗎?你最近一次讀到某段程式碼、並且如同對Ward的說法點頭一般對這段程式碼點頭,是什麼時候的事了?

  Ward期望你不會為整潔程式碼所震驚。你無需花太多力氣。那程式碼就是深合你意。它明確、簡單、有力。每個模組都為下一個模組做好準備。每個模組都告訴你下一個模組會是怎樣的。整潔的程式好到你根本不會注意到它。設計者把它做得像一切其他設計般簡單。

  那Ward有關“美”的說法又如何呢?我們都曾面臨語言不是為要解決的問題所設計的困境。但Ward的說法又把球踢回我們這邊。他說,漂亮的程式碼讓程式語言像是專為解決那個問題而存在!所以,讓語言變得簡單的責任就在我們身上了!當心,語言是冥頑不化的!是程式設計師讓語言顯得簡單。

  本文摘自《程式碼整潔之道》

相關文章