こんにちは、メルペイのバックエンドエンジニアの @kazegusuri です。
メルペイではクラウド環境としてGoogle Cloud Platform(GCP)を採用しています。
そしてデータストレージとしてほとんどのマイクロサービスでGoogle Cloud Spannerを採用しています。
SpannerではMySQLのようなRDBMSとは全く異なるスキーマ設計や実装が必要となるため、日々試行錯誤しながらサービスの開発を行っています。
本記事ではサービス開発中に開発したSpanner用のコード生成ツールのYoについて紹介したいと思います。
xoについて
Yoについて説明する前にYoの元になった xo について紹介します。
xoはMySQLだけでなくPostgreSQLやOracleなどの複数のデータベースに対応したコード生成ツールです。
今までGoでデータベースを扱うために database/sql を直接使ったり、GORMなどのORMや sqlx などのライブラリを実プロダクトで試してきましたが
どれももう少しなんとかしたいと思うところがありました。
xoでは冗長なコードが生成されたりはしますが、 database/sql を直接扱う単純なコードが生成されるためGoのコードとして見通しがよく扱いやすいと感じています。
生成されるコードもGoのtemplate機能を使っていてカスタマイズ可能なのでプロジェクトと一緒にテンプレートも管理することで一括してコードを管理することができるようになります。
また、xoの一番良い部分はインデックスを考慮したクエリとコードも生成してくれることです。
基本的にクエリはインデックスを利用するべきなので、xoが生成したコードを利用することで確実にインデックスを使っていることがわかるので安心できます。
もちろんJOINなどを含んだ複雑なクエリは生成できないので手動でクエリを書くことになりますが、ほとんどは単純なクエリにWHERE句が付く程度のものなのでレビューの手間を大きく減らすことができるようになります。
Yoについて
Yoはxoと同様にスキーマからモデルやクエリなどのコードを生成するツールです。
命名の由来はxoの次ということでyoになっています。
生成されるコードには以下のような特徴があります。
- テーブル毎に1ファイル
- テーブル名からstructを生成
- Insert/Update/DeleteなどはMutationを返す
- SELECT文では*を使わずにカラム名を全て指定
- セカンダリーインデックスから FindXXXByYYY というメソッドを生成 (XXXはテーブル名, YYYはインデックス名)
- Readを使わずにQueryで取得するので全てのカラムを取得
- ReadWriteTransaction/ReadOnlyTransactionを両方使えるようにinterfaceで受けている
Spannerをちゃんと使っていくためにはまだまだ機能的には足りていないところは多いですが、xoと同程度の使い勝手は提供できています。
テンプレート機能もあるため、プロジェクト毎にカスタマイズすることも可能です。
実際にメルペイ社内ではYoで生成したコードを利用しているマイクロサービスがいくつもあります。
例えば決済システムはもともとMySQLで動作させていたためxoを使っていましたが、Yoを使ってSpannerを使うように書き換えました。
こちらで記事で報告したとおりMTC2018のカンファレンスLPでも使用していました。
Yoはまだまだできたばかりで社内でも試行錯誤しながら利用しています。
データ型もArrayやStructなどが対応していなかったりReadを使った最適な参照、最近追加されたDMLの対応もまだです。
個人的にはxoの良いところであるインデックスからコードを生成することで安全で最適なアクセスが保証してくれるように、
様々なユースケースに対応するようなクエリパターンを自動的に生成できるようにして、手動でクエリを書くというのを極力少なくしていきたいと考えています。
何か要望などがあればぜひGitHubのIssueなどからお願いします。
予告
まだまだ社内にはYo以外にもSpanner用に開発したツールがいくつかあるので、これらも順次公開していくはずです!!