天天看點

「後端」Code Review 是苦澀但有意思的修行

作者:架構思考
本文将分享對于團隊 CodeReview 的一些看法和心得,歡迎閱讀~

一、前言

最近 CodeReview(代碼評審,又叫代碼審查,下稱 CR)心态相當的平和,代碼是一個講道理的東西,是就是,否就否。在 CR 時,溝通特别輕松,問題讨論也特别聚焦,因為它是量化和定向的。CR 的過程不是恃強淩弱,也不是一言堂,大家看着代碼,當是一種靈魂的交流,那麼每一次的 CR 也是同僚間提升和諧度的一種方式。優良的 CR 傳統可以展現團隊溫度,展現高年級同學傳幫帶的技術文化。平時,大家擡頭看 PRD,低頭寫代碼,很少有時間靜心氣閑地交流一下業務流程、業務邏輯、業務未來擴充,在 CR 時,往往可以反複被讨論到。有些問題是 CR 階段群智群力發現的。人的一個能力,不是解決了問題,也不是發現了問題,而是利用某種手段預知了問題。曾經有段代碼,我覺得取反邏輯生澀難懂,反複修改之後,發現寫代碼的小夥伴是錯誤的領會了業務意圖。

提升技術品質、促進人才成長、培養技術情懷這些口号我們今天先放一邊,聊聊最近 CR 的切身體會。CR 不是互相看天書,而是産生天天看書的感覺,每一段寫得好,寫得不好的代碼都是一本書,好的代碼希望見賢思齊,差的代碼希望見不賢而内自省也。總之,CR 是一種修行,也是一種自我積累,苦澀的是看到慘不忍睹的代碼,心裡說:我去!有意思的是看到優雅的代碼,心裡也說:我去!

二、業務跑得這麼快,沒時間 CR

這是一個很大的謊言,不要為自己的醜代碼找個華麗的借口,沒有時間好好 CR,總有時間焦頭爛額地處理故障和投訴。時間老人是公平的,我一直認為某個同學在工位上噼裡啪啦打字,就是說明他幹活快,通過團隊打字比賽,發現其中 20% 在按 BACKSPACE 鍵。業務跑得快,代碼寫得快,可能寫的是一堆沒有營養甚至是有毒的代碼。我們需要追求的是 CR 的效能,而不是逃避 CR。CR 是一種修行,對于雙方都是一樣的收獲。因為如果想象成一個攤派任務,抵觸情緒總會油然而生。業務跑得快,也得兩腿是健康的, CR 就是讓業務持續快的一個小醫生。要不然,今天沖刺 100 米,明天就嗝 P,這樣的不正常的業務節奏對公司的中長遠發展肯定是弊大于利。

三、代碼是講道理的

我覺得靠燒香來保佑代碼不出問題時,保平安往往也是暫時的。牛叉的代碼,就是在小流量、單線程沒有問題,在高流量、高并發時還是沒有問題,你的限流,你的容災,你的降級各種飛彈防禦系統一樣自動打開并正确地發揮價值。很多人的思維覺得,代碼隻要在場景和邏輯上沒有問題就行,那是因為夜路走得不夠多,還沒有碰到鬼。代碼是講道理的,就像有一個同學說 >= 比 > 更加慢,那隻是我們的潛意識猜測,經過深達編譯層的分析,發現兩個指令幾乎是完全一樣。其實憑我們的想象,那也是一個位運算級别的操作,從左向右比,如果一處有 1,另一個沒有 1,那麼前者一定是更大。沒有無緣無故的愛,沒有無緣無故的恨,一切的故障總是代碼的字裡行間。我們需要做的,就是讀懂她,用好她,寫好她。如果代碼任性闖禍,那麼是我們不懂代碼的心思。

四、每一行代碼的存在是有意義的

更加嚴格地說,每一個字元的存在都應該是有意義的。如果某行代碼的存在完全是可有可無的,這個時候,我們考慮過 JVM 的感受嗎?憑白無故地要編譯這些位元組碼,然後棧進棧出的忙活一陣子,然後告訴它,你的勞動是沒有任何價值的。比如:

Boolean assetFlag = Boolean.true;           

這裡都已經明确地給給出來顯示的初始值,可是在調用端,居然還有這樣的判斷:

if ( assetFlag != null && assetFlag == true) {...}           

什麼情況下為 null 值啊?另外參數在架構裡已經做了值的判斷,那麼下邊又是 n 行,對所有參數重新判斷一遍,是對我們的代碼有多少不自信,還是對架構不自信?每一行的代碼,相當于生命,它的存在一定是有意義的,一定是能夠被執行到并且能夠為實際的業務負責的。

五、我們比拼的不是代碼行數

在 CR 過程中,發現有些方法,重複用到一段邏輯,這段邏輯如果不抽取出來成為一個方法,未來的修改就成了一個必須多點全部修改的大坑,稍有不慎,容易遺漏。重複代碼在送出行數上,似乎挺壯觀的。如果在同樣的效果上,3 行代碼能夠實作功能的價值,就不應該用 4 行來實作。我們經常說曬出代碼行數,并非是單純地鼓勵代碼行數多,而是提倡大家去寫代碼,寫優質的代碼,優質的代碼一定是少即是多的原則。代碼的實作,不要像魯迅先生說的一樣:懶婆娘的裹腳布又臭又長。

六、使用者視角的成功與失敗

在傳遞時,調用服務失敗,然後傳回前台一個空清單,那麼前端業務的展示是背景資料正常,這個人不擁有資料清單,這明明是對資料的一種曲解。是以,背景調用服務失敗,就應該明确告訴前台,服務出錯了,這個使用者有沒有資料。系統出錯的資訊給使用者看,合适嗎?不合适。前後端的使用者交界面上,往往飛着兩類資訊:錯誤碼、錯誤資訊。這樣夠了嗎?使用者提示需要額外地再給出來,往往根據不同的錯誤碼,有不同的使用者提示,可能是一個多對多的關系。多個錯誤碼,提示給使用者的資訊:請輸入必填項。多個使用者資訊,可能也對應一個錯誤碼。一般來說背景承包這三者的關聯關系,json 串推送給前端時,前端拿來主義即可。

七、有重複使用的量一定要找個地方集中隔離

不管是變量,還是常量,工具類,如果是多個地方同時用到,那麼如果寫死在代碼或者沉澱在包裡,未來一定是一個災難。比如,一個組裝 SQL 語句的代碼,到處都是"from"、"where"、"limit",都是這類語句直接寫死在代碼中,注意問題來了,這些單詞前後都需要加空格。有時候在複制粘粘時,發現少了一個空格,出現的問題,往往是緻命的。再比如,一個互相約定的分隔符“###”,定義在本類中 private String,這明顯是兩個共同遵守的常量,單獨定義的結果就是容易造成不比對。隔離的目的是複用它,保護程式地正常運作,易于維護。

八、單測沒必要代碼 CR

單測有時候感覺像是闌尾,有或沒有感覺都是無關緊急,這是錯誤的觀點。單測感覺就是一個任務。你寫單測了嗎?寫了。單測是否需要 MOCK,是否進行邊界值測試,是否用例覆寫到業務場景,這都也是 CR 的一部分。單測寫得好,BUG 肯定少。需要調試來查找錯誤時,往往是一種對異常處理機制的侮辱

良好的日志和異常機制,是不應該出現調試的。打日志和抛異常,一定要把上下文給出來,否則,等于在毀滅命案現場,把後邊處理問題的人,往歪路上帶。别人傳一個參數進來,發現是 null,立馬抛出來一個參數異常提示,然後也不傳回哪一個參數是 null,這在調用參數很多的情況下,簡直就是字謎遊戲一樣。到底是抛異常,還是抛錯誤碼?我不管抛什麼,反正錯了什麼東西,都應該透明出來。到底是抛受檢異常,還是非受檢異常,我隻想說,沒有充足的理由,不要亂抛受檢異常。異常抛出時,一定要自己消化幹淨,告訴别人說我的方法簽名抛的是 AbcException,實際運作中,代碼某個地方直接抛出 EfgException,這也是不負責任的。

九、多個 return 的語句,機率高的一定先進行判定

if(condition1) return; if(condition2) return; if(condition3) return;           

那麼需要評估一下 condition 1/2/3 出現機率的大小,概念大的在最前邊,盡可能快地進行 return,不需要進行後續無謂的比對。不要總覺得計算機跑得快,不差這點蠅頭小利的,這種思維,和《南轅北轍》裡的寓義一樣的嗎?

十、吝啬空行

感覺空行是廉價的,到處亂扔是一種;另一種是感覺空行是昂貴的,舍不得用,這種情況更多見。50 行代碼沒有一個空行,就像英語 50 句話,沒有任何标點符号一樣。既然标點符号起到隔斷和語義區分作用,我們的空行不是同一個道理嗎?在以下情形:

  1. 在方法的 return、break、continue 這種斷開性語句後必須是空行。
  2. 在不同語義塊之間。
  3. 循環之前和之後一般有空行。

十一、命名太随意

代碼有兩件事情比較頭疼:命名和循環。人如其名,如果不是它幹的活,名字卻是一副道貌岸然,太容易把人帶偏了,一個中國人如果取名叫趙 C,一個女孩子如果取名叫石敢當,第一印象生生地給扭曲了。英語不好的同學,要麼用錯英文單詞,要麼翻詞典,整出一個專八的詞彙,任何人都不認得這個單詞,在 CR 時,還需要打開線上翻譯時的命名,絕對不是好命名。當然如果線上翻譯都翻不出來的時候,那更頭疼。如果表意錯誤,那更要命。

十二、注釋是電影的旁白

電影的旁白:1)資訊量大。2)适時出現。就像 《Star Wars》 裡開始的一段一樣,如果不交代那些背景,可能進入正片是一臉懵逼的。在代碼上不需要寫正确的廢話,名字取得好,自然是自解釋的。在嵌套循環中,或者在複雜條件分支中,往往是需要講明白的。另外,添加業務背景資訊,以及執行頻率,執行條件,甚至維護者注意點,都是注釋的重要理由。識别到哪裡要寫注釋,也是一個對業務的閱讀能力,而不是代碼閱讀能力。

十三、滿天飛的函數式程式設計好嗎?

不好。如果一個 stream 後邊的調用超過 5 個,我覺得你是為了炫耀,因為别人不敢改這段代碼,展現出來你的不可替代性。這種 10 行都是函數式程式設計的方式,就像讓人在水裡憋氣超過 10 分鐘不能換氣一樣難受,有點缺氧的感覺。函數式程式設計調試困難,難于上青天,如果沒有辦法修改調試器的話,那隻有委屈那些喜歡天馬行空寫一串函數式語句的同學了。如下圖,個人反對這種直接 return 一個長鍊路的處理結果:

「後端」Code Review 是苦澀但有意思的修行

文章來源:https://developer.aliyun.com/article/752244

繼續閱讀