以下文章來源於一艘慢船 ,作者JayL,原文連結:https://mp.weixin.qq.com/s/5N8KIz-UXvTC_B21mdIp8A
1. Awesome-Go 項目
參與過awesome-go項目的gopher都知道,每個MR都必須滿足它以下的要求:
Make sure that you've checked the boxes below before you submit PR:
I have added my package in alphabetical order.
I have an appropriate description with correct grammar.
I know that this package was not listed before.
I have added godoc link to the repo and to my pull request.
I have added coverage service link to the repo and to my pull request.
I have added goreportcard link to the repo and to my pull request.
I have read Contribution guidelines, maintainers note and Quality standard.
總結出來,就是兩項關鍵質量指標:
- 靜態代碼質量評分https://goreportcard.com
- 測試代碼的覆蓋率https://coveralls.io
這兩項指標都通過量化的數值對合併項目進行審查。只有滿足了指標的閥值要求,你提及的MR才會被合進awesome-go的主分支。
以下是我的兩個合併進主分支的項目:
- JOB, make your short-term command as long-term job
- go routine control with context, support: Main, Go, Pool and some useful Executors
代碼審查 Code Review,程式設計師本能就是抵制的。我也不列外,但是很多事即使開始抵制,一旦嘗試過,就再也停不下來。代碼審查Code Review屬此類。
通過參與awesome-go項目和實際的Code Review實踐,可以得出:一個 Go 項目的優劣至少在編譯期就可以作出初步判斷,而判斷標準就是以下兩項:
- 靜態代碼審查的通過率
- 單元測試的代碼覆蓋率
2. 企業Go項目代碼審查
同樣在企業內部也遇到相同的問題,面對開發人員能力水平的參差不齊以及各種Freestyle的代碼風格, 大大增加了企業 Go 項目的維護難度。指定一套標準規範,同時將其固化到 CI 過程,是非常必要的。
在awesome-go項目中採用的是開源的代碼審查項目與集成服務,但這些服務僅用於開源項目。要移植到企業內部,需要一些必要的準備工作。分別找出靜態代碼審查的通過率與單元測試的代碼覆蓋率替代方案。
2.1 代碼審查神器:golangci-lint
通過收集篩選,靜態代碼審查工具選擇golangci-lint項目。該項目的使用者包括了眾多國際大廠:google、facebook、 IBM 等等。其可用性已經被充分的驗證過了。
2.1.1 審查分類
在golangci-lint中,它內置了絕大部分Go項目需要使用的審查工具。以下就其內置工具做一下簡單的分類。分類能夠幫助我們快速定製出必要的審查工具,哪些是必要的,哪些是可選的一目了然。
該分類,還可以通過以下命令查詢:
$: golangci-lint help linters...##內置Linters分類Linters presets:bugs: bodyclose, errcheck, gosec, govet, scopelint, staticcheck, typecheckcomplexity: gocyclo, nakedretformat: gofmt, goimportsperformance: bodyclose, maligned, preallocstyle: depguard, dupl, gochecknoglobals, gochecknoinits, goconst, gocritic, golint, gosimple, interfacer, lll, misspell, stylecheck, unconvertunused: deadcode, ineffassign, structcheck, unparam, unused, varcheck
更詳細的工具使用說明,可以直接跳轉到對應的項目頁進行查詢。
代碼BUG審查
- bodyclose - checks whether HTTP response body is closed successfully
- errcheck - Errcheck is a program for checking for unchecked errors in go programs. These unchecked errors can be critical bugs in some cases
- gosec - Inspects source code for security problems
- govet - Vet examines Go source code and reports suspicious constructs, such as Printf calls whose arguments do not align with the format string
- scopelint - Scopelint checks for unpinned variables in go programs
- staticcheck - Staticcheck is a go vet on steroids, applying a ton of static analysis checks
- typecheck - Like the front-end of a Go compiler, parses and type-checks Go code
代碼複雜度
- gocyclo - Computes and checks the cyclomatic complexity of functions
- nakedret - Finds naked returns in functions greater than a specified function length
代碼格式化
- gofmt - Gofmt checks whether code was gofmt-ed. By default this tool runs with -s option to check for code simplification
- goimports - Goimports does everything that gofmt does. Additionally it checks unused imports
代碼性能審查
- bodyclose - checks whether HTTP response body is closed successfully
- maligned - Tool to detect Go structs that would take less memory if their fields were sorted
- prealloc - Finds slice declarations that could potentially be preallocated
代碼風格審查
- golint - Golint differs from gofmt. Gofmt reformats Go source code, whereas golint prints out style mistakes
- stylecheck - Stylecheck is a replacement for golint
- interfacer - Linter that suggests narrower interface types
- unconvert - Remove unnecessary type conversions
- dupl - Tool for code clone detection
- goconst - Finds repeated strings that could be replaced by a constant
- depguard - Go linter that checks if package imports are in a list of acceptable packages
- misspell - Finds commonly misspelled English words in comments
- lll - Reports long lines
- gosimple - Linter for Go source code that specializes in simplifying a code
- gocritic - The most opinionated Go source code linter
- gochecknoinits - Checks that no init functions are present in Go code
- gochecknoglobals - Checks that no globals are present in Go code
無用代碼審查
- deadcode - Finds unused code
- ineffassign - Detects when assignments to existing variables are not used
- structcheck - Finds unused struct fields
- unparam - Reports unused function parameters
- unused - Checks Go code for unused constants, variables, functions and types
- varcheck - Finds unused global variables and constants
2.1.2 推薦配置
按linter具體功能分類,在進行ci的過程中, 配置如下:
- 代碼BUG
- 代碼複雜度
- 代碼格式化
- 代碼性能
- 代碼風格
- 無用代碼
勾選是必選項,非勾選按實際情況進行配置。具體如何配置,可以參考 .golangci.example.yml。
配置好配置文件後,確認配置,通過以下命令查詢當前項目配置.
# 項目目錄下查詢具體啟用的linters設置$: golangci-lint linters
golangci-lint配置文件的查詢規則是:從當前目錄,逐次向上級目錄查詢。
2.1.3 CI集成
集成到企業 Go 項目的 CI 中就很簡單,在每個項目的構建過程中,增加以下命令即可:
# 項目目錄下$: golangci-lint run
2.2 測試覆蓋率審查
完成了靜態代碼審查的準備工作,現在看看測試代碼覆蓋率的方案。
2.2.1 Go項目測試覆蓋率
在 Go 1.2 版本就已經提供了代碼測試覆蓋率的工具。具體操作如下:
# 項目整體測試覆蓋率, 以 github.com/x-mod/routine 項目為例$: go test -cover github.com/x-mod/routine | awk '{print $4 " " $5}'coverage: 83.0%
具體測試覆蓋率詳細信息,可以通過命令行的方式也可以通過網頁的方式查看,按https://dave.cheney.net提供的腳本,簡單修改後如下:
# 測試覆蓋率詳情cover () { t=$(mktemp) go test $COVERFLAGS -coverprofile=$t $@ && go tool cover -func=$t && unlink $t}# 測試覆蓋率詳情 web方式查看cover-web() { t=$(mktemp) go test $COVERFLAGS -coverprofile=$t $@ && go tool cover -html=$t && unlink $t}
具體測試覆蓋率詳情cover-web github.com/x-mod/routine, 效果如圖:
命令行效果,讀者可以自己測試一下 cover github.com/x-mod/routine 。
2.2.3 CI集成
如何集成到 CI 流程,也很簡單了,只需要做一件事: 設置好測試覆蓋率的通過值,比對項目的測試覆蓋率的值。簡單提供一下取值的腳本函數:
cover-value(){ go test -cover $@ | awk '{print $5}' | awk -F. '{print $1}'}
具體比較過程,以及參數配置等過程就交給讀者了。
3 參考連結
- awesome-go
- golangci-lint
- Simple test coverage with Go 1.2