一、前言
作为一名合格的程序员我们都知道代码可读性的重要性,所以会尽量不写出非常复杂的代码,这里面就有很多方法论了,什么分层、抽象、条件前置、依赖前置等等。拿有没有一个标准作为复杂度的衡量依据呢?
这里就要提到一个名词“圈复杂度”,“圈复杂度”是用于表示程序复杂度的软件度量的一种方式。它是通过代码的线性独立路径数量的定量度量。它由Thomas J. McCabe, Sr.于 1976 年开发。
函数的圈复杂度根据以下规则计算:
- 1 is the base complexity of a function
- +1 for each ‘if’, ‘for’, ‘case’, ‘&&’ or ‘||’
对复杂度基本可以分为以下几个级别:
- 1 - 10 程序简单,风险小
- 11 - 20 更复杂,中等风险
- 21 - 50 复杂、高风险
- 50 不可测试的代码,非常高的风险
PS:降低代码复制度和写单元测试一样需要额外的成本,但低复杂度的代码编写单测也会非常容易
PS:推荐代码复杂度控制在15以内会是一个不错的选择
资料汇总:
- Golang复杂度工具:https://github.com/fzipp/gocyclo
二、gocyclo工具使用
使用Gocyclo 工具来计算 Go 项目中函数的圈复杂度。
$ go install github.com/fzipp/gocyclo/cmd/gocyclo@latest
$ gocyclo
Calculate cyclomatic complexities of Go functions.
Usage:
gocyclo [flags] <Go file or directory> ...
Flags:
-over N show functions with complexity > N only and
return exit code 1 if the set is non-empty
-top N show the top N most complex functions only
-avg, -avg-short show the average complexity over all functions;
the short option prints the value without a label
-ignore REGEX exclude files matching the given regular expression
The output fields for each line are:
<complexity> <package> <function> <file:line:column>
基本用法:
$ gocyclo . # 当前项目所有方法的复杂度拍讯
$ gocyclo main.go # 单个文件复杂度排序
$ gocyclo -top 10 src/ # src 文件下最复杂的10个方法
$ gocyclo -over 25 docker # docker 目录下复杂度大于 25 的方法
$ gocyclo -avg . # 当前项目的平均复杂度
$ gocyclo -top 20 -ignore "_test|pb.go|Godeps|vendor/" . # 忽略部分文件
效果如下:
可以使用gocyclo:ignore指令忽略单个函数:
//gocyclo:ignore
func f1() {
// ...
}
//gocyclo:ignore
var f2 = func() {
// ...
}
三、怎么降低复杂度?
具有较高圈复杂度的函数需要更多的测试用例来覆盖所有可能的路径,并且可能更难理解。最终进过多人之手,各种风格就会变成无法维护的庞然巨物,最终走向重构。
降低复杂度一定不是最终的目的,让程序具备可维护性能够更好的开发迭代,就和俄罗斯方块一样有规则有章法游戏就能一直进行下去。
场景的几种降低复杂度的方法:
- 合理的分层,通过领域划分,将每个域的内容抽象出来,并且形成原子方法,从而实现”高内聚低耦合“
- 降低方法行数进行方法拆分,将大逻辑拆分出逻辑块分而治之
- 利用工具库和封装库对与数据处理等需要大量for if 等数据处理的场景进行封装,比如:go-zero的fx流式处理包和https://github.com/ahmetb/go-linq
本文含有隐藏内容,请 开通VIP 后查看