Slide 1

Slide 1 text

   deadcode超解剖 Go Conference 2024 2024/06/08 kuroda naoki

Slide 2

Slide 2 text

自己紹介 kuro @knkurokuro7 - 名前:kuroda naoki - 所属:株式会社サイバーエージェン トAI事業本部 プリズムパートナーカンパニー - 普段はスクランブルスクエアでただ ただ佇んでいます。

Slide 3

Slide 3 text

deadcodeご存じですか? 「Finding unreachable functions with deadcode」というGo公式のブログでフュー チャーされました。

Slide 4

Slide 4 text

deadcodeとは? - “dead code”と呼ばれる、いかなる実行でも到達できない関数 を検知するツール。 - -whyliveフラグでdeadになっていない理由 も教えてくれる。 (https://pkg.go.dev/golang.org/x/tools/cmd/deadcode#hdr-Why_is_a_function_not_dead_) - Rapid Type Analysis (RTA) というアルゴリズムを使ってい る。

Slide 5

Slide 5 text

golangci-lintで 使ってみたい!

Slide 6

Slide 6 text

実際にissueを見てみると。。。👀 - Add deadcode linter · Issue #4254 - Integrate new deadcode tool · Issue#4270 - Add golang.org/x/tools/cmd/deadcode support · Issue#4298 - Add official go deadcode linter · Issue#4383 →全てclosed

Slide 7

Slide 7 text

なぜ採用されないのか? 理由: 1. unused との比較で、deadcodeの方がより false positive(偽陽性)があるから。 2. deadcodeはcommand lineでありlib(library)ではないか ら。 https://github.com/golangci/golangci-lint/issues/4254#issuecomment-1853840307 https://github.com/golangci/golangci-lint/issues/4254#issuecomment-1856231084

Slide 8

Slide 8 text

false positive (偽陽性)? →検出する必要のないものを誤って検知して しまうこと

Slide 9

Slide 9 text

deadcodeの仕組み RTAで、main()やinit()から始まって、 1. 直接呼び出される関数、2. interfaceを 通して間接的に呼び出される関数を到達 可能としてチェックし、それ以外を deadcodeとする。 2の方法は、“dynamic programming”(動的 計画法)を使う。 English French Greeter ✅ ✅

Slide 10

Slide 10 text

unusedの仕組み(interfaceとメソッド)※かなり省略しています - ASTと型の情報を利用してグラフを構築し、そのグラフを解析するこ とで未使用のコードを特定する。 - AST解析の段階で、 - 具象型がinterfaceを実装するために必要なメソッドは使用され たとする。 →あるメソッドは呼び出されていなくても使用されているとみなされる ことがある。

Slide 11

Slide 11 text

deadcodeを使ってみて - $ deadcode -test ./... inference/inferred_value.go:52:25: unreachable func: DeterminedVal.isInferredVal inference/inferred_value.go:94:27: unreachable func: UndeterminedVal.isInferredVal - 「不要なメソッドだ!」とPR送ったけど、、、 type InferredVal interface { isInferredVal()👈ここと copy() InferredVal } func (e *DeterminedVal) isInferredVal() {}👈ここだけ func (e *DeterminedVal) copy() InferredVal { return &DeterminedVal{Bool: e.Bool} }

Slide 12

Slide 12 text

deadcodeを使ってみて type InferredVal interface { isInferredVal()👈ここと copy() InferredVal } func (e *DeterminedVal) isInferredVal() {}👈ここだけ func (e *DeterminedVal) copy() InferredVal { return &DeterminedVal{Bool: e.Bool} } - 直接使用されていなくても、isInferredVal() メソッドをInferredVal interfaceに残 しておく。すると、意図した構造体(ここではDeterminedVal)だけが InferredVal interfaceを実装できる。 →意図しないバグを防ぐ。 - Goの実装でも使われている。👇 https://cs.opensource.google/go/go/+/refs/tags/go1.21.6:src/go/ast/ast.go;l=40

Slide 13

Slide 13 text

まとめ - deadcodeはコマンドライン、unusedはライブラ リ。 - deadcodeは関数、unusedは関数、定数、変 数、型などに使える。 - deadcodeはある特定のケースにおいては、 unusedより偽陽性があると言えるのかも。

Slide 14

Slide 14 text

参考文献 - Finding unreachable functions with deadcode - The Go Programming Language - pkg.go.dev - rta - pkg.go.dev - deadcode - GitHub - golangci/golangci-lint: Fast linters runner for Go - GitHub - dominikh/go-tools/unused: Staticcheck  - The advanced Go linter