過年回來後開始接手管理一個技術團隊,這個團隊去年一年基本上都在趕項目,晚上常常加班到晚上十點之後,因此代碼質量不用多說你們也能想獲得。前幾天跟你們開會,我提出來從下個版本開始要作code review,有個同窗問到「那不會浪費不少時間嗎?」,我告訴你們「會花不少時間,但不會浪費不少時間」。由於這個團隊裏同窗以前沒作過code review,因此準備下周給你們作一下分享告訴你們應該怎樣作,因而今天花點時間把腦子裏的想法掏出來梳理梳理。性能
作任何事情都要有一個目的,那麼咱們作code review的目的是什麼呢?原本開發工期就很是緊了,特別是身處中國這個大環境下的互聯網公司,老闆巴不得要你二十四小時連軸轉,爲何還要花那麼多時間去作code review呢?我認爲code review的目的在於提高代碼質量。單元測試
前幾天看了篇文章,裏面有這麼一段對我觸動很大:測試
在這種業務需求緊張的模式下,Facebook一些開源技術方案是如何產出的,是非業務團隊專門作的麼?
我想說的是即便業務需求緊張,也同樣把代碼好好寫好,另外有牛逼的tech lead和嚴格的code review,總的質量也不是不好。國內有一點很很差:常常沒有code review;並且技術人員觀念很差,把要寫的代碼當差事,只要能完成能用就好。因此就愈來愈操。
(Code reivew一直是硅谷一線互聯網公司的質量控制法寶,從Apple到Google,從Facebook到如今的Airbnb和Uber。可悲的是,國內的人都太聰明,以爲這東西沒用繁瑣,並且減慢開發速度。有時,咱們就是太過聰明。)編碼
因此咱們不要老是拿沒時間來當作藉口,若是對代碼質量沒有必定的追求,給再多時間也是沒用的。業務需求緊張須要經過提升工做效率來解決,而不是不花精力提升代碼質量。另外,站在一個項目的生命週期來看,寫爛代碼真的會比寫好代碼花的時間更少麼?翻譯
既然作code review的目的是提升代碼質量了,那麼什麼樣的代碼才能算是好的代碼呢?最開始這個標題我寫的是「什麼樣的代碼纔是好代碼?」,後來我想了下這個問題太大,我沒法對「好代碼」簡單的下一個定義,真正討論起來估計得單獨寫一篇文章了,因此先按住這個話題,換成簡單的「好代碼的最重要的特徵是什麼?」。日誌
我覺着好代碼最重要的特徵是可讀性強,這樣才能讓和你協做的同窗以及將來的你本身可以不用想太多就能看得懂,畢竟花在維護代碼上的時間要遠遠超過寫這段代碼花的時間。每新增一行代碼就會多增長一份維護成本,而可讀性強的代碼能夠把維護成本降到最低。code
那麼咱們怎樣來定義這個可讀性強呢?每一個人都有本身的標準,怎樣才能在團隊裏讓你們都承認呢?微博的一位工程師在他寫的《關於爛代碼的那些事》這樣寫到:對象
在不少跟代碼質量有關的書裏都強調了一個觀點:程序首先是給人看的,其次纔是能被機器執行,我也比較認同這個觀點。在評價一段代碼能不能讓人看懂的時候,我習慣讓做者把這段代碼逐字翻譯成中文,試着組成句子,以後把中文句子讀給另外一我的沒有看過這段代碼的人聽,若是另外一我的能聽懂,那麼這段代碼的可讀性基本就合格了。
用這種判斷方式的緣由很簡單:其餘人在理解一段代碼的時候就是這麼作的。閱讀代碼的人會一個詞一個詞的閱讀,推斷這句話的意思,若是僅靠句子沒法理解,那麼就須要聯繫上下文理解這句代碼,若是簡單的聯繫上下文也理解不了,可能還要掌握更多其它部分的細節來幫助推斷。大部分狀況下,理解一句代碼在作什麼須要聯繫的上下文越多,意味着代碼的質量越差。
逐字翻譯的好處是能讓做者能輕易的發現那些只有本身知道的、沒有體如今代碼裏的假設和可讀性陷阱。沒法從字面意義上翻譯出本來意思的代碼大多都是爛代碼,好比「ms表明messageService「,或者「ms.proc()是發消息「,或者「tmp表明當前的文件」。blog
我很承認這個說法,在這個基礎上,我一直堅持認爲雖然一個能把一件事情描述清楚的人寫的代碼不必定可讀性強,可是一個沒法將一件事情描述清楚的人寫出來的代碼可讀性確定不好。生命週期
說了那麼多了,具體怎樣落地到現實工做中呢?即便按照前文所說的把代碼逐字翻譯成中文講給其餘同窗聽,也同樣可能因爲認知問題致使對方聽不懂,好比你認爲很基礎的概念可能別人並不瞭解。因此我認爲你們要遵循一些基本原則,這樣纔能有效的溝通。
3.1 SOLID原則
這是面向對象的五條基本原則,我列在下面,在這裏就不展開來講了
Single responsibility principle
Open/closed principle
Liskov substitution principle
Interface segregation principle
Dependency inversion principle
3.2 Don’t Repeat Yourself
通常對這條原則的理解是對於一樣的功能不要直接copy原來的代碼,而是要抽象出一個公用的方法。可是實際上對一樣的功能用不一樣的思路或者代碼去實現也是一種浪費。好比常見的日誌處理、異常處理邏輯。
3.3 Prefer Composition to Inheritance
這條原則跟前面提到的OOP的SOLID原則裏面的Interface segregation principle有點重合之處。隨着業務需求的不斷迭代,小的組件逐漸會演變成大的組件,在這個過程當中駕馭的難度會逐步提高,而若是在不斷迭代的過程當中不斷抽象出小的組件,則能夠在業務功能複雜的同時保持代碼的簡潔。好比無論是飛機仍是汽車火車都是會移動的,而我在使用時只需知道這個對象是可移動的便可,至於這個對象是飛機仍是汽車我並不關心。
3.4 編碼規範
這個很少說了,能夠採用一些行業裏優秀的編碼規範。可是要注意的一點是規範的做用是保持項目編碼風格的統一,不要在規範上作無心義的爭論。
3.5 若是不具有抽象的能力,那就重複吧
這是一個比較殘酷的也比較常見的現實,看了一大摞的書廢了老大的勁終於抽象出了一個組件,可是最後的結果倒是加大了維護成本。因此若是你覺着沒法很好的去抽象,就直接用最粗魯的重複代碼吧,畢竟這樣別人還能看得懂,比抽象出來後還要再寫一大堆的if else好多了。
在技術以外還有一些要注意的點,首先最重要的就是要有一個開放的心態,review的是代碼,而不是具體的人,不要由於對方的review而感受羞恥,固然也不要進行人身攻擊。
其次,要把握review的粒度,不要一下發起一個很是大的PR,這樣會給review的同窗特別大的壓力。好比一個PR裏最好不要同時既有重構又有新特性的開發,或者憋到最後這個版本都要開發完了才一塊兒提交一個PR。review應該是在平時的工做中持續進行的,而不是相似里程碑的總結之類的東西。
第三,code review不該該承擔發現業務邏輯錯誤的責任,也就是日常咱們所說的bug,bug應該由單元測試、功能測試、性能測試等方法來保證,不要賦予code review太多的責任。