Slide 1

Slide 1 text

Go の analysis パッケージで⾃作する リファクタリングツール golang.tokyo #38 株式会社ナレッジワーク 宮⽥聖也(@38tter)

Slide 2

Slide 2 text

© Knowledge Work Inc. 2 • 宮⽥聖也 (38tter) • ソフトウェアエンジニア@ナレッジワーク • Golang, Ruby が好き • 趣味:🍺🍺🍺, ⚽ (󰧹, 󰎼), 🎸, 📷 ⾃⼰紹介

Slide 3

Slide 3 text

© Knowledge Work Inc. リファクタリングは... 3 3 ⼤事

Slide 4

Slide 4 text

© Knowledge Work Inc. ⼀⼝にリファクタリングといっても様々 4 4 ⾮推奨ライブラリの削除 コーディングスタイル変更への追従 安全性向上のための型の変更 可読性向上のための変数名の変更 アーキテクチャ変更による互換性維持 …etc.

Slide 5

Slide 5 text

© Knowledge Work Inc. リファクタリングは... 5 5 必要な⼯数も 1 min から 1 month まで様々 有効な⼿段も当然異なる 先延ばしにしがち

Slide 6

Slide 6 text

© Knowledge Work Inc. リファクタリングは... 6 6 機械的にやりたい ▶ Go の静的解析を活⽤

Slide 7

Slide 7 text

© Knowledge Work Inc. 本発表の⽬的 7 7 Go 標準が提供するリファクタリングツールを知る 各ツールのできること、できないことを押さえる ▶ 使いどころを考える

Slide 8

Slide 8 text

© Knowledge Work Inc. ある条件によって抽出されたコードを、挙動を保ちながら 別のコードに置き換えること 8 本発表での「リファクタ」とは before 
 after 


Slide 9

Slide 9 text

© Knowledge Work Inc. go/analysis 9 9 • https://pkg.go.dev/golang.org/x/tools/go/analysis • モジュール化された静的解析を提供 • コードを実⾏せずに⾏う検査 • 共通のインターフェースで再利⽤性が⾼い • CLI, IDE, Testing Framework などから利⽤ • analysis.Analyzer

Slide 10

Slide 10 text

© Knowledge Work Inc. go/ast 10 10 • https://pkg.go.dev/golang.org/x/tools/go/ast • AST (抽象構⽂⽊) • ソースコードを⽊構造で表現したもの • コード中の字句の意味(式、⽂、宣⾔)や、 ファイル上の位置、親⼦関係を取得可能

Slide 11

Slide 11 text

© Knowledge Work Inc. 11 analyzer の実装例: コマンドインターフェース singlechecker.Main で単⼀の Analyzer を スタンドアロンなコマンドとして実⾏できる

Slide 12

Slide 12 text

© Knowledge Work Inc. 12 analyzer の実装例: コマンドインターフェース 解析の詳細は Run に記述

Slide 13

Slide 13 text

© Knowledge Work Inc. go/analysis + go/ast によるリファクタの流れ 13 13 字句解析&構⽂解析 AST(抽象構⽂⽊) 取得 AST のノードを巡回 指摘箇所を検出(&修正)

Slide 14

Slide 14 text

© Knowledge Work Inc. 14 analyzer の実装例: コマンドインターフェース 字句解析&構⽂解析 AST(抽象構⽂⽊) 取得 AST のノードを巡回 指摘箇所を検出(&修正) 実装者が AST 取得を意識する必要がない

Slide 15

Slide 15 text

© Knowledge Work Inc. 15 analyzer の実装例: run の内部処理 字句解析&構⽂解析 AST(抽象構⽂⽊) 取得 AST のノードを巡回 指摘箇所を検出(&修正)

Slide 16

Slide 16 text

© Knowledge Work Inc. 16 analyzer の実装例: run の内部処理 字句解析&構⽂解析 AST(抽象構⽂⽊) 取得 AST のノードを巡回 指摘箇所を検出(&修正)

Slide 17

Slide 17 text

© Knowledge Work Inc. 17 ドメインイベントの型変換の実装を差し替えたい go/analysis を使ったリファクタの例

Slide 18

Slide 18 text

© Knowledge Work Inc. 18 ドメインイベントの型変換の実装を差し替えたい go/analysis を使ったリファクタの例

Slide 19

Slide 19 text

© Knowledge Work Inc. 19 単体の場合の差し替えは⼿動でも容易 イベント数が膨⼤(100~)になると困難 go/analysis を使ったリファクタの例

Slide 20

Slide 20 text

© Knowledge Work Inc. 20 go/analysis を使ったリファクタの例 ドメインイベントの型をレシーバに取るメソッド ToActivityEvent を検出し 実装の中⾝({, } の内側)を置き換える

Slide 21

Slide 21 text

© Knowledge Work Inc. 21 analyzer の実装: run の内部処理 字句解析&構⽂解析 AST(抽象構⽂⽊) 取得 AST のノードを巡回 指摘箇所を検出(&修正) ドメインイベントの型をレシーバに取るメソッド 編集箇所はノードの brace の内側 置き換え後のテキスト 任意の内容が書ける

Slide 22

Slide 22 text

© Knowledge Work Inc. go/analysis を使ったリファクタリングは... 22 22 ルールベースで複雑な置き換えが可能 (もちろん、より単純なことも) …だが、置き換え後の動作は 実装者が保証する必要がある

Slide 23

Slide 23 text

© Knowledge Work Inc. eg - example-based refactoring 23 23 Go 公式のコードリプレイスツール • https://pkg.go.dev/golang.org/x/tools/cmd/eg 式(expression) のリプレイスに限定 • ⽂(statement), 宣⾔(declaration) は指定できない 差分を記述した template を与えて実⾏ • before: 式A, after: 式B と書ける • eg だけに easy (?) リプレイスにともなう import の追加も⾏われる • ただし不要になった import は削除されない • eg 実⾏後に goimports の実⾏が推奨

Slide 24

Slide 24 text

© Knowledge Work Inc. eg: 型安全なコードリプレイス 24 24 置き換え後の式の戻り値の型が⼀致 • func before, func after のシグネチャ (types.Signature) の⼀致が要求される before の式が after の式にアサインできるか検証 • types.AssignableTo

Slide 25

Slide 25 text

© Knowledge Work Inc. eg: 式(expression) のリプレイスに限定 25 25 指摘箇所の検出は ast.Expr の⼀致を検証 • ワイルドカードによる⽐較も可能 expression 以外の statements の指定は(あえて)スコープアウト • `eg --help` でも注意事項として記載

Slide 26

Slide 26 text

© Knowledge Work Inc. まとめ 26 26 • go/analysis + go/ast による静的解析はリファクタツールにも応⽤できる AST ノードの情報により柔軟なコードリプレイスが可能 コードスタイルの変更に伴う修正などの複雑なコンテキストも落とし込める AST の学習コストが⼀定必要となる → fix typo から負債解消のための⼤規模なリファクタリング PJ まで • eg では型安全なリファクタが可能 expression に限定される テンプレートファイルベースで、チーム内共有も容易 学習コストは少ない → ⾮推奨なライブラリの置き換えや、コーディングスタイルの強制など