gRPC の普及により、通信時ののデータやり取りの仕組みとして、Protocol buffers を使うことも増えてきただろうと思う。
Protocol buffers のフォーマットでデータをやり取りする場合、IDLとなる .proto ファイルを複数のリポジトリが参照する形になる。
少なくとも、最新の .proto ファイルか、そこからコンパイルされたコードを、全サービスで共有できるようにしておく必要がある。
方針1: APIのサーバー側リポジトリでクライアントコードを生成し、クライアントは生成後のコードを参照する
APIのサーバー側リポジトリで .proto だけでなく、そこから生成されたクライアント用コードも管理してしまう案。
.proto の管理者はIF定義を更新する場合、必ずコンパイル後のコードも合わせてpushする必要がある。
現実的には .proto ファイルがpushされたら、CIで各言語のコードが生成され、個別の各サービスは git submodule などを使って生成後のコードを参照する形になるだろう。
メリット
- 各クライアントリポジトリ側で .proto をいちいちコンパイルする必要がない
デメリット
- 新たな言語のクライアントが現れた時に、サーバー側リポジトリでのコンパイルを増やす必要があり、サーバ側の責務としてやりすぎている
- サーバー側とクライアント側の開発者が同じならまだいいが、大規模開発などでは運用が難しい
- サーバー側リポジトリの .proto に依存するサービスの言語の数だけコンパイルする必要があり、ファイルが入り乱れる
- git submodule での管理だと、参照する APIサーバーが増えてきたときに、どのAPIでどのバージョンを参照しているのか把握しづらい
方針2: サーバー側では .protoファイルのみを管理し、クライアント側は .proto を取り込んで各自コンパイルする
サーバ側では .proto ファイルのみを管理し、各クライアントは protodep を使って、 依存関係のある .proto ファイルのうち、更新のあるものだけを収集する。
(protodep を使わなくても、git submodule を使ったり、手でコピーするなどの管理方法もある)
.proto のコンパイルは各クライアント側で行う。
protodep の使い方参考
https://soichisumi.net/2019/05/managing-proto-files-with-protodep/
メリット
- 使用する .proto のバージョンをファイル管理でき、依存の把握がしやすい
- APIサーバー側で無駄なファイル管理とコンパイルをする必要がないので、開発における責務を分解できる
デメリット
- いちいちコンパイルする必要がある
方針3: .proto ファイル管理用のリポジトリを立てて、サーバーもクライアントもそのリポジトリのファイルを参照する
gRPCサービスが増えてくると、クライアントは複数のリポジトリの .proto を参照する必要が出てくるかもしれない。
そんな時は、 .proto 管理用のリポジトリを一つ作って、そこで色んなサービスの .proto を管理するという手もある。
(メルカリはこの手法を取っているらしい)
.protoだけでなく、コンパイル後のコードまでここで管理しても良い。このリポジトリのCIタスクとして、.proto が push されたら 各言語のクライアント用コードを生成するようにしておけば、自動でコンパイルされる。
まとめ
検索すると protodep を使った方法が結構出てくる。
実際、手軽に始めるなら方針2が良さそう。
みなさんどうやって運用しているんでしょう。