如何提高代碼質量

何謂代碼質量?

代碼是給人看的

1. 書寫規範:遵守本身公司制定的編程語言書寫規範。
2. 易閱讀。
3. 易修改。
4. 易測試。git

代碼是給機器運行的

1. 安全
2. 快速
3. 穩定web

代碼質量的標準?

對於機器來講,標準是恆定的,但不可兼得。

好比:編程

  • 鎖機制:安全

    • 安全、慢
  • 指針:數據結構

    • 快、不穩定
  • 改內存地址:app

    • 快、不安全

總的來講,這就像 CAP 理論同樣,不一樣場景下的需求不同,根據當下業務需求去作出取捨便可。編程語言

對於人來講,標準是變化的,由於習慣不一樣、工期不一樣、目的不一樣。

易閱讀

表意明確

名詞要準確

類、結構體、變量、常量等名詞要能直觀地描述這是個什麼東西,通常 1-5 個單詞組成爲宜。函數

英文單詞裏沒有官方縮寫的就儘可能不用縮寫,像 result 就 6 個字母,也有人給縮寫成 res、ret,temp 縮寫成 tmp,更有甚者寫 cnt,它究竟是 count 仍是 content 呢?除了歧義,徹底沒有任何好處。性能

動詞要精簡

方法名、函數名等動詞要能保證只作一件事。一個方法不寫太長的前提是它的功能自己就很少。單元測試

形容詞要歸約

屬性、校驗等形容詞要歸約爲方法,業務邏輯關鍵點大多在判斷上,預留擴展點會讓閱讀難度不隨着加需求而快速增大。

單詞統一

不要有歧義,由於人是有思惟慣性的,好比一樣的業務邏輯,有的寫 add,有的寫 append,有的寫 insert,會嚴重影響閱讀效率。

描述業務

有意義的名字要專一於描述業務,使讀者經過閱讀代碼理解業務邏輯。不要在起名中摻雜數據結構。

例如這麼幾個場景:列表(集合)、配置映射

  • good case:users(用戶集合),articles(文章列表)、siteNameToSiteId(映射)
  • bad case:userSet、articleList、siteMap

加上類型,並不會對理解業務邏輯有幫助,讀者看到 list,map 這些關鍵詞還會聯想到數據結構中,很容易打斷思惟。

避免贅述

具備包含關係或從屬關係的時候,不要重複,不要表達累贅的語境。

關注做用域和生命週期

當一個變量的做用域很窄,或生命週期很短的時候,能夠用單字母命名,通常來說,單字母意味着臨時使用,讀者在瞭解邏輯的時候能夠不用關注這部分。

變量要接近使用的地方聲明,不要開頭聲明一堆變量,隔幾十行才使用。

寫有用的註釋

「好的代碼是自描述的」 即讀代碼就和讀文章同樣。註釋不該該用來解釋代碼邏輯,而應該是用來講明爲何這麼寫。

寫什麼樣的註釋

  1. 公共的、全局的變量和常量:說明用在哪,提供給誰用。
  2. 函數,方法:說明函數功能是什麼。
  3. 行註釋:xx 產品在 x 年 x 月 x 日提出什麼需求,作此修改。

註釋不是用來刪代碼的!!!

代碼不用了就完全刪除,怕之後還有用就從 git 裏找回來,若是一個函數 100 行,其中 50 行都被註釋掉了,這種會很容易分散讀者的注意力。

易修改

一值一用

不要把一個變量重複賦值使用。雖然類型同樣,但這樣作會讓修改的人很是頭疼,所謂牽一髮而動全身。例如:

  • bad case:

result, err := a.Get()
result, err = b.Get()

  • good case:

resultA, err := a.Get()
resultB, err = b.Get()

少寫參數

當你發現一個函數的功能須要傳入七八個參數才能完成的時候,必定是函數乾的事太多了,邏輯寫太長了。須要適當拆分。

正確使用邏輯運算符

&&、||、!這些邏輯運算符是用來作邏輯判斷的,不是用來控制執行流程的。

例如這樣一段邏輯:

if (isA()) {
    doB()
}

不要寫成 isA() && doB(),儘管結果是同樣的。

適當化簡

if ((condition1() && condition2()) || !condition1()) {
    return true
}
return false

取反後化簡爲:

if(condition1() && !condition2()) {
    return false
}
return true

下降圈複雜度

圈複雜度的定義:https://zh.wikipedia.org/wiki/循環複雜度

增長圈複雜度的關鍵詞:

if、else、while、for、case、||、&& 等

圈複雜度的合格標準:

大部分標準在 10-20 之間。
這也是一個平均值,不是要求每個函數都在 20 如下。
個別超標,是能夠接受的。

如何下降

1. 提煉函數
2. 抽象配置,使用 map
3. 合併返回值相同的函數

多寫函數少寫變量

實現一樣的功能,並非代碼越少越好。

由於代碼越少每每意味着耦合度越高,修改擴展起來會更麻煩,就是爽了本身,給別人留坑。

可是,每一行代碼都要有價值。

若是說邏輯節點之間須要一個東西來充當橋樑,變量就是獨木橋,函數像隧道。
防槓精:有人說要考慮性能開銷啊,多寫一個函數比一個棧內的變量開銷大啊,我以爲業務代碼不差這一星半點的,自行斟酌。

易測試

TDD

測試驅動開發:寫一個函數以前先考慮寫出來以後能不能測試,好很差測試。

實現方式

1

第一步:先寫單元測試。沒必要關心如何實現函數功能。

第二步:寫目標函數,以恰好能經過單元測試的邏輯代碼爲目的。

第三步:重構函數,合理命名,優化結構,抽象設計。

如此循環,保證每次改動代碼都能無缺地經過全部測試用例。

這樣作的目的是讓錯誤儘早的暴露出來,在 10 行代碼中解決 bug 要比在 100 行代碼中解決 bug 更加容易和快速。

理想與現實

看起來 TDD 的理論和可操做性還不錯,但實際開發中,若是真的嚴格按照此理論去開發。對開發效率是一個比較大的影響。
並且一旦造成慣性思惟和盲從依賴,會下降對代碼的靈感和熟練度。
測試用例跑過了就沒問題了嗎?不必定。由於測試用例也是人寫的,隱藏的坑才最致命。
其實,當作到易閱讀和易修改以後,易測試就是水到渠成的事情。

IoC 模式

將對象、接口、非固定值(如系統時間、隨機數)等做爲依賴注入,先構造條件,再執行函數。而不是由函數內部去構造。

全局變量單一寫入方

當有兩個以上的函數控制同一個全局變量的時候,會相互影響,即局部造成了一個狀態機,使測試難度陡升。

封裝外部依賴

有外部依賴的,尤爲涉及 IO 通訊的,要單獨封裝,哪怕只有幾行代碼也要封裝成一個獨立的函數,不要把對外部依賴的調用混合在自身的邏輯代碼中。

最後

閱讀 → 修改 → 測試

這是一個遞進的關係,環環相扣,而且前一步作好了都能有利於後一步的完善。

相關文章
相關標籤/搜索