Ponz Dev Log

ゆるくてマイペースな開発日記

gRPCのprotoファイルをGitサブモジュールで管理してみる

gRPCでインタフェースを定義するprotoファイルはどのように管理するのだろうと考える場面があったので、 Gitサブモジュールで管理してみました。備忘録です。

モチベーション

gRPCのサーバやクライアントアプリケーションは、 それぞれprotoファイルに記載された定義をもとに通信用のコードを生成しないといけません。 もしprotoファイルをそれぞれのリポジトリに腹持ちしてしまうと、片方のファイルの更新漏れによってインタフェースの不一致によるバグの発生確率が高まります。いちいち手動コピーする場合はなおさらです。

この課題を解決する場合、各アプリケーションのリポジトリではないどこかにprotoファイルを切り出す方法が有効に見えます。 切り出して一元管理されたリポジトリの内容を、protoファイルを利用するリポジトリに配布します。 単純にファイルを共有するだけですので、プログラミング言語固有のライブラリのしくみではなくGitサブモジュールを使うやり方が手っ取り早いように感じます。

Javaアプリケーション向けに実践してみる

実際にgRPCのサーバを実装するJava(Spring Boot)アプリケーションを例に実践してみます。

まず、protoファイルは専用のGitリポジトリを立てます。 ここでは言語ごとのコードは生成しません。あくまでこのリポジトリの責務はprotoファイルの管理と配布のみです。リポジトリは以下の図のように、protoファイルを保持するだけです。

f:id:accelerk:20210301002109p:plain
protoファイルの管理リポジトリ

次にproto管理リポジトリを、アプリケーションのリポジトリのサブモジュールとして取り込みます。 アプリケーションのリポジトリは、protoファイルをもとに通信用のコードを生成と業務機能の実装の責務を持たせます。 今回のサンプルはJavaアプリケーションですので、取り込み先のディレクトリは src/main/proto とします。以下のコマンドでサブモジュールをリポジトリに取り込みます。

git submodule add <PROTO_REPO_URL> src/main/proto

実行後は以下の図のディレクトリ構成になっています。 あとは取り込んだprotoファイルからgRPCのコードを生成します。

f:id:accelerk:20210301002146p:plain
アプリケーションのリポジトリにサブモジュールを取り込む

ビルドでGradleを使う場合は、gRPCのコード生成をするために以下のbuild.gradleを作成します。 作成後は gradle build を実行すると、src/main/protoGen ディレクトリに生成コードが格納されます。

gRPC server build spec for Spring Boot application

サブモジュールを取り込んだリポジトリをリモートにプッシュしたら、ほかの開発者もprotoファイルと生成済みコードを参照できます。リポジトリをクローン時に注意が必要で、サブモジュールも一緒にクローンするには --recursive フラグをつける必要があります。

git clone <REPO_URL> --recursive

参考

qiita.com


もっと賢いツールを使う方法もあるかもしれませんが、Gitのしくみだけでも十分protoファイルを管理できそうですね。

以上。