譯者 | 陳峻
審校 | 梁策 孫淑娟
眾所周知,干凈的代碼不但能夠讓閱讀者方便理解程序的意圖,而且也方便維護與迭代??偟恼f來,它能夠給軟件的開發與升級帶來如下好處:
- 在維護上花費更少的時間。干凈的代碼更易于被閱讀和領會,您可以花費更少的時間去弄清楚實際問題的來龍去脈,進而為修復、修改、以及擴展等操作留下更多的時間。
- 更清晰地交流想法。程序開發離不開協作。而干凈的代碼往往可以減少項目成員之間可能產生的誤解。而且從長遠來看,這也意味著更少的錯誤,更快地解決問題。
不過,正所謂“知易行難”,從某種程度上說,編寫干凈的代碼就像學繪畫、烹飪或攝影那樣--看起來比較容易,實踐起來則比較困難。下面,我將和您討論能夠編寫出優秀且干凈代碼的十大技巧。
1.使用描述性名稱
程序中的變量、類和函數,往往是給其他程序員、以及應用程序底層邏輯之間的接口調用的。因此,當您對變量、類和函數使用不明確且非描述性的名稱時,實際上就是在擾亂閱讀代碼者(包括開發人員自己)對應用程序邏輯的理解。例如:您能一眼看出一個名為dxy的變量的實際含義嗎?想必,您必須閱讀整個代碼塊,才能對其含義進行“逆向工程”吧。不過,對于變量distanceBetweenXY,你我都能夠馬上領會到它代表的含義。
同理,類和函數也是如此。請盡量避免使用CalcTan(),而應當按需采用CalculateTangent()或CalcTangentAngle()??傊沟么a看起來整潔的基本技巧之一便是使用描述性名稱。
2. 讓每個類/函數都有實際意義
您一定看到過那些長達數百甚至數千行的函數吧?想必,您在瀏覽、理解、甚至是編輯的時候會覺得無比痛苦。就算行間有相應的注釋,其實際效果往往也是“杯水車薪”的。而干凈的代碼則不然。它們會被分解成不同目的的代碼塊。其中,每個子函數都被設定為完成某個具體的任務,而每個類也都代表了一個特定的概念。由此帶來的簡潔性,更適合局部調整,也更適合問題的定位與排查。
例如,在實踐中,諸如GetCreditScore()之類復雜的功能,有必要被分解成為GetCreditReports()、ApplyCreditHistoryAge()、以及FilterOutstandingMarks()等多個輔助函數。您可以參考《??每個程序員都應該知道的基本編程原則??》一文,來進一步了解相關做法。
3.刪除不必要的代碼
不知您是否有過這樣的體驗:在修復或優化某段代碼的過程中,您特意將其注釋掉,并在其下方開始動手重寫新的代碼。而且,您這樣做的目的,只是純粹為了保留舊的代碼,以備不時之需。不過,隨著時間的推移,您可能會不知不覺地積累了大量的、不再需要的、被注釋掉的代碼塊。這些代碼塊無疑會讓您的源代碼變得混亂不堪。而且,多數實際情況往往是:由于周圍的相關代碼、及其環境也早已發生了迭代,因此這些被注釋掉的代碼,其實并不可能再被恢復使用了。
當然,這種注釋掉舊代碼的做法,完全可以被如今時尚的源代碼控制系統所取代。您可以通過使用Git或Mercurial之類的工具,及時、準確、自動化地開展源代碼管理工作。
同時,為了讓應用服務輕便而敏捷,您也可以有意識地通過現成的Web框架,避免“重復造輪子”,進而利用由框架提供的類庫,來簡化自己的代碼。對此,您可以具體參考《??一些值得開發人員學習的Web框架??》一文。
4.可讀性
大多程序員會把“干凈的代碼”和“聰明的代碼(clever code)”混為一談,并簡單地認為“把十行代碼壓縮成一行,以減少屏幕空間的占用”,便是干凈的代碼。其實,在大多數時候,這樣的代碼不一定真的容易被理解。
在我看來,此類可解決某些專業難題的代碼,屬于“聰明的代碼”范疇。程序員們可以將其視為自己的獨門秘籍。它們往往被用來證明自己的編程技能,甚至被用作炫技之需。而對于干凈代碼的編寫,您應該保持開放的心態:代碼量的多少,并非代碼是否干凈的唯一衡量標準。除了實現代碼的功能,您的代碼還需要保持一定的可讀性。畢竟下一次閱讀該代碼段的很可能不是別人、正是你自己。畢竟,誰都不想給自己的將來刨坑埋雷。
5. 保持一致的編程風格
每個程序員都有自己的編程風格。在此,我并不想推薦或強求大家去遵從某種所謂最佳編程風格。如果您習慣在行間使用大括號,如果您想在方法調用之前加上空格,如果您更喜歡使用制表符而不是空格的話,這些都可以。只不過,請保持此類用法的一致性。
同時,如果您打算將camelCaseNaming用作變量,那么就請不要將其與underscore_naming混為一談;如果您在某個地方使用了GetThisObject(),那么就請不要在其他地方采用FetchThatObject()。
此外,諸如Python和C#等編程語言,本身就帶有各種需要遵循的樣式規范,包括:絕不允許制表符和空格的混用等。
6. 選擇正確的架構
您可以使用各種現成的范例和架構來創建不同的項目。當然,前提條件是,請選擇最適合的,并不是所謂最好的。例如,模型-視圖-控制器(Model-View-Controller,MVC)模式一直是Web開發領域最流行的架構。畢竟,它不但有助于您保持代碼架構的清晰合理,而且能夠使得后期的維護工作量最小。類似地,實體-組件-系統(Entity-Component-System,ECS)模式在游戲開發界也非常流行。畢竟它能夠協助實現模塊化的游戲數據和邏輯,使得維護更輕松,同時能夠生成更加易讀的代碼。
7. 掌握語言中的慣用法
我們所熟悉的Python、Java和JavaScript等不同的語言,都有著不同的編程思想與習慣。它們之間的差別或是巨大或是細微。例如:Python代碼會完全依賴緊湊代碼和鴨子類型(duck typing,基于“當一只鳥走起來像鴨子、游起來像鴨子、叫起來也像鴨子,那么這只鳥就可以被稱為鴨子?!钡倪壿?,我們不必關心對象是什么類型,只要關心它的動態行為即可。);而Java則更傾向于冗長和明確的代碼。同時,每一種語言都會鼓勵使用自己的慣用法,例如Python中的列表推導式。
與此同時,我們也要警惕所謂的“反面模式(anti-patterns)”。雖然那些由前人積累的、解決某些軟件開發特定問題的模式,會讓后輩獲益無窮;但是如果它們是一些狹隘的、僅對特定需求有效的模式的話,那么就應該被避免繼續沿用。
8.學習大師寫的代碼
俗話說“有樣學樣”,如果您想編寫出干凈的代碼,那么您首先就要知道干凈的代碼應該是什么樣子。而一些大師級前輩的程序作品,就能起到很好的示范作用,學習他們背后的編程思想、邏輯、以及代碼習慣。
顯然,您不可能隨便跑進微軟總部去“偷師”他們的項目,但是您可以通過Github上的各種??展示性項目??,隨時瀏覽到典型的行業應用、以及各個開源項目的源文件代碼。畢竟,這也是開源項目的一個初衷:讓更多的人可以從中學習編程。通過這種社區互助的方式,您的代碼質量會得以迅速提高。
9. 寫好注釋
“附上注釋”是編程世界中最古老的一項建議。不過在實際編程中,新手程序員一旦被建議要盡可能地留下注釋,他們就會樂此不疲。當然,那些不必要的描述、甚至會透露敏感信息的過度注釋,也可能會帶來適得其反的效果。
我們該如何恰如其分地點到為止呢?我的一個經驗法則是:注釋是被用來解釋為何需要這段代碼,而不是講解代碼實際能夠做什么。如果您的代碼寫得足夠干凈的話,其作用是不言自明的。例如:我們雖然可以用注釋來解釋“刪除它就會破壞A、B和C”的警告,但是在大多數情況下,我們應該用注釋來揭示諸如:“使用此參數,是因為X、Y和Z”之類,讀者無法從代碼中立即獲悉到的內容。
10.重構
正如編輯屬于文字寫作過程的一部分那樣,重構也應該是編程過程的一部分。其實,重構能夠起到協助優化代碼的作用,而不會影響其實際行為。同時,重構也有利于提高代碼維護的效率。我在此方面的經驗是:“不要僅僅注釋掉那些讓你覺得混亂、或者不夠好的代碼,請干脆重寫它們吧?!碑吘?,隨著時間的推移和經驗的積累,您在回顧或維護整個軟件項目時,總能發現一些對于首次編寫不滿意、且值得重構的代碼。
小結
正如我們學習如何寫出言簡意賅的說明文那樣,干凈的代碼本身并沒有絕對正確的參照標準。希望上文和您討論的十項技巧,能夠成為您避免寫出冗長且臃腫的代碼的實用參考。
譯者介紹
陳峻 (Julian Chen),51CTO社區編輯,具有十多年的IT項目實施經驗,善于對內外部資源與風險實施管控,專注傳播網絡與信息安全知識與經驗;持續以博文、專題和譯文等形式,分享前沿技術與新知;經常以線上、線下等方式,開展信息安全類培訓與授課。
原文標題:10 Tips for Writing Cleaner & Better Code,作者:JOEL LEE