有多少程序員(yuán),就有多少定義。所以我(wǒ)(wǒ)隻詢問了一(yī)些非常知(zhī)名且經驗豐富的程序員(yuán)。
Bjarne Stroustrup,C++語言發明者,C++ Programming Language(中(zhōng)譯版《C++程序設計語言》)一(yī)書(shū)作者。
我(wǒ)(wǒ)喜歡優雅和高效的代碼。代碼邏輯應當直截了當,叫缺陷難以隐藏;盡量減少依賴關系,使之便于維護;依據某種分(fēn)層戰略完善錯誤處理代碼;性能調至最優,省得引誘别人做沒規矩的優化,搞出一(yī)堆混亂來。整潔的代碼隻做好一(yī)件事。
Bjarne用了“優雅”一(yī)詞。說得好!我(wǒ)(wǒ)MacBook上的詞典提供了如下(xià)定義:外(wài)表或舉止上令人愉悅的優美和雅觀;令人愉悅的精緻和簡單。注意對“愉悅”一(yī)詞的強調。Bjarne顯然認爲整潔的代碼讀起來令人愉悅。讀這種代碼,就像見到手工(gōng)精美的音樂盒或者設計精良的汽車(chē)一(yī)般,讓你會心一(yī)笑。
Bjarne也提到效率——而且兩次提及。這話(huà)出自C++發明者之口,或許并不出奇;不過我(wǒ)(wǒ)認爲并非是在單純追求速度。被浪費(fèi)掉的運算周期并不雅觀,并不令人愉悅。留意Bjarne怎麽描述那種不雅觀的結果。他用了“引誘”這個詞。誠哉斯言。糟糕的代碼引發混亂!别人修改糟糕的代碼時,往往會越改越爛。
務實的Dave Thomas和Andy Hunt從另一(yī)角度闡述了這種情況。他們提到破窗理論4。窗戶破損了的建築讓人覺得似乎無人照管。于是别人也再不關心。他們放(fàng)任窗戶繼續破損。最終自己也參加破壞活動,在外(wài)牆上塗鴉,任垃圾堆積。一(yī)扇破損的窗戶開(kāi)辟了大(dà)廈走向傾頹的道路。
Bjarne也提到完善錯誤處理代碼。往深處說就是在細節上花心思。敷衍了事的錯誤處理代碼隻是程序員(yuán)忽視細節的一(yī)種表現。此外(wài)還有内存洩漏,還有競态條件代碼。還有前後不一(yī)緻的命名方式。結果就是凸現出整潔代碼對細節的重視。
Bjarne以“整潔的代碼隻做好一(yī)件事”結束論斷。毋庸置疑,軟件設計的許多原則最終都會歸結爲這句警語。有那麽多人發表過類似的言論。糟糕的代碼想做太多事,它意圖混亂、目的含混。整潔的代碼力求集中(zhōng)。每個函數、每個類和每個模塊都全神貫注于一(yī)事,完全不受四周細節的幹擾和污染。
Grady Booch,Object Oriented Analysis and Design with Applications(中(zhōng)譯版《面向對象分(fēn)析與設計》)一(yī)書(shū)作者。
整潔的代碼簡單直接。整潔的代碼如同優美的散文。整潔的代碼從不隐藏設計者的意圖,充滿了幹淨利落的抽象和直截了當的控制語句。
Grady的觀點與Bjarne的觀點有類似之處,但他從可讀性的角度來定義。我(wǒ)(wǒ)特别喜歡“整潔的代碼如同優美的散文”這種看法。想想你讀過的某本好書(shū)。回憶一(yī)下(xià),那些文字是如何在腦中(zhōng)形成影像!就像是看了場電(diàn)影,對吧?還不止!你還看到那些人物(wù),聽(tīng)到那些聲音,體(tǐ)驗到那些喜怒哀樂。
閱讀整潔的代碼和閱讀Lord of the Rings(中(zhōng)譯版《指環王》)自然不同。不過,仍有可類比之處。如同一(yī)本好的小(xiǎo)說般,整潔的代碼應當明确地展現出要解決問題的張力。它應當将這種張力推至高潮,以某種顯而易見的方案解決問題和張力,使讀者發出“啊哈!本當如此!”的感歎。
竊以爲Grady所謂“幹淨利落的抽象”(crisp abstraction),乃是絕妙的矛盾修辭法。畢竟crisp幾乎就是“具體(tǐ)”(concrete)的同義詞。我(wǒ)(wǒ)MacBook上的詞典這樣定義crisp一(yī)詞:果斷決絕,就事論事,沒有猶豫或不必要的細節。盡管有兩種不同的定義,該詞還是承載了有力的信息。代碼應當講述事實,不引人猜測。它隻該包含必需之物(wù)。讀者應當感受到我(wǒ)(wǒ)們的果斷決絕。
“老大(dà)”Dave Thomas,OTI公司創始人,Eclipse戰略教父。
整潔的代碼應可由作者之外(wài)的開(kāi)發者閱讀和增補。它應當有單元測試和驗收測試。它使用有意義的命名。它隻提供一(yī)種而非多種做一(yī)件事的途徑。它隻有盡量少的依賴關系,而且要明确地定義和提供清晰、盡量少的API。代碼應通過其字面表達含義,因爲不同的語言導緻并非所有必需信息均可通過代碼自身清晰表達。
Dave老大(dà)在可讀性上和Grady持相同觀點,但有一(yī)個重要的不同之處。Dave斷言,整潔的代碼便于其他人加以增補。這看似顯而易見,但亦不可過分(fēn)強調。畢竟易讀的代碼和易修改的代碼之間還是有區别的。
Dave将整潔系于測試之上!要在十年之前,這會讓人大(dà)跌眼鏡。但測試驅動開(kāi)發(Test Driven Development)已在行業中(zhōng)造成了深遠影響,成爲基礎規程之一(yī)。Dave說得對。沒有測試的代碼不幹淨。不管它有多優雅,不管有多可讀、多易理解,微乎測試,其不潔亦可知(zhī)也。
Dave兩次提及“盡量少”。顯然,他推崇小(xiǎo)塊的代碼。實際上,從有軟件起人們就在反複強調這一(yī)點。越小(xiǎo)越好。
Dave也提到,代碼應在字面上表達其含義。這一(yī)觀點源自Knuth的“字面編程”(literate programming)5。結論就是應當用人類可讀的方式來寫代碼。
Michael Feathers,Working Effectively with Legacy Code(中(zhōng)譯版《修改代碼的藝術》)一(yī)書(shū)作者。
我(wǒ)(wǒ)可以列出我(wǒ)(wǒ)留意到的整潔代碼的所有特點,但其中(zhōng)有一(yī)條是根本性的。整潔的代碼總是看起來像是某位特别在意它的人寫的。幾乎沒有改進的餘地。代碼作者什麽都想到了,如果你企圖改進它,總會回到原點,贊歎某人留給你的代碼——全心投入的某人留下(xià)的代碼。
一(yī)言以蔽之:在意。這就是本書(shū)的題旨所在。或許該加個副标題,如何在意代碼。
Michael一(yī)針見血。整潔代碼就是作者着力照料的代碼。有人曾花時間讓它保持簡單有序。他們适當地關注到了細節。他們在意過。
Ron Jeffries,Extreme Programming Installed(中(zhōng)譯版《極限編程實施》)以及Extreme Programming Adventures in C#(中(zhōng)譯版《C#極限編程探險》)作者。
Ron初入行就在戰略空軍司令部(Strategic Air Command)編寫Fortran程序,此後幾乎在每種機器上編寫過每種語言的代碼。他的言論值得咀嚼。
近年來,我(wǒ)(wǒ)開(kāi)始研究貝克的簡單代碼規則,差不多也都琢磨透了。簡單代碼,依其重要順序:
能通過所有測試;
沒有重複代碼;
體(tǐ)現系統中(zhōng)的全部設計理念;
包括盡量少的實體(tǐ),比如類、方法、函數等。
在以上諸項中(zhōng),我(wǒ)(wǒ)最在意代碼重複。如果同一(yī)段代碼反複出現,就表示某種想法未在代碼中(zhōng)得到良好的體(tǐ)現。我(wǒ)(wǒ)盡力去(qù)找出到底那是什麽,然後再盡力更清晰地表達出來。
在我(wǒ)(wǒ)看來,有意義的命名是體(tǐ)現表達力的一(yī)種方式,我(wǒ)(wǒ)往往會修改好幾次才會定下(xià)名字來。借助Eclipse這樣的現代編碼工(gōng)具,重命名代價極低,所以我(wǒ)(wǒ)無所顧忌。然而,表達力還不隻體(tǐ)現在命名上。我(wǒ)(wǒ)也會檢查對象或方法是否想做的事太多。如果對象功能太多,最好是切分(fēn)爲兩個或多個對象。如果方法功能太多,我(wǒ)(wǒ)總是使用抽取手段(Extract Method)重構之,從而得到一(yī)個能較爲清晰地說明自身功能的方法,以及另外(wài)數個說明如何實現這些功能的方法。
消除重複和提高表達力讓我(wǒ)(wǒ)在整潔代碼方面獲益良多,隻要銘記這兩點,改進髒代碼時就會大(dà)有不同。不過,我(wǒ)(wǒ)時常關注的另一(yī)規則就不太好解釋了。
這麽多年下(xià)來,我(wǒ)(wǒ)發現所有程序都由極爲相似的元素構成。例如“在集合中(zhōng)查找某物(wù)”。不管是雇員(yuán)記錄數據庫還是名-值對哈希表,或者某類條目的數組,我(wǒ)(wǒ)們都會發現自己想要從集合中(zhōng)找到某一(yī)特定條目。一(yī)旦出現這種情況,我(wǒ)(wǒ)通常會把實現手段封裝到更抽象的方法或類中(zhōng)。這樣做好處多多。
可以先用某種簡單的手段,比如哈希表來實現這一(yī)功能,由于對搜索功能的引用指向了我(wǒ)(wǒ)那個小(xiǎo)小(xiǎo)的抽象,就能随需應變,修改實現手段。這樣就既能快速前進,又(yòu)能爲未來的修改預留餘地。
另外(wài),該集合抽象常常提醒我(wǒ)(wǒ)留意“真正”在發生(shēng)的事,避免随意實現集合行爲,因爲我(wǒ)(wǒ)真正需要的不過是某種簡單的查找手段。
減少重複代碼,提高表達力,提早構建簡單抽象。這就是我(wǒ)(wǒ)寫整潔代碼的方法。
Ron以寥寥數段文字概括了本書(shū)的全部内容。不要重複代碼,隻做一(yī)件事,表達力,小(xiǎo)規模抽象。該有的都有了。
Ward Cunningham,Wiki發明者,eXtreme Programming(極限編程)的創始人之一(yī),Smalltalk語言和面向對象的思想領袖。所有在意代碼者的教父。
如果每個例程都讓你感到深合己意,那就是整潔代碼。如果代碼讓編程語言看起來像是專爲解決那個問題而存在,就可以稱之爲漂亮的代碼。
這種說法很Ward。它教你聽(tīng)了之後就點頭,然後繼續聽(tīng)下(xià)去(qù)。如此在理,如此淺顯,絕不故作高深。你大(dà)概以爲此言深合己意吧。再走近點看看。
“……深合己意”。你最近一(yī)次看到深合己意的模塊是什麽時候?模塊多半都繁複難解吧?難道沒有觸犯規則嗎(ma)?你不是也曾掙紮着想抓住些從整個系統中(zhōng)散落而出的線索,編織進你在讀的那個模塊嗎(ma)?你最近一(yī)次讀到某段代碼、并且如同對Ward的說法點頭一(yī)般對這段代碼點頭,是什麽時候的事了?
Ward期望你不會爲整潔代碼所震驚。你無需花太多力氣。那代碼就是深合你意。它明确、簡單、有力。每個模塊都爲下(xià)一(yī)個模塊做好準備。每個模塊都告訴你下(xià)一(yī)個模塊會是怎樣的。整潔的程序好到你根本不會注意到它。設計者把它做得像一(yī)切其他設計般簡單。
那Ward有關“美”的說法又(yòu)如何呢?我(wǒ)(wǒ)們都曾面臨語言不是爲要解決的問題所設計的困境。但Ward的說法又(yòu)把球踢回我(wǒ)(wǒ)們這邊。他說,漂亮的代碼讓編程語言像是專爲解決那個問題而存在!所以,讓語言變得簡單的責任就在我(wǒ)(wǒ)們身上了!當心,語言是冥頑不化的!是程序員(yuán)讓語言顯得簡單。