Slide 1

Slide 1 text

genkey6 @ newmo × LayerX "Go" 同 勉強会 / 2024-08-27 
 Go Code Generation 
 at newmo 


Slide 2

Slide 2 text

自己紹介
 ● 新卒からスタートアップ2社を経て、2024年7月に newmoに入社
 ● バックエンドがメインのソフトウェアエンジニアとして運 行管理サービスの開発に携わっている
 ● 鳥が好き 🐦
 genkey6
 2 Gen Shu


Slide 3

Slide 3 text

本日お話しすること
 ● newmo では開発時にスキーマからコードを自動生成する schema first な思想を中心 に据えている
 ● 主にバックエンドのレイヤーで行っている Go のコード生成の具体的な方法やそれぞれ の要素技術で取り入れている工夫について、実際のコード例を交えつつ紹介する 
 ○ GraphQL やデータベース周りの話が多め 
 ○ gRPC にも少し触れる
 3

Slide 4

Slide 4 text

GraphQL のコード生成|gqlgen を使った開発
 4 schema first なアプローチで GraphQL server を開発


Slide 5

Slide 5 text

GraphQL のコード生成|field resolver
 @goField directive をつけて field resolver として切り出す 
 ● 取得にコストがかかるフィールドは オーバーフェッチを防ぐために field resolver として定義 ● gqlgen 的には config ファイルで指 定する方法と schema で指定する方 法が存在する ● 可能な限り schema から情報を読み 取れるようにしたいという理由から、 後者を採用 5

Slide 6

Slide 6 text

GraphQL のコード生成|custom scalar
 ● 以下の custom scalar が存在 ○ Timestamp ○ Date ○ YearMonth ○ UUID ○ Base64String schema 上で頻出する型を custom scalar として定義 
 6

Slide 7

Slide 7 text

GraphQL のコード生成|custom directive
 validation 用に custom directive を定義
 ● 以下の directive が存在 ○ @validateInt ○ @validateFloat ○ @validateBoolean ○ @validateString ○ @validateArray 7

Slide 8

Slide 8 text

GraphQL のコード生成|custom directive
 validation 用に custom directive を定義
 ● model の生成時に Go の struct tags に validation の情報が付与される 8

Slide 9

Slide 9 text

GraphQL のコード生成|custom plugin
 ● template を修正して Go の struct の interface を満たすような UnimplementedHogeResolver を生成することで schema のみの変更をマージでき るようにしている gqlgen を fork して一部 plugin に手を加えている 
 9

Slide 10

Slide 10 text

GraphQL のコード生成|custom plugin
 validation struct tags の付与も plugin の改造で実現 
 10 before after

Slide 11

Slide 11 text

GraphQL のコード生成|custom plugin
 API テスト用の GraphQL operation file を自動生成する自作 plugin 
 ● Yamashou/gqlgenc を使って GraphQL operation file から GraphQL Client を生成している ● 手書きしていることでフィールドの指定漏れが起きるの を防ぎたい 11

Slide 12

Slide 12 text

GraphQL のコード生成|custom plugin
 ● gqlgen のコード生成時に作られる AST を活用して簡単に実装できた 12 API テスト用の GraphQL operation file を自動生成する自作 plugin 


Slide 13

Slide 13 text

GraphQL のコード生成|(番外編)fake server
 13 directive で指定した値をクライアント向けに fake として返す仕組み 


Slide 14

Slide 14 text

GraphQL のコード生成|(番外編)fake server
 ● schema からレスポンスの fake を生成する 際に @example directive で指定した値をデ フォルト値として利用 ● 詳細は newmo-oss/graphql-fake-server に 14 directive で指定した値をクライアント向けに fake として返す仕組み 


Slide 15

Slide 15 text

gRPC のコード生成|field behavior & protovalidate
 proto で記載した field behavior を protovalidate を用いて検証 
 ● 以下の behavior が存在 ○ OPTIONAL ○ REQUIRED ○ OUTPUT_ONLY ○ INPUT_ONLY ○ MUTABLE ○ IMMUTABLE ○ IDENTIFIER ○ PARENT_IDENTIFIER 15

Slide 16

Slide 16 text

gRPC のコード生成|field behavior & protovalidate
 proto で記載した field behavior を protovalidate を用いて検証 
 ● gRPC の interceptor と して実装されている 16

Slide 17

Slide 17 text

gRPC のコード生成|protoc-gen-go-grpc-newmo
 モジュラーモノリスならではのボイラープレートコードを自動生成する plugin 
 ● component 間の通信に 必要な環境変数の設定 に関する Go の実装を自 動生成する 17

Slide 18

Slide 18 text

データベースのコード生成|xo を使った開発
 SQL を書いて xo で Go の struct & レコード操作のための関数を生成 
 18

Slide 19

Slide 19 text

データベースのコード生成|xo を使った開発
 定義した index に応じた関数が生成される 
 ● PRIMARY KEY による WHERE 句を指定するための 関数 19

Slide 20

Slide 20 text

データベースのコード生成|xo custom template
 index を指定するフィールドの型によって生成されるメソッドが変わる 
 ● index に time, date 型のカラムが含まれ る場合は、時刻、日付のレンジで WHERE 句を指定できるような関数が生 成される ● この関数を呼び出すことでページングの実 装が簡単にできる 20

Slide 21

Slide 21 text

データベースのコード生成|xo custom template
 index を指定するフィールドの型によって生成されるメソッドが変わる 
 ● レンジで検索する際に指定できる条 件はこんな感じ 21

Slide 22

Slide 22 text

データベースのコード生成|xo custom template
 独自のメソッドの生成は xo の template を改造することで実現 
 22

Slide 23

Slide 23 text

データベースのコード生成|xo custom template
 生成される Go の struct の型を調整する目的でも template を改造
 ● date 型のフィールドは Go の struct でも Date 型として生成さ れて欲しい ● template に手を入れる前は BirthDate フィールドが time.Time 型で生成されていた → 改造後は Date 型で生成され るように 23

Slide 24

Slide 24 text

データベースのコード生成|xo custom template
 生成される Go の struct の型を調整する目的でも template を改造
 ● PostgreSQL の型から Go の型にマッピングする箇所の実装を fork して date 型に対す る条件分岐を追加 24

Slide 25

Slide 25 text

データベースのコード生成|xo custom template
 trace の span を仕込むのも自動化している 
 25

Slide 26

Slide 26 text

データベースのコード生成|xo custom query
 任意の WHERE 句の指定や JOIN などの複雑な操作が必要な場合は custom query に対応するモデルが生成される 
 26

Slide 27

Slide 27 text

データベースのコード生成|xo の課題
 query からのコード生成でいくつかの課題が存在する 
 27 ● 生成される Go の struct が分かれてしまうので、型変換などの処理を別々に実装す る必要があって扱いづらい ● custom query による UPDATE が非対応 ● nullable なカラムを取得する custom query を書いた際に、生成される Go の struct 上では常に non null な型になってしまう

Slide 28

Slide 28 text

データベースのコード生成|sqlc の利用を検討中
 まずは query による生成から置き換えていこうとしている 
 28 ● 先ほど挙げた xo の課題が解決できる ○ (JOIN をしなければ)生成される Go の struct が分かれない ○ xo では custom query を使う必要があった UPDATE 文にも対応可能 ○ nullable なカラムに対するクエリ結果が nullable になる ● 他にも xo にはなかった便利な点が存在する ○ SQL をパースしているので、コード生成の精度が高い ○ コード生成をスキーマファイルから静的に行える( xo はコード生成前にデータベースにスキー マを反映させる必要がある) ○ クエリを書く際に query parameter の型を指定しなくても自動で判別してくれる

Slide 29

Slide 29 text

データベースのコード生成|sqlc の利用を検討中
 一方で sqlc にも課題は存在する 
 29 ● パースした情報に index の情報が存在しないため、xo でやっていたような index に 応じた検索用の関数の柔軟な自動生成ができない

Slide 30

Slide 30 text

● GraphQL、gRPC、データベースの各レイヤーでコード生成に採用しているツールを紹介し つつ、それぞれのツールに対して行っているカスタマイズや取り入れている工夫について 紹介した ● 時間の都合で紹介しきれなかった Tips は他にもあるので、気になる方は懇親会でお話し ましょう & こういうこともできたりしない?という話をしましょう ● コード生成を駆使して開発者体験を突き詰めたいエンジニアはぜひ newmo へ! まとめ
 30

Slide 31

Slide 31 text

“ 移動で地域をカラフルに ”
 Our Mission