🚀

Encraft #5 「Go1.21+ 最前線」開催レポート

2023/08/18に公開1

株式会社ナレッジワーク ソフトウェアエンジニアのmichioです。
本記事では、2023年07月28日に開催したオフライン勉強会Encraft #5「Go1.21+ 最前線」の開催レポートをお届けいたします!

Encraftとは?

Encraft(エンクラフト)は株式会社ナレッジワークが提供する、 "Enablement" と "Craftsmanship" をテーマにした勉強会です。技術にこだわりを持つ人々が集まって互いに知見を交換し、できることを増やしていく場を作りたいと思っています。
過去のイベントの開催レポートは以下からご覧ください。

オフラインで参加することが難しい方などに向けて、今回もYouTubeでのLive配信も行いました。動画アーカイブもこちらにありますので、ぜひご覧ください!
また、セッションの感想をハッシュタグ #encraft でつぶやいていただけると嬉しいです。

パネルディスカッション

Encraft#5では、「Go1.21+ 最前線」をテーマに、@syumaiさん、@sivchariさん、@tennntennさんの3名にパネルディスカッションを行っていただきました。
Encraft #5の時点では未リリースだったG1.21.0ですが、日本時間の2023年08月09日にリリースされました。本パネルディスカッションではそのリリースに先んじて、注目機能やGoの学び方といったテーマで白熱した議論がなされました。さらにはEncraft #5開催直前でGo1.22の話題がホットになったため、急遽Go1.22以降の話題もディスカッションテーマに追加しました。以下にサマリーを記載いたしますので、気になるテーマがありましたらぜひ読んでいただけると嬉しいです。

パネルディスカッションサマリー

① Go1.21の注目機能

https://youtu.be/bEJ3qWF0068

開発に影響アリなもの

GOTOOLCHAIN / GODEBUG

GOTOOLCHAINは環境変数であり、GOTOOLCHAINでGoのバージョンを指定すると、そのバージョンでビルドをする。手元に指定したバージョンのGoが存在しない場合は、ダウンロードもしてくれる。CIの設定にも良い影響がありそう。
GODEBUGも環境変数であり以前から存在していたが、Go 1.21 から//go:buildコンパイラディレクティブで記述できるようになった。ソースコード上で管理できるようになった恩恵は大きい。

go test -c

-c オプションは テストファイルのコンパイルのみを行うオプションであり、これ自体は以前から存在していた。Go1.21.0で複数パッケージのコンパイルに対応した。 go test -c ./… を実行すると配下のファイルが全てビルド対象に入るので、パッケージを1つずつ列挙する必要がなくなったのは嬉しい。CIで重宝するのではないか。

contextパッケージ

WIthoutCancel関数の追加に注目している。これにより、一度context.WithCancel関数やcontext.WithTimeout関数でキャンセルを行うように設定したコンテキストであってもキャンセルを外し、context.WithValue関数で紐づけた値だけを利用できるようになった。これまでは自前で実装する人が多かった印象なので、嬉しい人は多いのではないか。

導入背景が面白いもの

slices, mapsパッケージ

Goを教えているとマップのキーを取得する組み込み関数はあるのかと毎回のように聞かれ、その度に「ありません。for range文を利用してください。並び順はランダムになりますが」と答えていた(笑)。Go1.21.0で標準ライブラリにmapsパッケージが追加され、ようやくマップのキー取得が簡単になりそうだと考えてこのスライドを作った。しかしながら、イベント開催直前にmaps.Keys関数と maps.Values関数を無くすプロポーザルが出て承認された。なので残念ながら、キーの取得について状況はしばらく変わらなさそう。(本イベントの後にmapsパッケージへイテレータを利用したKeys関数やValues関数を導入するプロポーザルがGo開発チームのエンジニアであるRuss Cox氏より提出されました。)

WebAssembly System Interface (WASI) Preview 1

Web Assembly (Wasm)はブラウザが解釈可能な専用のバイナリ形式であり、Wasm自体はGoでも以前からサポートされていた。Go 1.21.0では WASI (「ワジ」と発音しているが自信はない) の初期サポートがされた。WASIとはasmから OS の機能にアクセスするためのインターフェースのこと。これによって、Goで生成した Web AssemblyからOS の機能を呼び出せるようになる。

testing/slogtestパッケージ

slog(構造化ログ)パッケージは独自実装ができるようになっている。そうすると、ユーザ独自のslogの検証方法が課題になる。
導入背景が面白いと感じた点は、slogパッケージ単体のためだけにtestingパッケージ配下に slogtestパッケージが増えた点。

これどうなの?な機能

ループ変数の挙動変更 (GOEXPERIMENTALS=loopvar)

Go1.21.xまでは for文のループ変数はイテレーションごとではなくfor文単位で宣言されているこれに起因するバグはしばしば発生するが、GOEXPERIMENTALS=loopvarを設定することで、for文の ループ変数はイテレーションごとに異なるインスタンスとして宣言されるようになる。

log/slogパッケージ

標準ライブラリに log/slogパッケージが含まれた。Goでよく利用されているサードパーティのロギングライブラリである zapやzerologを代替できる方法として期待している。
しかしながら、標準ライブラリに入れるのが早かったな、という観点で「これどうなの?」にした。
新しいプロジェクトを作る時は使っていいのではないかと考えている。パフォーマンス面はzapやzerologの方が速いが、slogパッケージも実用に耐えそうな水準ではある。

min/max関数, cmpパッケージ

min/max関数については 組み込み関数にするかcmpパッケージ配下に作成するかなど継続的にディスカッションがされていたという点が興味深い。初期の設計者の間でも侃侃諤諤だった。
また、min関数におけるNaNの振る舞いも面白い。

② Go1.22+で入りそうな機能

https://youtu.be/hskP3BEvhbQ

for文の改善 (#60078, #61538, #61405)

for range文で扱える変数が増え、関数と整数にも対応するようになった。

  • イテレータは書くのは難しいけど、使うと便利そう。
  • イテレータっぽい機構の作り方が統一されて良さそう。関数呼び出し結果のbool値を見てbreak などを書かずに済むのは嬉しい。
  • 引数周りを書くのが面倒だけど便利そう。呼び出し側が関数呼び出しのみで継続するか判定できるのは便利。

untyped builtin zero (#61372)

  • 定義済み識別子zeroが導入されると、nilは不要になる?
    • zeroはnilのスーパーセットなので、nilで書けるところはzeroで書けてしまう。
  • ジェネリクスでよく使うvar zero Tのイディオムが消える。
    • ジェネリックな関数だとゼロ値のリテラルを書けないので、先頭にvar zero Tでゼロ値になる変数を宣言して最後にreturn zeroする、といった処理が必要。
    • しかもこの書き方だと、比較可能な型に限定されてしまう場合がある。zeroの導入によりジェネリクスにおけるゼロ値の比較が簡単に出来るようになる。
  • 型なしのゼロ値という概念は、定数の仕様からして自然。
  • ゼロ値を簡単にかけるのは便利。(e.g. time.Time{}, err)
    • ただ、コーディングルールは複雑になりそう。go fmtでゼロ値で書けるところはゼロに書き直して欲しい。

net/httpルーティング改善 (#61410)

  • 唯一の弱点だったと感じているルーティングが改善されたら嬉しい。
  • 実用的なHTTP Serverが標準ライブラリだけで作りやすくなる。HTTPメソッド名をパターンに含めるのは初見時驚き。
  • ルーディングが改善される!!既存のルーティングがどう進化を遂げるか楽しみ。METHOD名をパターンに入れることで同一のパスパターンを使えるようになるのもいい。

③ 新しい機能の学び方

https://youtu.be/FCCbvjrog0Q

情報源

proposal review meetingを読む。

Accepted (実装予定のもの)、Declined (拒否されたもの)、Likely Accept (採択可能性が高いもの)、Likely Declined (拒否可能性が高いもの)、Active (現在進行形で議論されているもの) に分類される。
毎週木曜に更新されるので、週刊雑誌のように毎週楽しみに読んでいる。

GoのGitHub / GerritのCL を読む

GitHubは様々なissueを眺めるのが面白い。
Gerritとは、Go開発チームの方々がよく利用しているコードビューツール。
issueの内容がよくわからない時に、GerritのCLを読むと理解が深まることがある。

学び方

CLやソースコードを読む
承認されたプロポーザルのissueを読む

次のバージョンにどのような機能が入るかを、背景やモチベーションレベルで知りたいときはissueを読んでいる。
Russ Cox氏のコメントを読むだけでも大いに理解の助けになる。

最新のmasterブランチをローカルでビルド

毎日ランチタイムに最新のmasterでビルドを実行している。gotip downloadでもビルドができるが。
The Go Playgroundのdevブランチでも試すことができる。

マル秘テクニック

gotip download CL番号でCLの内容を試せる
gospec previewer (自作ツール)

https://gospec-previewer.vercel.app/
Goの言語仕様の変更(CL)が読みづらいので、HTMLで読めるようにビューアを自作した。
コミットのハッシュで検索すると、該当のCLをHTML形式で閲覧することが出来る。

Action GraphをJSONで吐き出す

Triple-Win アンケート

Encraftでは、参加者がアンケートに回答するとナレッジワーク社がその回のテーマに合わせたOSSプロジェクトに寄付をする試みを行っております。
参加者の 1回答当たり8ドルをナレッジワークがOSSに寄付することで、参加者とOSSプロジェクトをナレッジワーク社が繋ぐ仕組みです。なお、寄付先であるGoToSocialはヨーロッパ拠点であり寄付もユーロ払いのため、1回答当たりの寄付金額を8ユーロとさせていただきました。
Encraft#5では33名の方がアンケートに回答してくださり、264ユーロをOpen Collective経由でGoToSocialに寄付いたしました。
ご回答いただいた皆様、ありがとうございます!

以下のようなご感想やフィードバックを参加者アンケートを通して頂きました。ありがとうございました。なお、ここに掲載している文言は頂いたご意見をまとめたものになります。

  • 機能導入までの背景まで知ることができて勉強になった
  • もう少し時間に余裕があったら、なお良かったかもしれない
  • 最新のGoの学び方や情報収集方法が知れた
  • もっと実践的な内容だと期待していた

頂いたご意見をもとにタイムマネジメントの強化やイベントページに掲載する内容の分かりやすさに気をつけていきます。

開催の様子

受付の様子
受付の様子です。

準備の様子
YouTube Live配信準備の様子です。配信作業お疲れ様でした。


会場の様子です。沢山のご来場、ありがとうございました!


登壇者の皆さんです。議論中に参加者の方からも質問があり、終始盛り上がっていました。


懇親会の様子です。各地でGo談義に花が咲いていたようで、大盛況でした。

次回予告

Encract #6は2023年8月30日(水)の19:30からの開催を予定しております。
テーマは「Focus on UI Component 実装」です!SmartHRの@nabeliwoさん、サイバーエージェントの@herablogさんにそれぞれセッションをご担当いただきます。ナレッジワークの@yoshikoも登壇いたします。
自社UI Componentの設計や実装の工夫、気に入っているポイントなどについてお話しいただく予定です。

ぜひご参加ください!

Encraftは今後も定期的に学びと交流の場として開催を予定しています!

Connpassでグループメンバーになっていただけると開催通知メールが送られますので、開催を知りたい方は以下より是非グループメンバー登録をよろしくお願いします。

https://knowledgework.connpass.com/

セッションをオンラインでご覧いただいた方も、感想などハッシュタグ#encraftでツイートしていただけたら嬉しいです!

それでは、また次のEncraftでお会いしましょう!

Discussion

tenntenntenntenn

補足です。

新しく入るかもしれないzeroという識別子ですが、プロポーザルが承認されたためGo1.22以降で入ることが決まりました(#61372)。

その際に、nilのスーパーセットとしての意味合いではなくなりました。
詳細は新しい仕様を確認してほしいですが、簡単にまとめると以下の通りです。

代入可能性において、型Vのxの値を型Tの変数に代入する場合を考えます。
型Tが型パラメタではない場合、型Tが構造体または配列のときにxは定義済み識別子zeroにできます。
一方で、型Tが型パラメタの場合は、型パラメタTに0,"", nilが代入できないときに限りxにzeroが使えます。

syumaiさんの仕様書ビューアで該当部分を確認するとわかりやすいです。
https://gospec-previewer.vercel.app/refs/ff6a26780f87f175c64b854ad3d2c663e9038bf4#Assignability