Slide 1

Slide 1 text

© 2026 ANDPAD All Rights Reserved. Copyright © 2026 Present ANDPAD Inc. This information is confidential and was prepared by ANDPAD Inc. for the use of our client. It is not to be relied on by and 3rd party. Proprietary & Confidential 無断転載・無断複製の禁止 2026.02.21 @Go Conference mini 2026 in Sendai Narumi Koki(@sunecosuri)/ 株式会社アンドパッド Go 1.26 で生まれ変わった go fix をプロダクト開発の運用に乗せる 
 


Slide 2

Slide 2 text

© 2026 ANDPAD All Rights Reserved. ● 2022年12月 アンドパッドに入社 ● 社内外を含んだ承認フローを管理するプロダクトの開発・運用に従事 ● 約6年ぶり(?)に Go を書いています Koki Narumi / @sunecosuri 開発本部 Software Engineer Profile | プロフィール 自己紹介 2

Slide 3

Slide 3 text

© 2026 ANDPAD All Rights Reserved. Confidential 現場の効率化から経営改善まで一元管理できる クラウド型建設プロジェクト管理サービス 社 内 社 外 営業 / 監督 / 設計 事務 / 管理職 職人 / 業者 メーカー / 流通 案件管理 資料承認 工程表 写真 報告 チャット 黒板 図面 受発注 ● ● ● 
 ANDPADとは 3

Slide 4

Slide 4 text

© 2026 ANDPAD All Rights Reserved. Confidential ANDPAD の Go 4 Go を間接的に使っているプロダクト のプロダクト Go がメインのプロダクト 施工管理 図面 引合粗利管理 検査 黒板 受発注 ボード 資料承認 おうちノート … 歩掛管理 請求管理 入退場管理 遠隔臨場

Slide 5

Slide 5 text

© 2026 ANDPAD All Rights Reserved. Confidential このセッションで得られるもの 5 1. go fix をチームに導入する際の 判断軸 2. go fix にまつわる 3つのアプローチの 使い分け 3. 自作 fix ツールへの 第一歩

Slide 6

Slide 6 text

© 2026 ANDPAD All Rights Reserved. Confidential go fix の 「復活」 6 Go 1.0 Go 1.1 ~ 1.25 Go 1.26 API 変更の自動 マイグレーション ツールとして登場 ルールが追加されず ほぼ使われなかった modernize アナライザが 組み込まれて復活

Slide 7

Slide 7 text

© 2026 ANDPAD All Rights Reserved. Confidential Go 1.26 の go fix modernizeとは 24のルールに沿って安全にコードをモダン化してくれる 20ルールがデフォルト有効(2026/02/21時点) 7 ルール単位で有効/無効にして段階的な適用も可能 挙動を変えない意図で設計(変わればバグとして対処)

Slide 8

Slide 8 text

© 2026 ANDPAD All Rights Reserved. Confidential modernize: any(Go 1.18) interface{} → any エイリアスに置換 8

Slide 9

Slide 9 text

© 2026 ANDPAD All Rights Reserved. Confidential modernize: rangeint(Go 1.22) for ループ → for range n に置換 ただし、ループ変数と上限値がループ本体内で変更されていない場合のみ 9

Slide 10

Slide 10 text

© 2026 ANDPAD All Rights Reserved. Confidential modernize: forvar(Go 1.22) ループ変数の冗長な x := x 再宣言を削除 range ループ内にのみ適用 10

Slide 11

Slide 11 text

© 2026 ANDPAD All Rights Reserved. Confidential modernize: slicescontains(Go 1.21) ループで要素探索 → slices.Contains に置換 11

Slide 12

Slide 12 text

© 2026 ANDPAD All Rights Reserved. Confidential modernize: waitgroup(Go 1.25) wg.Add(1) + go func + defer wg.Done() の組み合わせを wg.Go に置換 12

Slide 13

Slide 13 text

© 2026 ANDPAD All Rights Reserved. Confidential modernize: minmax(Go 1.21) if/else による比較 → 組み込み min() / max() に置換 ※浮動小数点型は NaN の扱いが異なるため置換されない 13

Slide 14

Slide 14 text

© 2026 ANDPAD All Rights Reserved. Confidential modernize: mapsloop(Go 1.23) map のループコピー → maps.Copy に置換 14

Slide 15

Slide 15 text

© 2026 ANDPAD All Rights Reserved. Confidential modernize: fmtappendf(Go 1.19) []byte(fmt.Sprintf(...)) → fmt.Appendf(nil, ...) で中間文字列の 割り当てを回避 15

Slide 16

Slide 16 text

© 2026 ANDPAD All Rights Reserved. Confidential modernize: newexpr(Go 1.26) ポインタヘルパー関数 → new(expr) に置換 ptrOf / toPtr のようなヘルパー関数を定義するパターンが不要になる 16

Slide 17

Slide 17 text

© 2026 ANDPAD All Rights Reserved. Confidential modernize: omitzero(Go 1.24) struct フィールドの omitempty → omitzero に置換 17

Slide 18

Slide 18 text

© 2026 ANDPAD All Rights Reserved. Confidential modernize: plusbuild(Go 1.18) 旧式 //+build コメントを除去(//go:build のみ残す) 18

Slide 19

Slide 19 text

© 2026 ANDPAD All Rights Reserved. Confidential modernize: reflecttypefor(Go 1.22) reflect.TypeOf((*T)(nil)).Elem() → reflect.TypeFor[T]() に置換 19

Slide 20

Slide 20 text

© 2026 ANDPAD All Rights Reserved. Confidential modernize: slicessort(Go 1.21) sort.Slice → slices.Sort に置換 20

Slide 21

Slide 21 text

© 2026 ANDPAD All Rights Reserved. Confidential modernize: stditerators(Go 1.23) Len/At スタイルのループ → イテレータに置換 21

Slide 22

Slide 22 text

© 2026 ANDPAD All Rights Reserved. Confidential modernize: stringscut(Go 1.18) strings.Index + スライス → strings.Cut に置換 22

Slide 23

Slide 23 text

© 2026 ANDPAD All Rights Reserved. Confidential modernize: stringscutprefix(Go 1.20) HasPrefix + TrimPrefix → strings.CutPrefix に置換 23

Slide 24

Slide 24 text

© 2026 ANDPAD All Rights Reserved. Confidential modernize: stringsseq(Go 1.24) strings.Split のループ → strings.SplitSeq に置換 24

Slide 25

Slide 25 text

© 2026 ANDPAD All Rights Reserved. Confidential modernize: stringsbuilder(Go 1.10) ループ内の s += x → strings.Builder に置換 25

Slide 26

Slide 26 text

© 2026 ANDPAD All Rights Reserved. Confidential modernize: testingcontext(Go 1.24) context.WithCancel(context.Background()) → t.Context() に置換 26

Slide 27

Slide 27 text

© 2026 ANDPAD All Rights Reserved. Confidential modernize: unsafefuncs(Go 1.17)⚠ 未登録 unsafe.Pointer のアドレス演算 → unsafe.Add に置換 golang.org/x/tools の最新版のみ検出可能 (2026/2/20時点) 27

Slide 28

Slide 28 text

© 2026 ANDPAD All Rights Reserved. デフォルト無効の4ルール

Slide 29

Slide 29 text

© 2026 ANDPAD All Rights Reserved. Confidential modernize: appendclipped(Go 1.21)⚠ 無効 append を重ねて slice を結合するパターンを slices.Concat / slices.Clone に書き換える 29 無効理由:挙動の不一致(https://go.dev/issue/73557) append([]T{}, x...) → 常に非nil slices.Clone(x)    → 入力が nil なら nil を返す

Slide 30

Slide 30 text

© 2026 ANDPAD All Rights Reserved. Confidential modernize: bloop(Go 1.24)⚠ 無効 ベンチマークの b.N ループ → b.Loop() に置換 30 無効理由:ベンチマークがハングする場合がある (https://go.dev/issue/74967) b.StopTimer() / b.StartTimer() との組み合わせで 10分以上タイムアウト

Slide 31

Slide 31 text

© 2026 ANDPAD All Rights Reserved. Confidential modernize: slicesdelete(Go 1.21)⚠ 無効 append(s[:i], s[j:]...) → slices.Delete に置換 31 無効理由:ゼロクリアで panic する場合がある(https://go.dev/issue/73686) slices.Delete は余剰要素をゼロ値で埋める → ループ中のポインタ参照で nil panic

Slide 32

Slide 32 text

© 2026 ANDPAD All Rights Reserved. Confidential modernize: errorsastype(Go 1.26)⚠ 未登録 errors.As + 変数宣言 → ジェネリクス版 errors.AsType[T] 32 無効理由:利用可能なアナライザとして登録されていない ※2/17 現在では gopls 内部のみ利用可能

Slide 33

Slide 33 text

© 2026 ANDPAD All Rights Reserved. Confidential go fix は2回実行が推奨 33 公式ブログ[1] より:"it may be worth running go fix more than once; twice is usually enough" 1回目の修正が2回目の修正機会を生む [1] go.dev/blog/gofix

Slide 34

Slide 34 text

© 2026 ANDPAD All Rights Reserved. 実プロダクトでの適用結果

Slide 35

Slide 35 text

© 2026 ANDPAD All Rights Reserved. Confidential 担当プロダクトに go fix を全ルール適用 ● 変更ファイル数: 49ファイル ● 変更箇所数: 218箇所(+150 / -174行) ● 適用されたルール内訳: ○ any 114件 ○ newexpr 90件 ○ slicescontains 9件 ○ plusbuild 2件 ○ stringscut、slicessort、stringsbuilder 各1件 ● 既存テストに影響なし ○ lint, ユニットテスト, 結合テストも含めて全てPASSした → ルールごとの精査が不要 35

Slide 36

Slide 36 text

© 2026 ANDPAD All Rights Reserved. Confidential go fix 適用前後の diff (一部抜粋) 36 newexpr は go fix の2回実行が必要なパターンだった 1回目: // go:fix inline をつけて中身を new(s) に変換 2回目: // 呼び出し元を置き換える 1回目 2回目

Slide 37

Slide 37 text

© 2026 ANDPAD All Rights Reserved. 運用フローの設計

Slide 38

Slide 38 text

© 2026 ANDPAD All Rights Reserved. Confidential 検知と適用を分けて考える 38 選択肢 概要 導入コスト go fix -diff
 差分があれば CI を失敗させる ジョブの追加が必要 golangci-lint modernize linter 既存 lint に統合 + go fix 以上のルール 設定ファイルに 1行追加する 検知(古いコードに気づく) 適用(コードを書き換える) 役割 PR で古い書き方を警告 コードを自動で書き換え 頻度 毎 PR(常時 ON) Go バージョン更新時

Slide 39

Slide 39 text

© 2026 ANDPAD All Rights Reserved. Confidential golangci-lint modernize を採用 ● 既に golangci-lint v2 を CI で利用しているため追加ジョブが不要 ● .golangci.yml に 1行追加するだけ ○ .golancilint.yml にて以下のような変更を含める ● go fix の modernize ルールを同様に検出していることを確認した ● modernize の有無による CI での実行時間の増加は 約 0.5s 程度だった 39

Slide 40

Slide 40 text

© 2026 ANDPAD All Rights Reserved. Confidential 運用フローまとめ 40 Step 1: go fix ./... で既存コードを一括変換(2回実行) Step 2: CI で検知を常時 ON にする ● golangci-lint を使っている → modernize を有効化(設定1行) ● 使っていない → go fix -diff ./... を CI に追加 Step 3: Go バージョン更新のたびに Step 1 を実施 修正は Go バージョン更新時だけ。普段は検知に任せる。  →古いコードが放置されなくなる

Slide 41

Slide 41 text

© 2026 ANDPAD All Rights Reserved. 自作 fix の事例

Slide 42

Slide 42 text

© 2026 ANDPAD All Rights Reserved. Confidential go vet と go fix の関係 共通基盤: どちらも analysis.Analyzer で実装 既存の検出ツールに SuggestedFix を足す → 修正ツールに昇格 go vet go fix 役割 検出(報告のみ) 修正(コードを書き換え) サードパーティ -vettool
 -fixtool(Go 1.26〜) コード変更 しない する(SuggestedFix に基づく) 42

Slide 43

Slide 43 text

© 2026 ANDPAD All Rights Reserved. Confidential dupimport:重複 import を検出するAnalyzer 43

Slide 44

Slide 44 text

© 2026 ANDPAD All Rights Reserved. Confidential SuggestedFix で修正ツールとなる pass.Reportf → pass.Report + SuggestedFix に変更するだけ 
 44

Slide 45

Slide 45 text

© 2026 ANDPAD All Rights Reserved. Confidential SuggestedFix で修正ツールとなる pass.Reportf → pass.Report + SuggestedFix に変更するだけ 
 45 ただし、以下のようなコードに適用すると参照できずにエラーとなる

Slide 46

Slide 46 text

© 2026 ANDPAD All Rights Reserved. Confidential エイリアス参照の書き換え 46 pass.TypesInfo.Uses で alias import の参照先を特定し書き換える

Slide 47

Slide 47 text

© 2026 ANDPAD All Rights Reserved. Confidential SuggestedFix の実行例 47 重複 import の削除 + エイリアス参照の書き換えが一発で完了

Slide 48

Slide 48 text

© 2026 ANDPAD All Rights Reserved. go:fix inline で API 移行を自動化

Slide 49

Slide 49 text

© 2026 ANDPAD All Rights Reserved. Confidential 実装例: 関数・定数のインライン化(提供者側) パッケージ側://go:fix inline を付けるだけ 49

Slide 50

Slide 50 text

© 2026 ANDPAD All Rights Reserved. Confidential 実装例: 関数・定数のインライン化 利用者が go fix を実行すると自動的に展開される 50

Slide 51

Slide 51 text

© 2026 ANDPAD All Rights Reserved. Confidential 今後の展望: pre-commit を使った go fix の自動適用 ● 新規コード: pre-commit hook で変更パッケージに go fix を自動適用 ○ 仮に pre commit を抜けたコードが含まれても、CI で検知できる ● 既存コード: Go のバージョン更新時に `go fix ./...` で全体に一括適用 51

Slide 52

Slide 52 text

© 2026 ANDPAD All Rights Reserved. Confidential まとめ:このセッションで得られたもの 1. go fix をチームに導入する際の判断軸 原則:検知と適用を分離する CI で検知、local で2回適用 適用粒度は変換されるコードの内容に合わせて選ぶ 2. go fix に関する3つのアプローチと使い分け 3. 自作 fix への第一歩 pass.Reportf → pass.Report + SuggestedFix で修正ツールに昇格 アプローチ ユースケース 必要な作業 modernize コードをモダン化 go fix package-name を実行 SuggestedFix カスタムパターン修正 Analyzer に SuggestedFix を追加 go:fix inline API の非推奨化・移行 移行したい関数や変数に対してコメントを追加 52

Slide 53

Slide 53 text

© 2026 ANDPAD All Rights Reserved. Confidential 参考リンク ● Go 1.26 Release Notes ● go fix documentation ● modernize documentation ● golangci-lint modernize ● 16. 静的解析とコード生成 ● dupimport SuggestedFix PR 53