こんにちは。今回のポストでは、OpenAPI Specification、protobuf、gRPC、avroなど、一般的にインターフェース定義言語 (IDL) と呼ばれるものをPolyglot MSA環境で共有モジュールとして導入した事例について紹介したいと思います。
IDLとは?
一般的にIDLと呼ばれるgRPCを例に取ると、以下のように「通信」に関する仕様を記述することができます。
message SearchRequest {
string keyword = 1;
int32 page_number = 2;
int32 result_per_page = 3;
}
通信を仕様化することで共通のコードを通じた通信の共有
IDLによる前方/後方互換性の確保
通信を仕様化することで共通のコードを通じた通信の共有
ほとんどのIDLツールはCodeGenをサポートしています。例えば、上記の例の仕様を作成すると、通信部のオブジェクトとコードがすべて生成されます。これはクライアントとサーバーの両方で使用でき、IDLを作成することで、別途のI/O検証なしに信頼性の高いコードを作成できるようになります。
IDLによる前方/後方互換性の確保
IDLを導入すると、通信仕様に関するコードレビューにクライアントとサーバーの開発者が自然に参加することになり、Avroでは直接互換性の検証を助けてくれます。このように前方/後方互換性を保つことができれば、クライアントとサーバーの開発間の依存性が減少するため、並行して開発を進めることができます。
また、私も現在検討中ですが、もしIDLを使用してデペンデンシーマップを描くことができれば、自然に通信の現状とスキーマ進化に対するオブザーバビリティを確保できるため、大規模な開発環境では優れたツールとなるでしょう。
IDLの領域は現在も着実に拡張しており、最近ではAsyncAPIというEDA用の仕様ツールも登場し注目を集めています。それだけでなく、KafkaのSchema Registryのようなツールとも統合できるため、規模が大きくなる開発組織の場合、導入を検討する価値があります。
Git Submoduleを利用したサービス間の共有モジュール
上記で見てきたように、IDLはCodeGenをサポートしているため、Polyglot環境の複数のサービスも1つのコードベースを共有することができます。これをGit Submoduleで実装するなら、以下のようなワークフローを構築することができます。
ただし、Git Submoduleは1つのファイルとして扱われるため、複数の開発者が協力する際にコンフリクトのポイントとなる可能性があります。これを防ぐために、GitHubのDependabotのようにスキーマの進化が行われて新しいバージョンが出た時にPRを作成してくれるワークフローを作り、マージすることができます。
上記のように、生成されたコード自体をソースコードとしてインポートし、サービスのコードと統合して使用することができます。
GitHub Packagesを利用したサービス間の共有モジュール
ワークフロー自体は上記と同じですが、この方法をまず紹介した理由は、Polyglot環境ではパッケージレジストリをうまく利用することが難しいためです。GitHub Packagesでサポートされている主要な言語は、リモートモジュールのようにリリースし、スキーマ進化を進めることができます。しかし、PHPのような言語をサポートしなければならない場合は、上記のように生成されたコードをSourceSetとして利用する方が良いかもしれません。
IDLを導入する際に注意深く考慮した点を簡単に共有いたします。
CodeGenの責任は一箇所にあるべき
他のプラクティスを見てみると、生成されたコードを共有するのではなく、IDLを共有し、各サービスで各自CodeGenを通じて使用する場合もあります。しかし、ほとんどのIDL CodeGenツールはバージョンによって生成結果が異なるため、CodeGenは中央集中的な管理を受けることで、大きな問題を事前に防ぐことができます。
インターフェースファースト
IDLを導入すると、インターフェースに対するコードレビューがクライアント、サーバーの開発者によって活発に行われるようになります。また、これをオープンソースを利用してUIで表現することができるため、サービスカタログの役割を代替することも可能です。そのため、CIでのCodeGen、IDL lintも積極的に使用されるべきであり、IDLのディレクトリやパッケージ構造でもドメインを区別しやすいように多くの工夫が必要です。
すべてが自動化されているべき
上記で述べたように、IDLはクライアントとサーバーの開発者が共に参加する場になります。つまり、iOS開発者、Android開発者、バックエンド、フロントエンド開発者がそれぞれ異なる背景知識を持って参加するため、IDLを作成することと担当サービスのスキーマ進化(IDLモジュールのバージョンアップグレード)以外に気を配る必要がないようにするべきです。これを守れなければ、IDL導入初期に他の開発者から敬遠される可能性があります。
IDLはテクノロジー組織の規模が大きくなるにつれて、複数のチームを一つにまとめる強力な手段となります。IDLがうまく導入され、よく抽象化されたAPIが多く生まれれば、各製品でさまざまなドメインのデータや機能が活発に活用されるようになるでしょう。もし製品が非常に大きくなりドメインが増えた場合、以下のように構造を変更することもできるかもしれません。