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 催更。

推荐阅读

相关推荐
Pandaconda2 小时前
【Golang 面试题】每日 3 题(五十)
开发语言·经验分享·笔记·后端·面试·golang·go
魔法小匠2 小时前
Go 模块化开发入门(go mod 深度解析)
服务器·golang·go·模块化·go mod
王中阳Go21 小时前
Go框架面试突击!30道高频题解析
go
喵个咪3 天前
开箱即用的GO后台管理系统 Kratos Admin - 前端权限
前端·vue.js·go
WenTai_12044 天前
upx压缩工具使用说明
linux·go
kld2305 天前
Jenkins 使用教程:从入门到精通
git·go·jenkins
卜及中6 天前
【Go语言快速上手】第一部分:Go 语言基础
运维·开发语言·学习·golang·go
gopher_looklook6 天前
深度讲解Go源码-sync.WaitGroup
后端·go·源码
陈墨6 天前
es官方go客户端创建ik索引并进行查询操作
后端·go