Yappli Tech Blog

株式会社ヤプリの開発メンバーによるブログです。最新の技術情報からチーム・働き方に関するテーマまで、日々の熱い想いを持って発信していきます。

Protocol Buffersのコード生成をprotocからBufに移行しました

スプラトゥーン3で脳を破壊されたサーバーサイドエンジニアの @shuymn です。

Yappliではサービス間通信にgRPCを採用しています。gRPCでは標準のデータシリアライズフォーマットとしてProtocol Buffersがあり、Yappliでもこれを利用しています。

Yappliでの運用については紹介記事もありますのでよろしければそちらも合わせてご覧ください。

tech.yappli.io

移行の経緯

Protocol Buffersのスキーマ定義ファイルから各プログラミング言語で利用するためのコード生成をするためにprotocというコンパイラが公式から提供されています。また、Protocol Buffersのスキーマ定義ファイルのLinter・Formatterとしてサードパーティ製ですが prototool があり、これらのツールを組み合わせてCIを行っていました。

prototoolのリポジトリを見ていただくと分かるとおりこちらのツールは既に開発が終了しています。そのため以下の問題が発生していました。

  • prototoolはprotocに依存しているためprotocのバージョンを上げることができない
  • prototoolはApple Silicon向けにビルドすることができないため、最近入社したエンジニアが手元のマシンでLint・Formatを実行できない*1

そのため新たなツールを探していたところ、Bufを見つけたのでそれに移行することにしました。

Bufについて

Bufはざっくり言うとprotocとprototoolが一体となったようなCLIツールで、開発元は最近だとConnectというgRPCのGo向けのサードパーティの実装を公開したりとgRPCエコシステムの改善に注力しているBuf Technologies, Inc.によって開発されています。

コード生成とLint・Format以外の機能もありますが、本記事では紹介しませんので気になる方は公式のドキュメントをご確認ください。

https://docs.buf.build/introduction

Bufに移行してみた所感

まずBufの使い方を理解するために公式ドキュメントにあるチュートリアルをさわりました。その上で実際に移行作業を行いましたが、Bufを使ってコード生成やLint・Formatを行うようにするのはドキュメントに書いている範囲に収まっていて特別ハマったりはしませんでした。しかし全くなにもする必要がなかったわけではないので、細かい部分になりますが紹介します。

protocで生成されるコードと差分がある

見出しの通り同じProtocol Buffersのスキーマ定義ファイルからprotocとBufそれぞれで生成されるコード*2にごくわずかに差分がありました。実際に利用する側のテストやQAで動作に問題ないことを確認した上でリリースを行い、今のところ問題は起きていません*3

Buf Schema Registryを使うかどうか

Buf Schema Registry(以下BSR)の利用は最低限にとどめました。

最初は protoc-gen-go-grpc などプラグインをBSR経由で利用していましたが、BSR自体まだベータ版の機能でありコミュニティによって管理されているプラグインやライブラリの更新がどこまで活発に行われるか不透明な部分があると感じたためです。そのためプラグインについては go install したり package.json で管理したりといったように各言語ごとに分離して管理しています。そして各種依存のインストールやコード生成はMakefileで実行するようにしました。

現在BSRを利用しているのはgoogleapisgrpc-gatewayのようにメジャーなライブラリに絞っています。前者はBuf開発チームが公式にメンテナンスしていて、後者はgrpc-gatewayの開発チームによってメンテナンスされています。

BSRを検索して目当てのプラグイン/ライブラリがあったとしても、そのプラグイン/ライブラリの所有者ではなく第三者がForkした上でBSRにアップロードしている場合もあるので注意が必要です。

prototoolとのLintルールの差分をどうするか

Linterの設定についてはprototoolの標準的な設定よりも厳しい項目があったため、既存のパッケージについては修正が不要になるまで ignore_only を使ってLintルールの除外をしました。その代わり、新規で追加されるパッケージについてはなるべくLintルールを除外しない方針で運用しています。

VSCodeの拡張機能の使い心地

Bufには公式でVSCodeの拡張機能がありますが、この記事を投稿した段階ではまだバリバリ使えるという感じでは無く挙動が怪しいところもありました(他のエディタ拡張については確認していません)。しかしLanguage Serverの開発も行っているようなのでより良くなっていくだろうと期待しています。

コード生成の速度

BufのGitHubリポジトリにもprotocに比べてコード生成の速度に利点があるという紹介があります。そこでCIで行っているコード生成の時間を比較すると以下のようになりました。Protocol Buffersのスキーマ定義ファイルのコード行数はライブラリを除いておよそ2万行です。

  • protoc: 7〜8秒
  • Buf: 5秒

なんと約150%高速化しました!

スキーマ定義の量が多くコード生成に時間がかかることが悩みの種であれば非常に魅力的なのではないでしょうか。

情報収集について

(Bufに限った話ではありませんが)BufのGitHubリポジトリのIssueでは頻繁に情報交換が行われているため、ドキュメントを読んでも分からないことがあったらまず同じような質問がされているか調べると以外とあったりするのでBufを使う場合はこちらも是非参考にしてみてください。

YappliのgRPCの今後

今回Bufに移行したことにより、Protocol Buffersとその周辺環境については最新の状態に保つことができるようになりました。そのため次はgRPCの周辺環境の更新を目論んでいます。

tech.yappli.io

こちらの記事でも紹介がありますが、現在Yappliのコンテンツ管理画面とサーバーの通信にはgRPC-Webを使っていて、それを実現するためにTypeScript向けのコード生成プラグインとしてimprobable-eng/ts-protoc-genを利用しています。そもそもProtocol BuffersのTypeScriptのコード生成はデファクトスタンダードが無い状態でしたが、使っていたプラグインもとうとう更新が止まってしまいました。

そこでEnvoyの面倒を見る必要はありますが安心感がある公式のgRPC-Webを使うか、期待の新星Connectを使うかを今後様々な観点から比較検討していきたいと思っています。

おわりに

protocからBufへの移行事例、いかがでしたでしょうか。Bufはツールだけでなく開発元がgRPCエコシステムに対して情熱を持って取り組んでいるため、今後の動向も逐一追っていきたいと思います。

YappliではWebフロントエンドチーム、iOS/Androidアプリチーム、サーバーサイドチームの3チームが交わる点としてgRPCが存在しています。gRPCとその周辺環境を整備することでプロダクトに直接影響を与えるだけでなく、開発に必要なコミュニケーションがより誰でも快適に高速にできるようになるという間接的な影響も与えることができると考えています。そんな縁の下の力持ちとしてバリューを発揮できる環境が整っているYappliに興味がありましたら是非カジュアル面談しましょう!

open.talentio.com

*1:M1が載っているマシンが支給されるため。

*2:Goのみ確認しています。他の言語でどうなるかは確認していません。

*3:一例であり、あまねく動作を保証するものではありません。