Go deadcode:查找没意义的死代码,对于维护项目挺有用!

大家好,我是煎鱼。

还记得我前两年在深圳参加了个技术大会,其中一个议题是携程的一个大佬分享他在日常工作中,发现一大堆过时的无意义代码和逻辑,导致大家工作较为繁琐且较为辛苦的情况。

携程应该是 Java 应用为主,他基于 Java 各种研究,通过 JVM 内参数结合各种手段找到了无意义的死代码,并通过灰度机制等完成了逐步上线和替换。

最近 Go 官方也终于有了类似的工具,今天分享给大家,可以持续关注!

用 deadcode 检测代码

普遍来讲,作为 Go 项目源代码一部分,但在任何执行过程中都无法触及的函数被称为 "死代码",它们会拖累代码库的维护工作。

也会造成程序员在阅读代码时的认知负担,看了半天发现这代码根本没用。或是莫名其妙就被引入模块依赖里里。尴尬得很。

现在我们可以用 deadcode 来识别他。安装方式如下:

shell 复制代码
$ go install golang.org/x/tools/cmd/deadcode@latest
$ deadcode -help
The deadcode command reports unreachable functions in Go programs.

Usage: deadcode [flags] package...

以下是一个简单 Demo:

go 复制代码
func main() {
	var g Greeter
	g = Helloer{}
	g.Greet()
}

type Greeter interface{ Greet() }

type Helloer struct{}
type Goodbyer struct{}

var _ Greeter = Helloer{}
var _ Greeter = Goodbyer{}

func (Helloer) Greet()  { hello() }
func (Goodbyer) Greet() { goodbye() }

func hello()   { fmt.Println("你好,煎鱼!") }
func goodbye() { fmt.Println("再见,煎鱼!") }

运行结果:

go 复制代码
$ go run main.go
你好,煎鱼!

咋一眼一看,可能没法知道是哪块代码没用到。还需要多看两眼。

这时候我们只需要借助 deadcode 工具去扫描,一下子就能得到结果了。

执行如下命令并查看输出结果:

go 复制代码
$ deadcode .
main.go:20:17: unreachable func: Goodbyer.Greet
main.go:23:6: unreachable func: goodbye

检测结果告诉我们 goodbye 函数和 Goodbyer.Greet 方法都无法访问。也就是这个代码本身的存在是没有运行意义的。

如果你希望清除这些骚扰代码,就可以依据这个结果去做删除代码了。

同时也可以借助命令的子选项 -whylive,让检测工具给我们解释为什么 greet.hello 函数是有效的。

如下解释结果:

go 复制代码
$ deadcode -whylive=example.com/greet.hello .
                  example.com/greet.main
dynamic@L0008 --> example.com/greet.Helloer.Greet
 static@L0019 --> example.com/greet.hello
                   example.com/greet.main
  ...

该命令会把 main 开始到函数调用的过程打印出来,作为一种解释。证明这个函数确实是存在使用的。

注意点和发现机制

需要留意的是:deadcode 工具,必须要包含 main 函数。言外之意就是其检测链路是从 main 函数开始的。

否则会产生如下的报错信息:

shell 复制代码
$ deadcode .
deadcode: no main packages

deadcode 工具本身会加载、解析和类型检查指定的包,然后将其转换为类似编译器的中间表示形式。

然后会使用 Rapid Type Analysis(RTA)的算法来建立可达函数集,最初只包括每个主要包的入口点:main 函数和包初始化函数(分配全局变量并调用名为 init 的函数)。

RTA 分析每个可达函数的语句体以收集三种类型的信息:直接调用的函数集合、通过接口方法进行的动态调用集合以及转换为接口的类型集合。

因此他必须依赖 main 函数作为主入口来做调用链路分析。当然了,这也是相对正常的。总得有个 "客户端" 来做开始逻辑。

我们可以定期在 Go 项目上运行 deadcode 命令(特别是在重构工作之后),以帮助识别程序中不再需要的部分。

但需要留意的是,deadcode 工具还是在发展阶段。复杂场景下,可能无法保证 100% 的准确率,我们最好还是要自己做一遍 double check 和灰度上线。

总结

今天基于官方的《Finding unreachable functions with deadcode》给大家分享了 deadcode 工具的使用和机制。

整体上来讲,还是非常乐见这个工具的诞生和发展的。历史项目维护旧了,很多地方删删改改,堆积久了后,确实会给大家开发造成不少的认知负担和维护成本。

文章持续更新,可以微信搜【脑子进煎鱼了】阅读,本文 GitHub github.com/eddycjy/blo... 已收录,学习 Go 语言可以看 Go 学习地图和路线,欢迎 Star 催更。

推荐阅读

相关推荐
煎鱼eddycjy13 小时前
新提案:由迭代器启发的 Go 错误函数处理
go
煎鱼eddycjy14 小时前
Go 语言十五周年!权力交接、回顾与展望
go
不爱说话郭德纲1 天前
聚焦 Go 语言框架,探索创新实践过程
go·编程语言
0x派大星2 天前
【Golang】——Gin 框架中的 API 请求处理与 JSON 数据绑定
开发语言·后端·golang·go·json·gin
IT书架3 天前
golang高频面试真题
面试·go
郝同学的测开笔记3 天前
云原生探索系列(十四):Go 语言panic、defer以及recover函数
后端·云原生·go
秋落风声3 天前
【滑动窗口入门篇】
java·算法·leetcode·go·哈希表
0x派大星5 天前
【Golang】——Gin 框架中的模板渲染详解
开发语言·后端·golang·go·gin
0x派大星6 天前
【Golang】——Gin 框架中的表单处理与数据绑定
开发语言·后端·golang·go·gin
三里清风_7 天前
如何使用Casbin设计后台权限管理系统
golang·go·casbin