Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Go Code Generation at newmo / 2024-08-27 #newmo...

genkey6
August 27, 2024

Go Code Generation at newmo / 2024-08-27 #newmo_layerx_go

newmo × LayerX "Go"同 勉強会
https://layerx.connpass.com/event/323385/

genkey6

August 27, 2024
Tweet

Other Decks in Programming

Transcript

  1. genkey6 @ newmo × LayerX "Go" 同 勉強会 / 2024-08-27

    
 Go Code Generation 
 at newmo 

  2. 本日お話しすること
 • newmo では開発時にスキーマからコードを自動生成する schema first な思想を中心 に据えている
 • 主にバックエンドのレイヤーで行っている

    Go のコード生成の具体的な方法やそれぞれ の要素技術で取り入れている工夫について、実際のコード例を交えつつ紹介する 
 ◦ GraphQL やデータベース周りの話が多め 
 ◦ gRPC にも少し触れる
 3
  3. GraphQL のコード生成|field resolver
 @goField directive をつけて field resolver として切り出す 


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

    ◦ Date ◦ YearMonth ◦ UUID ◦ Base64String schema 上で頻出する型を custom scalar として定義 
 6
  5. GraphQL のコード生成|custom directive
 validation 用に custom directive を定義
 • 以下の

    directive が存在 ◦ @validateInt ◦ @validateFloat ◦ @validateBoolean ◦ @validateString ◦ @validateArray 7
  6. GraphQL のコード生成|custom directive
 validation 用に custom directive を定義
 • model

    の生成時に Go の struct tags に validation の情報が付与される 8
  7. GraphQL のコード生成|custom plugin
 • template を修正して Go の struct の

    interface を満たすような UnimplementedHogeResolver を生成することで schema のみの変更をマージでき るようにしている gqlgen を fork して一部 plugin に手を加えている 
 9
  8. GraphQL のコード生成|custom plugin
 API テスト用の GraphQL operation file を自動生成する自作 plugin

    
 • Yamashou/gqlgenc を使って GraphQL operation file から GraphQL Client を生成している • 手書きしていることでフィールドの指定漏れが起きるの を防ぎたい 11
  9. GraphQL のコード生成|(番外編)fake server
 • schema からレスポンスの fake を生成する 際に @example

    directive で指定した値をデ フォルト値として利用 • 詳細は newmo-oss/graphql-fake-server に 14 directive で指定した値をクライアント向けに fake として返す仕組み 

  10. gRPC のコード生成|field behavior & protovalidate
 proto で記載した field behavior を

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

    protovalidate を用いて検証 
 • gRPC の interceptor と して実装されている 16
  12. データベースのコード生成|xo custom template
 index を指定するフィールドの型によって生成されるメソッドが変わる 
 • index に time,

    date 型のカラムが含まれ る場合は、時刻、日付のレンジで WHERE 句を指定できるような関数が生 成される • この関数を呼び出すことでページングの実 装が簡単にできる 20
  13. データベースのコード生成|xo custom template
 生成される Go の struct の型を調整する目的でも template を改造


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


    • PostgreSQL の型から Go の型にマッピングする箇所の実装を fork して date 型に対す る条件分岐を追加 24
  15. データベースのコード生成|xo の課題
 query からのコード生成でいくつかの課題が存在する 
 27 • 生成される Go の

    struct が分かれてしまうので、型変換などの処理を別々に実装す る必要があって扱いづらい • custom query による UPDATE が非対応 • nullable なカラムを取得する custom query を書いた際に、生成される Go の struct 上では常に non null な型になってしまう
  16. データベースのコード生成|sqlc の利用を検討中
 まずは query による生成から置き換えていこうとしている 
 28 • 先ほど挙げた xo

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

    の情報が存在しないため、xo でやっていたような index に 応じた検索用の関数の柔軟な自動生成ができない