SODA Engineering Blog
🐙

tenntenn Conference 2023 にスポンサーし、Goの静的解析を完全に理解した話

2023/06/26に公開

はじめに

コンニチハ!
SODAでVP of Engineeringをしている @rinchsan です。

2023年4月1日に開催された「tenntenn Conference 2023」に企業スポンサーとしてSODAが協賛させていただき、「スポンサーセッション」と「社内勉強会」を @tenntenn さんに実施していただきました!

https://tenntenn.connpass.com/event/261521/

本記事では、スポンサリングの意思決定からスポンサー後の社内の変化までをご紹介します。

爆速のスポンサリング意思決定

2022年10月1日(?)に企業スポンサーを募集することが告知され、その日に社内に展開され、10月3日に申し込みを完了する、という爆速(?)な意思決定でした。

スポンサーは抽選ではなく早いもの勝ちだったので、この対応により無事滑り込むことが出来て嬉しかったです。

tenntennさんとの打ち合わせで技術課題を伝える

カンファレンスが近づいてくると、スポンサーのベネフィットである「スポンサーセッション」の内容を相談する打ち合わせが開催されました。
事前に、SODAにある技術課題に合わせてスポンサーセッションやその他の動きを相談したいと伝えられていました。

そこで、

  1. SODAでは社内勉強会が盛んで、その中で静的解析について扱ったこともあり、何名かはAST(抽象構文木)はある程度触れる状態であること
  2. ASTのその先にも色々な静的解析手法があると思うが、それについては誰も詳しくないので静的解析で解決できる問題を見逃してしまっている気がすること

を伝えました。

そして最終的に、

  • 「抽象構文木のその先へ」というタイトルでスポンサーセッションを行う
  • ASTのその先にある静的解析についてEnablingしていただく勉強会を4回開催する

ということが決定しました!

第1回の勉強会

カンファレンスの前に初回の勉強会が開催されました。

初回の勉強会では、

  • ASTを利用した構文解析の復習を簡単に
  • ASTでは解析できないパターンを見てみる
  • Type Check(型チェック)まで利用することで解析できることを見る

という進め方で、ASTでは解析できない部分をType Checkによって解析できるようになるところまでを学びました。

  • 「あ、ウワサの素Vimだ!」
  • 「あ、Goのソースコードを見に行くときのURLを空で打ってる!」

と、tenntennさんの特徴的な(?)行動を生で見ることが出来てテンションが上がっていました(僕が)。


引用: https://www.youtube.com/watch?v=xg_wDPl0cW0

第1回の復習 & 第2回以降の予習となるスポンサーセッション

スポンサーセッションは事前に「初回勉強会の復習になり、2回目以降の予習になるように作る」ということを相談していました。

そしてセッションの内容も、ASTでは解析できないパターンに対して、Type Checkで解析を進めつつ、ある程度は解析できたものの、さらに1つ上の「SSA(静的単一代入形式)」に登らないと解析できない問題が出てくる、という構成でした。
(tenntennさんご自身は「型チェックだけでいけると思ったけど静的単一代入形式までいかないといけないことが分かった」とライブコーディングしながらおっしゃっていたので、意図した構成ではなかったのかもしれません笑)

詳しくはYouTubeでご覧ください!

↓↓↓↓↓

https://www.youtube.com/watch?v=xg_wDPl0cW0&t=6083s

第2回〜第4回の勉強会

第2回以降は、実際に弊社SODAにあるGoの課題をベースに、静的解析によって解決するツールを一緒に作っていく進め方となりました。
2つのお題に関して取り組んだのですが、どちらもASTやType Checkだけでは解析しきれない取り組みがいのあるお題でした。

1つ目:静的単一代入形式を使う

1つ目は、「 context.Context をパッケージの外に渡す際に、きちんと context.WithTimeout で生成された context.Context になっているかをチェックする」というお題でした。

さっそくASTだけでは解析できないお題で、SSA(静的単一代入形式)を利用して解析していくことになりました。

下記は実際に skeleton を利用してツールを作っていく際に作成したテスト用のGoコードです。

package a

import (
	"context"
	"time"
)

func main() {
	ctx := context.Background()
	f(ctx)       // want "NG"
	defer f(ctx) // want "NG"

	ctx, cancel := context.WithTimeout(ctx, 100*time.Second)
	defer cancel()
	f(ctx) // OK
}

func f(ctx context.Context) {}

2つ目:Factを使う

2つ目は、「 chi.Router でルーティングする先の http.Handler な関数の中でHTMLをレンダリングしている場合、そのHTMLファイルをエンドポイントと対応づけてリストアップしたい」というお題でした。

このお題では、ルーティングしているコードとルーティング対象となる http.Handler なコードが別パッケージに配置されていたので、複数パッケージに対して解析をかける必要がありました。
Goの静的解析は複数パッケージに対して解析をかける難易度が高いため、手法が限られてきたり、パフォーマンスが落ちて解析に時間がかかったりします。

今回は、「Fact」という概念を利用し、

  1. ルーティングしている部分でルーティング対象の http.Handler な関数に印をつける(ExportFactする)
  2. http.Handler な関数があるパッケージで印を取得して(ImportFactして)関数の中身を見てHTMLファイル名を探す

というように2段階に分けて解析していくことになりました。
(僕もまだまだ理解が甘いので曖昧なことや間違ったことを書いているかもしれません、、)

下記はテスト対象となるGoコードのイメージです。

package main

import (
	"a/web"
	"github.com/go-chi/chi/v5"
)

func main() {
	r := chi.NewRouter()
	r.Get("/", web.GetIndex)
}
package web

import "http"

func GetIndex(w http.ResponseWriter, r *http.Request) {
	render("/path/to/html/file.html")
}

社内のその後

Goの静的解析、完全に理解した!!!

とは言えないくらい静的解析の世界は広すぎる、、、(タイトルはウソでした)(Factナニソレ)

今回tenntennさんと一緒に作った2つのツールは両方とも完全には完成しておらず、途中で止まって完成させることが宿題として残っています。
そして、それらを「完成させるぞ!」と意気込んでいるエンジニアがいるので、それらが完成する頃にまたZennでお会いしましょう!

おわりに

▼下記ではより詳しく弊社のプロダクト開発組織について紹介してますので 是非ご覧ください!

https://recruit.soda-inc.jp/engineer

またSODAでは特にエンジニアを積極的に採用しておりますので
少しでも弊社に興味を持っていただけましたらご応募お持ちしております!

▼詳しい会社情報はこちらから

https://recruit.soda-inc.jp/

SODA Engineering Blog
SODA Engineering Blog

Discussion