GraphQLは銀の弾丸か

銀の弾丸なんてないと言われつつ、割とGraphQLはRESTの上位互換のような、銀の弾丸扱いされることが増えてきていると感じる。

過去触ってきた中で疑問に思うことがあるものの、まとまった技術記事にするほど思考がまとまってないのでメモがわりにここに供養する。

(「過大評価かも?」って内容なので反対意見ばかりになるが、別に反対派ではない)

本当に開発速度が速いのか

これについてはGraphQLだから必ずしも早くなるかは疑問に感じる。 何と比較し、どのようなスキーマ設計で開発を進めていくかに依存しており、「仮説検証フェーズだから素早く作るためにGraphQLだよね」って短絡的に繋げることはできないんじゃないだろうか。

半自動作成できる

まずこの主張の前提には「スキーマ定義がテーブル定義と同等である」が多く含まれていることが多い。 たとえばHasuraのようなサービスもそうだし、テーブル定義をもとに半自動的にスキーマを生産することでなんか素早くできるよねってケースが多い。

ただ後にも書くが「スキーマ定義がテーブル定義と同等である」には疑問があるし、半自動的に作成されたコードをバックエンドに使うには怖い。 特にそれだけだとほぼ剥き出しのDBをいじるのと同義だ。 それでいいならFirestoreでもいいし、RESTでも自動作成できるものはある。

複数エンドポイントの統合

ということで価値があるのはクエリの柔軟性の高さにより複数個作らないといけなかったエンドポイントが少なくすむようになることかなと思う。 ただ柔軟性の高さは怖さでもあって、たとえばリレーションがめちゃくちゃ離れたデータを1クエリで取得するために強引にとってくるって感じで、むしろ不必要なデータを大量にとってきてパフォーマンスを悪化させるような例もある。 バックエンド側としてあらゆるクエリを考慮することは難しいのでパフォーマンスチューニングもしづらいし、この辺の秩序をどうやって保ってくんだっけ?ってところのハードルはある。

フロントエンドの体験

使ってるライブラリによるかもしれないがフロントエンドの開発体験はむしろ悪くない?って思う。 わざわざクエリ書かないといけないし、gql書いた後にTypeScriptファイルが生成されてそれを型情報として渡して...みたいなステップは(半自動で裏に回るにしても)相対的に手数が多い。 RESTでOpenAPIでクライアント生成してできた関数を叩けば型情報付きで返ってくるのは、フロントエンドに閉じた話とすればそっちの方が楽じゃない?と思う。

というのでフロントエンドエンジニアがGraphQLが楽!っていうのはあまりわからない。 バックエンドエンジニアとのコミュニケーションなく勝手に欲しいデータ取ってこれるって話なのかな?

Server Components

そもそも最近はNext.jsでgetServersidePropsするなり、RemixでgetLoaderするなり、Server Components内でdb叩くなり、いわゆるRailsのような書き心地でページごとにDB叩く書き方が容易になってきた。 型情報も簡単に受け渡しできるし、パフォーマンス最適化の考慮やセキュリティ的な懸念、モデル設計の苦労もなくなる。 開発速度という観点では一番これが早いように思う。

モデリングの難しさ

やっぱり人間として一番楽なのは目の前の実装に最適化した実装だ。 たとえば「ユーザー一覧ページ」では、そのページで必要な情報だけ返すと言うのが一番議論の余地が少ない実装者ごとによるブレが少ないものになる。

一方でGraphQLは(その利点を享受するためには)ユースケースに左右されないモデリングが必要となる。 たとえばUserはユーザー一覧ページで使われるか、ユーザー詳細ページで使われるか、はたまた商品一覧ページでその商品へのコメントしたユーザー情報を表示するために使われるかに依存しないモデリングが必要となる。 そうなると何をどういう関係性のもとモデリングしていくかのセンスが求められることとなる。

これに対して一番簡単で大きく失敗しづらいのは、先にも書いたがテーブル定義と一致させる方法だ。 しかしテーブル定義はインフラの都合が絡むものであり、いわゆる設計界隈で批判される「データモデルとドメインモデルは別」という問題もある。

さらにここでいうモデルは参照系であることを考えると、ドメインモデルと一致させるのでなくCQRSのように異なるモデルで考えるのが適切にも思う。 GraphQL界隈はここどうしてるんだろう?って毎回疑問に思うが、本も記事も登壇もここについて詳しく言及してるものがほとんど見当たらなかった。

セキュリティのコントロールが難しさ

実体験として、やっぱりセキュリティはガバガバになりやすいなと感じる。 セキュリティ意識が薄いとなんでもできるスキーマ定義にしがちで、「これが欲しくなった!」って要件があると無秩序に機能が増えがちだ。

しかしデータに対する権限設定って結構難しい。 シンプルに「このデータは誰がどういう条件で見えるべきか」ってのを全モデルの全スキーマに対して検討するのはコストがかかる。 ましてや「このデータは本人か管理者だけ見れる」「このデータは再認証後に見れる」など複雑な権限要求されたら尚更だ。

特にリレーションを追っての抜け道もできやすい。 「商品情報のコメントからユーザ情報に辿り着いて、そこからそのユーザの年収が取得できます」みたいなことが起こりうる。 たとえば自分がCTOだとしてメンバーに自律的に開発してもらう中でこのリスク許容するのなかなかしんどくない?って思う。

これを踏まえるとやっぱりテーブルの写像としてのスキーマ構造はあんまり良くないんじゃないかとなり、Viewごとのモデルをしっかり定義する運用が安全なんじゃないかって思っている。 ただそうなるとGraphQLの利点って薄いんだよね。

動作の担保が難しい

これはテストを書いていて思ったが、どこまでテスト書けば良いの?っていう。 各データを返す、返さない、リレーションなどを含めると、ほぼ無限にパターンが考えられる。 もちろんFWが基礎的なところは担保してるよねってことで妥協して良いとは思うが、書いたテストが100%動作を担保できてるっていう安心感は薄いよなと感じる。

BFFとしてのGraphQLはあり

ここまで否定的に書いたが、BFFとしてのGraphQLはありなんじゃないかと思う。 特定のフロントエンドに依存した構造にならずにすむからだ。

特に「getServersideProps内でGraphQL叩く」とかならセキュリティの懸念も薄くなりほぼDBでも問題がなくなる。


この記事が気に入ったらサポートをしてみませんか?