原創|行業資訊|編輯:王香|2017-04-17 13:55:19.000|閱讀 477 次
概述:漂亮整潔的代碼不僅給人清爽舒適的感覺,也能有效提高程序員的工作效率,毫無疑問,在這個顏值擔當的時代,代碼也要看臉了,所以如何寫得一手漂亮整潔的代碼是程序員們特別需要get的技能。
# 界面/圖表報表/文檔/IDE等千款熱門軟控件火熱銷售中 >>
漂亮整潔的代碼不僅給人清爽舒適的感覺,也能有效提高程序員的工作效率,毫無疑問,在這個顏值擔當的時代,代碼也要看臉了,所以如何寫得一手漂亮整潔的代碼是程序員們特別需要get的技能。
代碼整潔的大前提
代碼大部分時候是用來維護的,而不是用來實現功能的
這個原則適用于大部分的工程。我們的代碼,一方面是編譯好讓機器執行,完成功能需求;另一方面,是寫給身邊的隊友和自己看的,需要長期維護,而且大部分項目都不是朝生夕死的短命鬼。
對清晰好看代碼的追求精神,比所有的技巧都要重要。
優秀的代碼大部分是可以自描述的,好于文檔和注釋
當你翻看很多開源代碼時,會發現注釋甚至比我們自己寫的項目都少,但是卻能看的很舒服。當讀完源碼時,很多功能設計就都清晰明了了。通過仔細斟酌的方法命名、清晰的流程控制,代碼本身就可以拿出來當作文檔使用,而且它永遠不會過期。
相反,注釋不能讓寫的爛的代碼變的更好。如果別人只能依靠注釋讀懂你的代碼的時候,你一定要反思代碼出現了什么問題(當然,這里不是說大家不要寫注釋了)。
說下比較適合寫注釋的兩種場景:
設計模式只是手段,代碼清晰才是目的
之前見過一些所謂“高手”的代碼都比較抽象,各種工廠、各種繼承。想找到一個實現總是要山路十八彎,一個工程里大部分的類是抽象類或者接口,找不到一兩句實現的代碼,整個讀起代碼來很不順暢。我跟他聊起來的時候,他的主要立場是:保留合適的擴展點,克服掉所有的硬編碼。
其實在我看來,也許他的代碼被“過度設計”了。首先必須要承認的是,在同一個公司工作的同事,水平是參差不齊的。無論你用了如何高大上的設計,如果大多數人都不能理解你的代碼或者讀起來很費勁的話,其實這是一個失敗的設計。
當你的系統內大部分抽象只有一個實現的時候,要好好思考一下,是不是設計有點過度了,清晰永遠是第一準則。
代碼整潔的常見手段
code review
很多大公司會用git的pull request機制來做code review。我們重點應該review什么?是代碼的格式、業務邏輯還是代碼風格?我想說的是,凡是能通過機器檢查出來的事情,無需通過人。比如換行、注釋、方法長度、代碼重復等。除了基本功能需求的邏輯合理沒有bug外,我們更應該關注代碼的設計與風格。比如,一段功能是不是應該屬于一個類、是不是有很多相似的功能可以抽取出來復用、代碼太過冗長難懂等等。
我個人非常推崇集體code review,因為很多時候,組里相對高級的工程師能夠一眼發現代碼存在較大設計缺陷,提出改進意見或者重構方式。我們可以在整個小組內形成一個好的文化傳承和風格統一,并且很大程度上培養了大家對clean code的熱情。
勤于重構
好的代碼,一般都不是一撮而就的。即使一開始設計的代碼非常優秀,隨著業務的快速迭代,也可能被改的面目全非。
為了避免重構帶來的負面影響(delay需求或者帶來bug),我們需要做好以下的功課:
靜態檢查
現在市面上有很多代碼靜態檢查的工具,也是發現bug和風格不好的比較容易的方式。可以與發布系統做集成,強制把主要問題修復掉才可以上線。目前美團點評技術團隊內部的研發流程中已經普遍接入了Sonar質量管理平臺。
代碼整潔的常見技巧
單一職責
這是整潔代碼的最重要也是最基本的原則了。簡單來講,大到一個module、一個package,小到一個class、一個method乃至一個屬性,都應該承載一個明確的職責。要定義的東西,如果不能用一句話描述清楚職責,就把它拆掉。
我們平時寫代碼時,最容易犯的錯誤是:一個方法干了好幾件事或者一個類承載了許多功能。
先來聊聊方法的問題。個人非常主張把方法拆細,這是復用的基礎。如果方法干了兩件事情,很有可能其中一個功能的其他業務有差別就不好重用了。另外語義也是不明確的。經常看到一個get()方法里面竟然修改了數據,這讓使用你方法的人情何以堪?如果不點進去看看實現,可能就讓程序陷入bug,讓測試陷入麻煩。
再來聊聊類的問題。我們經常會看到“又臭又長”的service/biz層的代碼,里面有幾十個方法,干什么的都有:既有增刪改查,又有業務邏輯的聚合。每次找到一個方法都費勁。不屬于一個領域或者一個層次的功能,就不要放到一起。
我們 team 在code review中,最常被批評的問題,就是一個方法應該歸屬于哪個類。
優先定義整體框架
我寫代碼的時候,比較喜歡先去定義整體的框架,就是寫很多空實現,來把整體的業務流程穿起來。良好的方法簽名,用入參和出參來控制流程。這樣能夠避免陷入業務細節無法自拔。在腦海中先定義清楚流程的幾個階段,并為每個階段找到合適的方法/類歸屬。
這樣做的好處是,閱讀你代碼的人,無論讀到什么深度,都可以清晰地了解每一層的職能,如果不care下一層的實現,完全可以跳過不看,并且方法的粒度也會恰到好處。
簡而言之,我比較推崇寫代碼的時候“廣度優先”而不是“深度優先”,這和我讀代碼的方式是一致的。當然,這件事情跟個人的思維習慣有一定的關系,可能對抽象思維能力要求會更高一些。如果開始寫代碼的時候這些不夠清晰,起碼要通過不斷地重構,使代碼達到這樣的成色。
清晰的命名
老生常談的話題,這里不展開講了,但是必須要mark一下。有的時候,我思考一個方法命名的時間,比寫一段代碼的時間還長。原因還是那個邏輯:每當你寫出一個類似于”temp”、”a”、”b”這樣變量的時候,后面每一個維護代碼的人,都需要用幾倍的精力才能理順。
并且這也是代碼自描述最重要的基礎。
避免過長參數
如果一個方法的參數長度超過4個,就需要警惕了。一方面,沒有人能夠記得清楚這些函數的語義;另一方面,代碼的可讀性會很差;最后,如果參數非常多,意味著一定有很多參數,在很多場景下,是沒有用的,我們只能構造默認值的方式來傳遞。
解決這個問題的方法很簡單,一般情況下我們會構造paramObject。用一個struct或者一個class來承載數據,一般這種對象是value object,不可變對象。這樣,能極大程度提高代碼的可復用性和可讀性。在必要的時候,提供合適的build方法,來簡化上層代碼的開發成本。
避免過長方法和類
一個類或者方法過長的時候,讀者總是很崩潰的。簡單地把方法、類和職責拆細,往往會有立竿見影的成效。以類為例,拆分的維度有很多,常見的是橫向/縱向。
例如,如果一個service,處理的是跟一個庫表對象相關的所有邏輯,橫向拆分就是根據業務,把建立/更新/修改/通知等邏輯拆到不同的類里去;而縱向拆分,指的是把數據庫操作/MQ操作/Cache操作/對象校驗等,拆到不同的對象里去,讓主流程盡量簡單可控,讓同一個類,表達盡量同一個維度的東西。
讓相同長度的代碼段表示相同粒度的邏輯
這里想表達的是,盡量多地去抽取private方法,讓代碼具有自描述的能力。舉個簡單的例子
public void doSomeThing(Map params1,Map params2){ Do1 do1 = getDo1(params1); Do2 do2 = new Do2(); do2.setA(params2.get("a")); do2.setB(params2.get("b")); do2.setC(params2.get("c")); mergeDO(do1,do2); } private void getDo1(Map params1); private void mergeDo(do1,do2){...};
類似這種代碼,在業務代碼中隨處可見。獲取do1是一個方法,merge是一個方法,但獲取do2的代碼卻在主流程里寫了。這種代碼,流程越長,讀起來越累。很多人讀代碼的邏輯,是“廣度優先”的。先讀懂主流程,再去看細節。類似這種代碼,如果能夠把構造do2的代碼,提取一個private 方法,就會舒服很多。
以上這些優化管理代碼的方法能夠有效使我們的代碼看起來更清爽更漂亮,還是那句話,這絕不僅僅是顏值問題,這更是一個工作效率的問題,不想在冗雜的代碼里掙扎就不妨嘗試一下上面的方法吧,也許你會發現something amazing.
微信關注公眾號:Aspose 滿足一切文檔需求
本站文章除注明轉載外,均為本站原創或翻譯。歡迎任何形式的轉載,但請務必注明出處、不得修改原文相關鏈接,如果存在內容上的異議請郵件反饋至chenjj@fc6vip.cn