
2025年9月27日(土)から9月28日(日)にかけて開催される「Go Conference 2025」に、石上敬祐、黒田尚輝、久保大貴、唐木稜生、山﨑正大朗、鈴木稜太朗が登壇いたします。なお、サイバーエージェントは今年も会場スポンサーを務めます。カンファレンス開催中は当社スポンサーブースを設置し、特別企画や限定ノベルティを用意してお待ちしております。参加予定の方々は、ぜひサイバーエージェントブースまでお立ち寄りくださいませ。
Go Conference 2025
Go Conference はプログラミング言語 ”Go”ユーザーのためのカンファレンスです。
登壇について
・発表タイトル
Swiss Table の実装に Deep Dive !
・登壇者
株式会社AJA 石上敬祐
・日時
9月28日(日) 15:30 - 15:50 | Room 2
・詳細
Go 1.24では、mapの内部実装がSwiss Tableベースに変更されました。本セッションでは、この新しい実装を実際のソースコードとともに詳細に議論していきます。
Swiss Tableはグループ単位でのSIMD並列処理を活用したアプローチです。ハッシュ値をH1(上位57ビット)とH2(下位7ビット)に分割し、H2を使って8つのスロットを並列でマッチングする仕組みを、実際のコードを見ながら議論します。特にctrlGroup.matchH2メソッドでの興味深いビット操作テクニックには目を見張るものがあります。
https://github.com/golang/go/blob/53af292aed21c3f6ea75d16e5b25f660b2c028fb/src/internal/runtime/maps/group.go#L157-L172
Go特有の要件がどのように実装に反映されているかについても議論していきます。8要素以下の小さなmapでは、テーブル構造を使わずに単一グループで直接管理するSmall Map最適化、
https://github.com/golang/go/blob/53af292aed21c3f6ea75d16e5b25f660b2c028fb/src/internal/runtime/maps/map.go#L267-L283
マップが実際に使用されるまで領域確保を遅延する設計、XORによるトグルを使った並行アクセス検出など、
https://github.com/golang/go/blob/53af292aed21c3f6ea75d16e5b25f660b2c028fb/src/internal/runtime/maps/map.go#L489-L491
実用的な最適化が随所に見られます。また、Go言語仕様の「イテレーション中でもmap変更を許可する」というセマンティクスに対応するため、古いテーブルへの参照を保持し続ける複雑な実装についても詳しく解説します。
さらに、Extendible Hashingによる段階的成長戦略を取り上げます。map全体を一度に再構築するのではなく、個別のテーブルを分割して成長させることで、大きなmapでのパフォーマンス劣化を防ぐ設計です。globalDepthとlocalDepthを使ったディレクトリ管理の仕組みや、テーブル分割時の複雑な処理を、実際のinstallTableSplitメソッドを追いながら理解していきます。
https://github.com/golang/go/blob/53af292aed21c3f6ea75d16e5b25f660b2c028fb/src/internal/runtime/maps/map.go#L359-L391
本セッションを通じてSwiss Tableへの理解と、それがどのように実装されているかを知る機会を提供できたらと思います。
=====================
・発表タイトル
サプライチェーン攻撃に学ぶmoduleの仕組みとセキュリティ対策
・登壇者
Developer Productivity室 黒田尚輝
・日時
9月27日(土) 11:10 - 11:30 | Room1
・詳細
2025年2月、Go言語エコシステムで3年間検出されなかった巧妙なサプライチェーン攻撃が発覚しました。github.com/boltdb-go/boltという悪意のあるパッケージが、正規のBoltDB(github.com/boltdb/bolt)をタイポスクワットし、Go Module Proxyのキャッシュメカニズムを悪用していた事件です。
攻撃者はGo Module Proxyの「一度キャッシュされたモジュールは(原則)永続的に利用可能」という特性を悪用し、GitHubのタグを書き換えて痕跡を隠蔽しながら、プロキシ経由では悪意のあるバージョンを配布し続けました。
この事件について調べていくと、Go Moduleの内部動作について多くの発見がありました。go.sum ファイルの役割、Module Proxyとチェックサムデータベースの関係、そしてgo mod verifyやgovulncheckといったツール等です。
これを機に実際にこれらのツールを使用して依存関係の検証を行い、セキュリティ対策として、普段の業務で積極的に使うようになりました。
そこで、この経験を通して、Go Moduleの仕組みを正しく理解し、適切なセキュリティ対策を実装するための実践的な知識をお伝えしたいと思っています。
具体的にはこのセッションで以下の項目についてお話しします。
1. Go Moduleシステムの内部動作とサプライチェーン攻撃の手法
- 悪意のあるBoltDBパッケージの具体的な実装
- go.mod、go.sum、Module Proxyの役割と相互関係
- 攻撃者がどのようにキャッシュメカニズムを悪用したか
2. Go Moduleのセキュリティメカニズム
- チェックサムデータベースによる整合性検証
- 最小バージョン選択(MVS)の仕組みとセキュリティへの影響
- Module Proxyの動作におけるセキュリティリスク
3. 実践的なセキュリティ対策とツールの使い方
- go mod verify、govulncheckの効果的な使用方法
- 今回のような事件の影響を防ぐ実践的なCI
このセッションは、Go Moduleの仕組みをより深く理解したい方や、Goのセキュリティ対策を強化したい開発者の方に対して特にお話ししたい内容です。
=====================
・発表タイトル
Deep Dive Into testing/synctest
・登壇者
株式会社タップル 久保大貴
・日時
9月27日(土) 13:30 - 13:50 | Room1
・詳細
テスト中に time.Sleep を使って数秒待った経験やそれによりテストが不安定になったり悩まされたことはありませんか?
例えば、「数秒後にキャッシュが期限切れになるか確認したい」といったテストでは、sleep を使うことでCIの実行時間が増えたり、flaky(不安定)になったりする原因になります。
Go 1.24 で実験的に導入された testing/synctest パッケージは、こうした並行処理+時間依存のテストを高速かつ安定して書けるようにするものです。また、Go 1.25のリリースノートでは testing/synctest パッケージは standard library として提供される予定で今後開発者間でも頻繁に使われるであろうものです。
このセッションでは、以下を中心に紹介・解説します:
1: synctest.Run による「バブル(Bubble)」とは何か?
2: 合成時間(synthetic time)の進み方と time.Sleep との連携
3: synctest.Run と synctest.Wait の使いどころ
4: durably blocked とは?
5: synctestの制約
また、具体例を通して、goroutineの同期と合成時間の制御周りを深掘りします。
そして、CI等で発生しやすい flaky テストの再現例と、synctest によってどれほど安定化するかのベンチマーク結果もご紹介したいと思います。
=====================
・発表タイトル
コード生成なしでモック処理を実現!ovechkin-dm/mockioで学ぶメタプログラミング
・登壇者
株式会社QualiArts 唐木稜生
・日時
9月28日(日) 17:30 - 17:50 | Room1
・詳細
本セッションでは、コード生成を必要とせずランタイムでモック処理を実現するovechkin-dm/mockio[1]というライブラリを取り上げ、Go言語におけるメタプログラミングの手法について解説します。
モックライブラリは単体テストにおける強力なツールです。
依存モジュールの振る舞いを一時的に置き換え、対象ロジックのテストを容易にします。
uber-go/mock[2]やmatryer/moq[3]といった既存のGoモックライブラリの多くは、事前のコード生成を前提とした設計になっています。
一方、本セッションで取り扱うmockioは、code1に示す通り、コード生成を一切必要とせずに型安全なモック処理を実現する革新的な手法を採用しています。
mockioの根幹を支えるのがovechkin-dm/go-dyno[4]です。
go-dynoは、インターフェース型を渡すとそれを満たす構造体を動的に生成するDynamic関数を提供します。
さらに、生成された構造体のメソッド呼び出し時に任意の処理を発火させるプロキシ関数(code2のCalculatorHandler参照)を渡すことが可能で、これがモック処理の肝になります。
本セッションでは、go-dynoがどのようにしてインターフェースの型情報から、それを満たす構造体を動的に生成しているのか、メソッドの中身を自由に定義することができるのかを深く掘り下げます。
コード生成なしで型安全なメタプログラミングを実現するテクニックについて、generics, reflect, unsafe, assemblyを活用した内部実装を詳細に解き明かします。
また、mockioのモックライブラリとしての価値にも言及します。
コード生成を行わないモックアプローチの機能的な・パフォーマンス的なメリットと課題について、既存モックライブラリと比較・評価します。
Goのランタイムの理解を深めたい方やモックライブラリ開発に興味がある方にとって、このセッションが有益な情報となれば幸いです。
code1: mockioを活用した単体テスト
```
// main.go
package main
type Calculator interface {
Add(a, b int) int
}
func Sum(calculator Calculator, nums ...int) int {
var result int
for _, num := range nums {
result = calculator.Add(result, num)
}
return result
}
// main_test.go
package main
import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/ovechkin-dm/mockio/v2/mock"
)
func Test_Sum(t *testing.T) {
ctrl := mock.NewMockController(t)
// NOTE: コード生成を行わずにモックを実現
mockCalculator := mock.Mock[Calculator](ctrl)
mock.When(mockCalculator.Add(0, 1)).ThenReturn(1)
mock.When(mockCalculator.Add(1, 2)).ThenReturn(3)
result := Sum(mockCalculator, 1, 2)
assert.Equal(t, 3, result)
mock.Verify(mockCalculator, mock.Times(1)).Add(0, 1)
mock.Verify(mockCalculator, mock.Times(1)).Add(1, 2)
}
```
code2: go-dynoによるメタプログラミング
```
package main
import (
"fmt"
"reflect"
"github.com/ovechkin-dm/go-dyno/pkg/dyno"
)
type Calculator interface {
Add(a, b int) int
Sub(a, b int) int
}
// NOTE: ランタイムで生成される構造体が持つメソッドの振る舞いをプロキシとして定義
func CalculatorHandler(m reflect.Method, values []reflect.Value) []reflect.Value {
fmt.Println("Method called:", m.Name)
switch m.Name {
case "Add":
return []reflect.Value{reflect.ValueOf(int(values[0].Int() + values[1].Int()))}
case "Sub":
return []reflect.Value{reflect.ValueOf(int(values[0].Int() - values[1].Int()))}
}
return nil
}
func main() {
// NOTE: Calculator型を満たす構造体をランタイムで生成
dynamicCalculator, _ := dyno.Dynamic[Calculator](CalculatorHandler)
addResult := dynamicCalculator.Add(2, 1) // Output: Method called: Add
fmt.Println(addResult) // Output: 3
subResult := dynamicCalculator.Sub(2, 1) // Output: Method called: Sub
fmt.Println(subResult) // Output: 1
}
````
[1]: https://github.com/ovechkin-dm/mockio
[2]: https://github.com/uber-go/mock
[3]: https://github.com/matryer/moq
[4]: https://github.com/ovechkin-dm/go-dyno
=====================
・発表タイトル
goplsの拡張によるマイクロサービス間の実装ジャンプ改善
・登壇者
株式会社WinTicket 山﨑正大朗
・日時
9月28日(日) 18:30 - 18:50 | Room1
・詳細
WINTICKETでは、モノレポ環境下でgRPCを用いたマイクロサービスの開発を行っています。機能開発時には、複数のマイクロサービスの実装を修正することがありますが、あるサービスから呼び出したRPCの実装を定義ジャンプで確認しようとしても、実際には自動生成されたinterface定義に飛んでしまい、目的の実装に直接ジャンプできないという課題がありました。そのため、毎回手動で実装を探しに行く必要があり、開発体験が良くありませんでした。 そこで、Go言語のLanguage Serverであるgoplsを拡張し、RPCのinterfaceではなく実装へジャンプできる新しい定義ジャンプ機能を実装しました。これにより開発体験が大きく向上しました。 このセッションでは、具体的なgoplsの拡張方法と、実際にWINTICKETで行っているVS Code拡張機能を活用した運用方法についてお話しします。
=====================
・発表タイトル
なぜGoのジェネリクスはこの形なのか? - Featherweight Goが明かす設計の核心
・登壇者
株式会社QualiArts 鈴木稜太朗
・日時
9月28日(日) 16:00 - 16:20 | Room1
・詳細
Go 1.18でジェネリクスが導入されました。本セッションでは、その仕様、特に「なぜ型制約にinterfaceを使うのか」「なぜコンパイルにモノモーフィゼーションという手法が選ばれたのか」という設計上の選択について、その背景を解説します。
この設計の背景には、Goジェネリクス設計の根幹をなす理論的支柱、Featherweight Goという論文があります。この論文は、Goの父であるRob Pike氏や、Haskellなどで知られる型理論の権威Philip Wadler氏らが参加し、Goのジェネリクスに「理論的な正しさ」を与えるために行われました。この論文で示された理論的な裏付けが、初期案であったcontractsから現在のinterfaceベースの仕様へと繋がりました。
このセッションでは、Featherweight Go論文を基に、Goのジェネリクスの仕組みを深掘りし、以下の点をお話しします。
- interfaceが型制約として採用された経緯(contracts案との比較)
- モノモーフィゼーションの仕組みと、それがもたらす性能上のメリット
- 現在の仕様では実現できない「共変レシーバ」と、それが解決する「式問題」の解説
このセッションを聞くことで、Goのジェネリクスがなぜ現在の仕様になったのかを深く理解し、そのトレードオフを意識した上で、より自信を持ってコードを書けるようになります。