- 以前社内向けに行った「Protobuf 速習会」で話した内容を記事として公開します。
- JSON / RESTful API と、Protobuf / gRPC を使った開発は何が違うのか
- 経験:Wantedly People での開発を通じて何度か大規模に Protobuf を使って開発をしてきた
- 単に「型がついて嬉しい」というレベルではないメリットがあった
- 前編となるこの記事では、Protobuf を使うと開発がどういう風に変わるのかについて話している
- 後編となるこの記事では、それについての技術的な事柄や、開発フローを実現するためのいろいろな道具立て、具体的な tips について説明している
- (ちなみに Protobuf にはバイナリベースであることによる性能上のメリットも存在するが、ここで言及するには設計上のメリットになる)
- 性能上のメリットと違って、設計上のメリットは、gRPC gateway のようなプロキシ・サーバーを通して JSON を喋る場合にも受けることができるし、受けてきた。
- まず結論から話すと、Protobuf を使うことで大きく二つのことが実現可能になると考えています。
- ひとつは、設計への適切な投資による **開発生産性の維持** です。
- もうひとつは、その結果としてのモジュール化による **開発者のスケーラビリティの向上** です。
- これら二つによって、 **新しいものを作るスピードと、作ったものを変えていくスピードを両立できる** というのがプロダクト開発におけるとても大きな価値だと感じています。
- つまり、新しいものを作るときは開発者のスケーラビリティによる恩恵を得て、作ったものを変えていく際はドメインの設計による恩恵を受けることができます。
- ソフトウェア開発における大きなパラメータとして、内部品質(可読性、変更可能性など)と開発期間があります。
- もし、内部品質を非常に低く設定した場合は、開発期間を大きく減らせます(”うまく”やった場合の話です)。
- これはこれで有用で、例えばプロダクトのプロトタイプの構築などに使えます。
- ただし、その代わり、継続的な改善はできません。
- プロダクト開発において「改善が99%」だという考え方がうちにはありますが、それでいうと改善ができないのは致命的です。
- 逆に、実装の品質を十分大きく取った場合、内部品質を度外視した場合に比べれば開発期間は長くなります。
- その分、継続的に改善することができます。
- もし、内部品質を非常に低く設定した場合は、開発期間を大きく減らせます(”うまく”やった場合の話です)。
- 無論、内部品質とスピードはトレードオフの関係ではなく正の相関があるというのが色々なソフトウェア・エンジニアリングの古典が教えてくれるところですが(最近の t_wada さんの講演が特にわかりやすいです)、
- とはいえ、設計に対して **どのくらい早くお釣りがくるのか?** というのは実際問題として重要になります。
- そして、Protobuf は、それと導入する前と比較して、内部品質と開発期間をかなり高いレベルで両立できるようになる道具だと思っています。
- 感覚的には、同じ内部品質にするとして、3割くらい開発期間が変わってくる、と今は思っています。
- あと、最近 Wantedly People の開発に新卒エンジニアが二人ジョインしたのですが、「Protobuf がないときにどうやって開発していたのかわからない」というようなことを言っていました。
- この例えが伝わるかわからないですが、BigQuery がない状態でどうやって推薦などをテキパキと組んでいったりサービスの状態を把握したりするのかって今となっては結構分からないと思うのですが、そういう道具なのかな、と思っています。
- この声からもわかるように、Protobuf でインターフェイスをきちんと記述しておけば、新しく開発チームに入ってきたエンジニアが活躍できるようになるまでのリードタイムを大きく減らすことができます。
- 今では新しく入ってきたバックエンド・エンジニアに最初に渡すものの一つに Protobuf が入っている状態です。
- (なお、Protobuf がそのような価値を生むには Protobuf の使い方もかなり重要だと考えていて、後編ではそれについてお話しします)
- あらゆる道具がそうであるように、Protobuf も銀の弾丸ではないので、特に有効だと考える状況について補足しておきます。
- Protobuf はインターフェイス定義言語(IDL)です。
- インターフェイス定義言語は、コミュニケーションツールとして使えます。
- したがって、開発チームでコミュニケーションが発生するようなプロジェクトにおいて特に大きな効果を発揮すると考えています。
- ちなみに一人でも長い期間開発すると過去の自分は他人だと思った方が良いので、一人で長い期間同じソフトウェアを開発するようなケースでも有用でしょう。
- 開発者のスケーラビリティが得られるとは具体的にどういうことか、直近のリニューアル・プロジェクトを例に取って説明します。
- このリニューアルプロジェクトではネイティブアプリのある大きめの機能をほぼゼロから改修しました。
- このプロジェクトの大まかな進行と依存関係がこの図のようになります。(図)
- 初めに仕様を定義しながらそれと並行して実現可能性に懸念がある部分などについて技術的な調査を並行して行なっています。
- これができたら Protocol Buffer で API を設計し、バックエンドとフロントエンドで合意します。
- 一旦 API が合意できれば、バックエンドもフロントエンドもすぐに走り出すことができるため、並行性のある開発を行うことができるようになります。これが一つ目のスケーラビリティです。
- もうひとつ、これは当初はそこまで想定していなかったことなのですが、さらに解像度を上げていくと、バックエンドやフロントエンドなど各ファンクションの中でもスケーラビリティを得ることができました。
- このように、Protobuf を使うと二重の意味でスケーラビリティが得られて、非常に良かったです。
- ではなぜこういう分担が Protobuf があると上手くできるのでしょうか?
- このことについては、Protobuf 以前と比較するとよく見えてきます。
API を使った開発について、「コミュニケーション」「開発パラダイム」「ドメイン理解」の三つの観点で考えてみましょう。
- まずコミュニケーションですが、Protobuf 以前は、バックエンドのエンジニアが JSON をイシューに貼り付けて「こういう形のレスポンスで行きます」というような形で進んでいました。
- 経験上、これだと雰囲気的に良さそうかくらいしか議論できません。
- 例えば、あるフィールドが必須なのかオプショナルなのかというようなことは JSON には登場しませんし、もっと込み入った取りうる値の集合についても、そうです。さらに重要なこととして、それがなんであるのかということは、そこには書かれていないのです。
- その結果、開発が進む中で API 定義についての手戻りや確認が大きなコストとなって返ってきます。
- つまり、プロジェクト進行上、バックエンドとフロントエンドを別けたとしても、その間で多くのコミュニケーションが発生してしま、ベロシティを低下させてしまいます。
- さらに、API の実装を進める中でデータ構造の細部をしれっと変更するようなこともできてしまいます。
- そのようなことを意図的に行う人はいないでしょうが、「どこまでが API の契約なのか?」というのは JSON を見せただけでは自明ではないので、それが起こり得ます。
- これに対して Protobuf 以降は、API について厳格に合意できるようになりました。
- API についての確認・議論の多くは API 定義時に明示的に行えますから、確認・手戻りを大幅に減らすことができますし、
- 実装フェーズに入った後に合意した API を変更する際も明示的な手続きが必要になります。
- ちなみに API に合意したあとは、型で保証されたモックをすぐにバックエンドから提供することで、バックエンドとフロントエンドで直ちに並列開発ができるようにしています。
- API の開発パラダイムも、RESTful API のときと比較して少し変わったなと思っています。
- RESTful API では、「エンドポイント」をひとつずつ実装するということが多かったように思います。
- 各エンドポイントは、RESTful API では「リソースAとその関連リソースB-Cを取得する」というような手続きです。
- リソース志向とはいえ、実装粒度自体はほぼ手続きであったのがそれまでの開発のパラダイムでした。
- リソース=オブジェクトをモジュール化の単位として考えると、モジュールごとに実装するようなことは十分にできていなかった、と言えます。
- この状況は Protobuf を使うと意外と大きく変わりました。
- Protobuf というのは message という「データ」にフォーカスした言語になっています。
- もちろん service という概念で呼び出し手続きについても記述できるようになっているのですが、message と service は明確に分離されていますし、message から書き始めることもできます。
- したがって、ドメイン上のオブジェクトをきちんと構築することができます。
- そのように構築したオブジェクト群に対して、serializer などの形で API の実装もモジュール化して行くことができます。
- このことによって、エンドポイントよりもさらに細かいレベルに実装が自然と分解されます。
- 「〇〇君はいまモックになってる “LinkCollection” メッセージの実装をお願いします」のような会話ができるようになります。
- Protobuf というのは message という「データ」にフォーカスした言語になっています。
- 要するに、Protobuf を使うことで、手続きをひとつひとつ実装するようなパラダイムから、オブジェクトをひとつずつ実装するようなパラダイムに変化しました。
- 最後にドメイン理解 - 何を作っているかについてのチームの認識 - の観点での変化がありました。
- これは特にタイムライン機能のような抽象度の高い機能を開発している時に問題が大きかったのですが、これまでの開発方法だと重要なドメインオブジェクトやドメインロジックについての定義が隠れてしまうことが多かったです。
- 貼りつけられた JSON はあくまでスナップショットであって、どのようなドメイン上の振る舞いがあるかは一部の人の頭の中にある状態、と言えば良いでしょうか。
- 分かりやすいケースでいうと、「これが null だったら〇〇を出さない」みたいな意味の定義はすぐに暗黙的になってしまいます。
- これは toy example 的な話で、実際にプロダクトにつける機能はもっと複雑な意味を内包していることもありますから、そのようなものを Protobuf なしで上手く構築する方法はありませんでした。
- 加えて、Protobuf で定義した message の名前などはそのままバックエンドとフロントエンドの実装にも使われるので、これがさらに一貫したドメイン理解をもたらしてくれました。
以上のように、Protobuf を導入すると API を作ったプロダクト開発は大きく変わります。
- コミュニケーション
- 昔:JSON をイシューに貼りつけて「こんな感じのレスポンスで行きます」
- 今:API の内容について厳格かつ継続的に合意できている
- 開発パラダイム
- 昔:複数のオブジェクトを含む手続き全体を実装していくしかない
- 今:必要なら個別のオブジェクトを別々に実装していくことができる
- ドメイン理解
- 昔:どのようなドメイン上の振る舞いがあるかは一部の人の頭の中にある状態
- 今:ドメイン上の重要な振る舞いは全ての開発者で共有できている状態
- 昔:どのようなドメイン上の振る舞いがあるかは一部の人の頭の中にある状態
良いことだらけの Protobuf なので、積極的に使っていきましょう。
ここまで読んでくださりありがとうございました!この記事は速習会で話したことの前編になります。
後編では、izumin がProtobuf を使っていくための実践的な開発フローやツールチェインについて色々と説明してくれます。ここに書いたようなこともより具体的にイメージができると思いますし、OSS として公開しているツールチェインを活用していただけるかもしれませんので、ご期待ください。