こんにちは。CX開発部サーバーサイドグループで、マネージャーをしている加納です。
少し、期間が空いてしまいましたが、先日、Go Conference 2025が開催され、弊社もスポンサーとしてイベントの盛り上げの一端を担いました。
弊社のGoエンジニアも何名か参戦しましたので、今回はそのエンジニアたちが、気になったセッション等をピックアップして紹介させていただきます。
こんにちは、サーバサイドエンジニアの中川(@tkdev0728)です。
普段の業務でよくGoを書いているのですが知らないことも多く、もっと色々なことを知りたいと思ってGo Conflenceに参加してきました。
学びが多かったのですが今回は特に個人的に興味を持ったセッションについて紹介したいと思います。
概要
コンパイル時にnil参照によるpanicを検知してくれる静的解析ツールnilawayの紹介でした。
注意点としてnilawayは現在開発中であり、誤検知や互換性を破る変更が発生する可能性があります。
興味を持ったきっかけ
Goを書いている人なら一度は意図しないnil参照に遭遇してしまったことはあるのではないでしょうか。もちろん私もその一人です。
意図しないnil参照をしてしまうとpanicが起きてしまうので、リリース前や実装段階で検知したいと思っていました。そのため特にこのセッションが気になって聞いていました。
仕組み
前提としてnil参照を完全に検出することは難しいです。そのため自分もどういう仕組みで実現しているのか興味がありました。
詳しくは発表者の方のスライドに記載されているので詳細は割愛しますが、要約するとnilがどこで生成されてどこにいくのかの伝搬経路を追跡し、nil生成箇所からnil参照箇所までの経路が存在する場合に報告してくれます。
実際に動かしてみた
nilawayの現時点での精度が気になり、実際に弊社のリポジトリでパッケージを絞って実行してみました。
あくまで体感レベルでは確かに誤検知もありましたが実際にnil参照が起きる可能性のある部分も検知できてよかったです。
また、これは個人的な考えにはなりますが、panicになり得る部分を検知してくれることを思うと、見逃しよりも空振りの方がいいと思っています。
claude codeなどを使って除外設定を入れたり、reviewdogを活用して適用範囲をPRの差分に絞るなど工夫することで活用できると感じました。
感想
もっと色々なことを知りたいという漠然とした思いで参加したGo Conflenceでしたが、まさに課題に思っていた部分についてのアプローチとその仕組みについて知れたので最高でした。
と同時に聞くだけじゃなくて実際に動かしてみることの大切さも感じました。
サーバーサイドエンジニアの西村です。Go言語好きな割にGo Conference初参戦でしたが、いろいろ復習したい内容持ち帰れたので、今回その一部を紹介します。
私が気になった内容
https://speakerdeck.com/kaorumuta/go-conference-2025
modernize packageはモダンな書き方に修正してくれたり提案してくれたりするpackageです。最新の記法を随時取り入れると各所で書き方が散らばってくるので、このpackageで書き方を統一できるのかなという期待がありました。なので個人的にあとで復習しようと思ってセッションを聞いていました。
modernize packageとは
https://pkg.go.dev/golang.org/x/tools/gopls/internal/analysis/modernize
modernize パッケージは、gopls(Go公式の言語サーバー)の analysis パッケージ群の中に含まれるアナライザーの1つで、Goコードをよりモダンな構文・APIの書き方に自動修正・提案してくれるツールです。
どう修正してくれるか
具体的にどう修正してくれるかのサンプルコードはslideの9ページにあったものですがこんな感じです。
例えば
これを
s := []string{"A", "B", "C"} for _, v = range s { v := v go func() { fmt.Println(v) }() }
こう
s := []string{"A", "B", "C"} for _, v = range s { go func() { fmt.Println(v) }() } A B C
修正してくれます。
今回のセッションでは、上記のサンプルコードにあるような、for文の要素のポインタを取得する必要なくなったGo1.22からの変更の書き方を修正してくれるアナライザーの一部のforvarコードが解説されていました。
冒頭に「modernize パッケージは、goplsの analysis パッケージ群の中に含まれるアナライザーの1つ」と説明しましたが、
個人的に復習するにあたって参考になったのが、 弊社の技術顧問をしていただいてるtenntennさん の こちらの記事 が参考になりました。
- analysis パッケージは静的解析ツールが抱える問題を解決できる
- 静的解析ツールの多くは、抽象構文木や型情報をソースコードをもとに取得する部分は共通している
- 重複した処理があると複数の静的解析ツールを実行するとその分だけ無駄に時間がかかります。静的解析ツールの実行に時間がかかると、静的解析ツールを実行することが億劫になってしまったり、CIへの導入諦めてしまう可能性がある
- 各静的解析ツールが独自の方式で開発し、それが乱立してしまうと複数の静的解析ツールで同じよう処理をしていたとしても再利用性が低く、うまく使いまわせない。すべてイチから作ることになってしまうと、新たに静的解析ツールを作りたいと考える開発者にとってもハードルが高くなってしまう
また、セッション登壇者の下記の所感にも共感できました。
- 生成AIでコードを書かせているが、学習しているコードは最新のコードではない場合もあるのでそういう場合に役立ちそう
- まだ実行時にpanic起こるというissueも上がっており、正しい変更かは各々で見極めるべき
全体を通してGo Conferenceは結構難しいなという印象でした。
それと同時に復習したいことや、学ぶきっかけもたくさんでき、引き続き精進しようと思いました。
※ 残念ながら公開されている資料を見つけることはできませんでした
こんにちは!サーバーサイドエンジニアの原です。
今年の4月にヤプリへ入社し、プロダクト開発目的としては初めて Go を使い始めたばかりです。
そんな私が Go Conferenceに参加してみて、Go にまつわることからコミュニティの雰囲気まで、実に様々なことを知ることができました。
今回は、数あるセッションの中でも、最初に聴講し、最も印象に残った発表の一つであった「Go1.24で進化したmap型について理解する」について簡単に紹介させていただきます。
概要
このセッションでは、Go 1.24 から変更された map の実装や、従来の実装との違いなどについて紹介されていました。
ポイント
map はハッシュテーブルを使って表現されています。
従来の実装では、内部に 8 つのスロットを持つ Bucket の配列に情報を格納していき、埋まった場合は Overflow Bucket をチェーンさせるような方式で実装されていました。
一方で、Go 1.24 からはオープンアドレス法を用いる Swiss Table による実装に置き換わりました。
新しい実装では、Directory と呼ばれる Table へのポインタの配列によって複数の Table を管理し、各 Table が複数の Group で構成される階層構造になっています。
Group は従来の Bucket に相当するもので、コントロールワードと呼ばれるメタデータを使って、複数のスロットを効率的に検索します。
この変更によって、マイクロベンチマークでは最大 60% の高速化が実現されましたが、map のサイズが小さい場合には、従来の実装の方が効率的なケースもあるようです。
セッションの中では、このような新旧 map の実装方法やそれらの違いなどに関して、図を用いて非常にわかりやすく解説されていました。
感想
このセッションを通じて、改めてアルゴリズムの面白さや重要性を実感することができました。
従来の実装はデータ構造もシンプルで理解しやすかっただけに、新しい手法がいかによく工夫されているかを感じました。
また、数値としての成果もかなり大きく、アルゴリズムの改善が実際のパフォーマンスに与える影響の重要性を再認識することもできました。
セッションでは、ハッシュテーブルのデータ構造や、コントロールワードの役割、実際のデータへのアクセス方法などが図を用いて解説されており、視覚的に理解しやすく、非常に理解しやすい内容でした。
普段から、 map の特性については把握していて、拡張処理ができるだけ発生しないようにすることなどは意識していましたが、このセッションを機に内部実装にも目を向けてみようと思いました。
特に、Go は Go で書かれているので、内部実装を読むことで得られるものは多いのではと考えています。
どうも、SREグループの伊藤(@icchy_san)です。
最近はGo言語を普段の開発では利用していないのですが、これまでGo言語で開発を行ってきた身として、そして現在もGo採用している企業で働いている身として、Go Conference 2025は非常に楽しみにしていました。
今回は数あるセッションの中でも encoding/json/v2を聴講した感想を述べたいと思います。
聴講した背景
v2と改めて表記されると、Go言語とはいえ破壊的変更が含まれるようなアップデートが入っているんじゃないか?と考え、その辺がどのようになっているのかを知りたかった、というのが主な理由です。
概要
encoding/json/v2での個人的に興味を持った部分は以下の通りです。(詳細な部分は発表者のスライドをご確認ください)
- 二層アーキテクチャ(jsontext=構文層、json/v2=意味層)で再設計され、相互に独立して動作するため、高い柔軟性を実現している。
- JSON標準仕様(RFC 8259)に厳格に準拠するようになり、重複キー・UTF-8不正・大文字小文字の区別ができるようになった。
- 互換は高めではあるものの、ゼロ値/omitempty周りに入った変更により若干互換性を保てない部分も出てくる。
GOEXPERIMENT=jsonv2をつけてBuildを行うことで、既存のv1のコードで互換性チェックを実施できる。
感想
手癖のように使っていた encoding/json パッケージですが、本セッションを聞いて初めて知るようなことや、過去に困ったことが対応されていて、 encoding/json/v2を利用することでv1より扱いやすくなりそうだと感じました。
JSONは特殊な操作(Goで別の言語のファイルを生成して、そのままそのファイルを実行するとか)で利用していたことがあり、入力時のバリデーションを Unmarshal 前に行っていたため、重複したフィールドがきた時に後の値が利用される、といったパッケージ特有の仕様は知らなかったです。
また、自分の経験として困ったことのある例として、発表者の方も挙げていますが、omitempty設定をしているフィールドで空の値は無視される仕様で空なのか、渡ってきてないだけなのかの判別ができなかった点です。こちらが、v2からは空値で初期化+JSONに出力されるようになったのは非常にありがたいです。(逆に無視前提の実装をしていた場合に問題が生じる可能性がある点には注意したい。)
実際に手元でも確認してみました。
package main import ( "encoding/json" jsonv2 "encoding/json/v2" "fmt" "os" ) type Test struct { T bool `json:",omitempty"` # Booleanが空の場合にfalseが入る } func main() { t := Test{} m, err := json.Marshal(t) if err != nil { fmt.Fprintln(os.Stderr, err) return } m2, err := jsonv2.Marshal(t) if err != nil { fmt.Fprintln(os.Stderr, err) return } fmt.Printf("v1: %s\n", string(m)) fmt.Printf("v2: %s\n", string(m2)) return } # GOEXPERIMENT=jsonv2 go run main.go # v1: {} # v2: {"T":false}
v1のjson packageの場合は、 omitemptyによって空になっていますが、v2の方は {“T”:false} が返ってきており初期値が入っていることが分かります。
GOEXPERIMENT=jsonv2設定によるencoding/jsonのomitemptyの挙動の違いは発生しませんでしたが、encoding/json/v2を利用する場合は前述のコードの実行結果の通り結果が異なるので、仮にv2のコードが標準化された場合に備えて、テストコード含め検証ができる状態にしておく必要があると思いました。
最後に
とても濃いセッションということもあり、多くの学びのある内容だったのですが詳細については登壇者のスライドを拝見していただきたいと考えています。
v2のコンセプトの話、拡張されたタグの話、そしてみんなが気になるであろうv1とv2のベンチマークの比較などなど載せきれない内容が盛りだくさんなので、ぜひ気になった方は登壇者さんのSpeakerDeckをご参照ください。
セッションだけでなく、Go Conference 2025自体楽しかったのでまた来年も参加したいと思います。
参照
サーバーサイドエンジニアの財宝です。
Go Conference 2025で「全てGoで作るP2P対戦ゲーム入門」というセッションを聞きました。Goで実装した1対1対戦ゲームの話で、特にEbitengineというゲームライブラリが気になり、「GoでGUIも…作れるの?」と衝撃を受け、自分でも試してみることにしました。
概要
このセッションでは、以下の5つの要素でP2P対戦ゲームを構築する方法が解説されていました。
- Ebitengine: wasmビルドでブラウザゲームを実現
- WebSocketサーバ: 軽量マッチングとシグナリング
- Ayame: シグナリング・プロトコルの実装
- Pion/WebRTC: P2P通信の実現
- レーティングサーバ: スコア管理
特に印象的だったのは、EbitengineでmacOSやWindows、Linuxはもちろん、Nintendo Switch™でも動くという点でした。
お試し
Ebitengineを使ってどうやってゲーム画面が描画されるのか気になって、簡単なゲームを作ってみました。
実際に作成したものはこちらです。


クリックしたら風車が回転するという簡単なゲームを作りましたが、全体では300行もなく、コードもすっきりしたものになりました。
ゲーム画面は以下の記述だけです。
func (g *Game) drawGame(screen *ebiten.Image) { screen.Fill(color.RGBA{30, 30, 40, 255}) op := &ebiten.DrawImageOptions{} imgWidth, imgHeight := g.spriteImage.Size() op.GeoM.Translate(-float64(imgWidth)/2, -float64(imgHeight)/2) op.GeoM.Rotate(g.rotation) op.GeoM.Translate(float64(screenWidth)/2, float64(screenHeight)/2) screen.DrawImage(g.spriteImage, op) clickText := fmt.Sprintf("クリック数: %d", g.clickCount) text.Draw(screen, clickText, g.font, 10, 30, color.White) degrees := int(g.rotation*180/math.Pi) % 360 rotationText := fmt.Sprintf("回転角度: %d°", degrees) text.Draw(screen, rotationText, g.font, 10, 60, color.White) backText := "ESC: メニューに戻る" text.Draw(screen, backText, g.font, 10, screenHeight-30, color.RGBA{150, 150, 150, 255}) }
簡単な内容のゲームとはいえ、動くものをGoで作れるのにびっくりしました。Ebitengineの描画は、画像から画像への描画として表現しているらしくかなりシンプルなものらしいです。
どこまでできるのか気になったので時間ある時にしっかり触ってみようと思います。
まとめ
Go Conference 2025のセッションをきっかけに、Ebitengineを使った簡単なゲーム開発に挑戦してみました。Goでこれほど手軽にゲームが作れることに驚き、同時にGoの可能性を再認識しました。
セッションでは、Ebitengine以外にもWebSocketを用いたマッチング実装や、P2P接続など技術的に面白い内容を話されていたので、ぜひ気になった方はこちらのSpeakerDeckのページをご参照ください。
今回、ヤプリからはプロポーザルには応募したものの、外れてしまったので登壇者はいませんでした。
ですが、Goを使っている一企業としてこれからも発信していこうと思いますし、来年のGo Conferenceにはリベンジできればと思います。
「もっとヤプリについて話聞きたい!」という人、「ヤプリのGoエンジニアと話したい!」という人は、ぜひオフィスに遊びに来たり、カジュアル面談にお越しください!
コメント