gRPCでインタフェースを定義するprotoファイルはどのように管理するのだろうと考える場面があったので、 Gitサブモジュールで管理してみました。備忘録です。
モチベーション
gRPCのサーバやクライアントアプリケーションは、 それぞれprotoファイルに記載された定義をもとに通信用のコードを生成しないといけません。 もしprotoファイルをそれぞれのリポジトリに腹持ちしてしまうと、片方のファイルの更新漏れによってインタフェースの不一致によるバグの発生確率が高まります。いちいち手動コピーする場合はなおさらです。
この課題を解決する場合、各アプリケーションのリポジトリではないどこかにprotoファイルを切り出す方法が有効に見えます。 切り出して一元管理されたリポジトリの内容を、protoファイルを利用するリポジトリに配布します。 単純にファイルを共有するだけですので、プログラミング言語固有のライブラリのしくみではなくGitサブモジュールを使うやり方が手っ取り早いように感じます。
Javaアプリケーション向けに実践してみる
実際にgRPCのサーバを実装するJava(Spring Boot)アプリケーションを例に実践してみます。
まず、protoファイルは専用のGitリポジトリを立てます。 ここでは言語ごとのコードは生成しません。あくまでこのリポジトリの責務はprotoファイルの管理と配布のみです。リポジトリは以下の図のように、protoファイルを保持するだけです。
次にproto管理リポジトリを、アプリケーションのリポジトリのサブモジュールとして取り込みます。
アプリケーションのリポジトリは、protoファイルをもとに通信用のコードを生成と業務機能の実装の責務を持たせます。
今回のサンプルはJavaアプリケーションですので、取り込み先のディレクトリは src/main/proto
とします。以下のコマンドでサブモジュールをリポジトリに取り込みます。
git submodule add <PROTO_REPO_URL> src/main/proto
実行後は以下の図のディレクトリ構成になっています。 あとは取り込んだprotoファイルからgRPCのコードを生成します。
ビルドでGradleを使う場合は、gRPCのコード生成をするために以下のbuild.gradleを作成します。
作成後は gradle build
を実行すると、src/main/protoGen
ディレクトリに生成コードが格納されます。
gRPC server build spec for Spring Boot application
サブモジュールを取り込んだリポジトリをリモートにプッシュしたら、ほかの開発者もprotoファイルと生成済みコードを参照できます。リポジトリをクローン時に注意が必要で、サブモジュールも一緒にクローンするには --recursive
フラグをつける必要があります。
git clone <REPO_URL> --recursive
参考
もっと賢いツールを使う方法もあるかもしれませんが、Gitのしくみだけでも十分protoファイルを管理できそうですね。
以上。