lacolaco

Google Developers Expert for Angular / 技術的なことや技術的じゃないことを書きます

GraphQLとRESTfulについて今日考えてたこと Backend for Usecase/Resourceについて

DISCLAIMER: これは本当にただのメモ書きで、これがベストプラクティスだとかいう話ではないので、同じようなことを考えてる人いたら今度議論しましょうよ、って程度の話の種。

GraphQLを使うべきスポット、RESTfulが好ましいスポットについて今日ぼんやり考えていて、なんとなく言語化ができる気がするので文字起こししてみる。

Backend for UsecaseとBackend for Resource

バックエンドのAPIには2種類あって、

  • 「データ」を構成する「リソース」を提供するもの
  • アプリケーションの「ユースケース」がもつシナリオのなかで登場する「データ」部分を埋めるためのもの

を区別することが必要そう、と思っている。

まず前者を Backend for Resource (BFR)と呼ぶことにする。これはわかりやすくて、これはまさしくRESTfulそのもの。 RDBやそうじゃないDB、あるいはファイルストレージかもしれない永続化されたリソースにURIを付与し、外部からアクセス可能にするのが役目。 BFRの設計はリソースのスキーマに依存する。

次の後者を Backend for Usecase (BFU)と呼ぶことにする。これがGraphQLが向いていそうなところ。 フロントエンドのユースケースのなかで、永続化されたデータが必要になった時の問い合わせ先。 つまり、BFUの設計はフロントエンドのユースケースに依存する。

f:id:lacolaco:20180712230727p:plain

なんで分けたいのか

BFFの文脈でいろんな理由が挙げられているとは思うが、個人的にはそのシステム自体のライフサイクルの違いに合わせた分割が、柔軟な開発サイクルを支えてくれるんじゃないかと思っている。

フロントエンドはユーザーが触れる最前線にあるので、UXの改善、ユースケースの再設計は成長段階のプロダクトにおいて頻繁に発生する。 フロントエンドについては一旦諦めるとして、バックエンドの中には、そうしたユースケースの再設計に巻き込まれてもしょうがない部分とそうでもなさそうな部分がある。 前者が、「ユースケースに対するデータプロバイダー」としてのバックエンド、つまり上述のBFUで、後者が「リソースコンテナ」としてのバックエンド、つまりBFRじゃないかと思う。

ユースケースが再設計されたとしても、リソース自体に変化があるわけじゃないなら、その部分は残したい。ユースケースに依存する範囲を明確に分けたい、というのが僕のBFU/BFRに対するモチベーションの大きな部分。 その境界でバックエンドのサーバーごと分けてしまうというのは、昨今のコンテナ化の流れにもマッチしてそうな気がする。

なんでBFUはGraphQLがよさそうか

フロントエンドのユースケースの中では目的が必ず存在してデータ要求が生まれる。 すごく単純化したら「ID=2のUserのデータがほしい」ではなく「ID=2のユーザーの名前を表示するためのデータがほしい」という話で、そのユースケースにとってはユーザーの名前がUserテーブルのNameカラムに保存されているとかそんなことはどうでもよく、ただユーザーの名前がほしい、というニーズだけがある。

BFUがない場合は、フロントエンドのなかでBFRから受け取ったデータをユースケースに合った形に自分で整形することになる。あるいはBFRが拡張されてユースケースを受け入れはじめるかのどちらか。

BFUがある場合は、フロントエンドはBFUにユースケースを投げつける。ユースケースを定義するのはフロントエンドの仕事なので、GraphQLのようにフロントエンドでほしいデータの形を定義するのがマッチするはず。

フロントエンド、BFU、BFRが分かれたとき、それぞれのシステムのライフサイクルは次のようになる。

f:id:lacolaco:20180713000156p:plain

悲しいことにフロントエンドはまっさきに壊されるが、それは宿命として諦めるとして、BFUがあることでBFRは長生きすることができる。

やっちゃいけないこと

BFUは「ユースケースに対するデータプロバイダー」としてのバックエンドであるから、常に実装の要件はフロントエンドのユースケースによって決定される。 そのため、次のことはやってはいけない。

  • 「DBからデータが取れるから」というボトムアップで実装すること
    • 本来依存しなくてもよい部分にBFRへの依存が発生する。
  • 複数のユースケースをひとつのqueryで対応しようとする
    • たまたまスキーマが似ているだけでDRY的にまとめるのは本来関係をもつはずのないユースケース間の関係を生んでしまう

BFUは常にアプリケーションのために存在するが、BFRはアプリケーションが無くても成立する。


とりあえずここまで。今日10分くらい会社でryopekoさんと雑談してたネタなのであまりしっかり練った考えではないけど、こんな感じのシステムを作って試してみたい。