work plus ~これからの「働く」が豊かになるメディア~

「働く」を豊かにする。をミッションに掲げるフィードフォースが、「働く」を豊かにするための取組みや調査のなかで知ったこと・気づいたことをカジュアルに発信しています。

新規プロダクトに GraphQL を導入した感想を、バックエンドエンジニアに聞いてみた

f:id:workplus:20180328181022j:plain

GraphQLの導入を先導したバックエンドエンジニアに、導入の経緯や採用した感想を聞いてみました!

こんにちは、人事部の川口です。

先日、フィードフォースでは新規プロダクト「EC Booster」をリリースしました!その開発にあたって「GraphQL という聞き慣れない技術を採用した」と聞き、導入を先導したバックエンドエンジニアの @kielze にインタビューしました。

フロントエンドエンジニアから見た GraphQL については小飼が記事を書いていますので、こちらもぜひご覧ください:GraphQLを使ったアプリケーションがリリースされたので勘所を考えた

今回のインタビュイー

EC Booster バックエンドエンジニア @kielze

2017年フィードフォース新卒入社。入社後、研修を経て新規プロダクト EC Booster チームに配属。
現在は同プロダクトにおけるバックエンドの開発を担当する傍ら、Webエンジニアとして就職したい若年層の学習を支援するプログラム「e-Navigator」を立ち上げ、運営を中心になって行っている

現在の開発環境と、 GraphQL の魅力

- まずは、今回リリースしたプロダクト『EC Booster』の開発環境を教えてください。

バックエンドは主に Ruby on Rails を使って開発しています。
GraphQL はフロントエンド向けの API を実装するために採用しました。GraphQL のクライアントライブラリは Apollo を採用し、React と一緒に使っています。

- なぜ新規プロダクトに GraphQL を採用すると決めたのですか?

クライアント ⇔ サーバー間の API をより柔軟に設計するためです。

開発当初は Rails の View を使っていたのですが、より良い UI/UX を実現するためにフロントエンドを React + Redux を使って書き直すことになりました。特に UX は時間をかけて検証し、納得行く形を模索していましたが、なかなかユーザーフローが決まりきらず…ルーティングに強く紐づく REST の API を設計するのが困難でした。
ちょうどその頃に社内で GraphQL が話題に上がっていたので調べたところ「URL に依存しない形で API を作れる」ということが分かり、「これは新規プロダクトにピッタリなのではないか」と感じたため、個人で深掘りしていきました。

考えていたことをチームに提案してみたところ、「試しにアプリケーションに組み込んでみてから判断しよう」ということになり、一部を実装してみたところ良さそうだったので採用された、という感じです。
バックエンドが調査を進めている間にフロントエンドの方でも並行して調査をしてくれていたので、とてもスムーズに導入できました。

他社の導入事例がない…GraphQL 導入までの道のり

- GraphQL の導入事例はまだあまり聞きませんが…前例がない中での導入に不安はありませんでしたか?

不安よりもワクワクの方が大きかったです。

Facebook が中心になって仕様を策定していたり GitHub が採用しているのもあって、簡単に陳腐化するものではなさそうだと感じていました。
また、Ruby で使える graphql-ruby というライブラリは GitHub のエンジニアの方が中心になって作っていて、 GraphQL の実装をしたライブラリの中ではかなり進んでいると感じました。どうしても GraphQL で実現するのが難しいところは REST と組み合わせることで回避できそうだったので、そこまで心配はしていませんでした
(例えば Query だけは GraphQL を使って更新系は REST のまま組み合わせて使っている事例もありました)

フロントエンドエンジニアにとって使いやすいか、というのが一番の懸念でしたが、「React と Apollo の組み合わせで良い感じにいけそうだ」と言ってもらえたため、安心して採用できました。
個人的には、そういった実際に運用をしていく上での知見も含めて自分たちが事例を作っていくぞ、という意識で取り組んでいます。

- GraphQL 導入は、誰がどのように進めたのでしょうか?

声を上げてバックエンド側の初期実装を進めたのは私です。
最初は自分自身で色々と試しながら実装を進め、ある程度見えてきた段階でチームメンバーに積極的に実装してもらったり、設計について議論を重ねたりしました。

ディレクトリ構成やテストについてはまだまだ事例が少なく模索しながらですが、今ではメンバー全員が GraphQL を問題なく使えるようになり、きちんとチームの財産にすることができたのではないかと思っています。

f:id:workplus:20180329094326j:plain

「魅力は、設計が楽になること」GraphQL をプロダクトに採用した感想

- 実際使ってみた感想を教えてください。

GraphQL を採用してみて、設計がかなり楽だと感じました。

REST は決まり事はありますが設計が基本的に自由なので、ルーティングやスキーマの定義、クライアント側との取り決めをほとんどゼロから作っていく必要があります。その点 GraphQL は、エンドポイントは基本的に1つであり、スキーマの定義についても仕様が明確に定められているので、モデルの設計がきちんとできていれば Query (データの取得)に関しては迷うことは少なかったです。

Mutation (登録や更新) に関しては難しさを感じている部分もありますが、複雑なことをしなければ大丈夫だと思います。

 また、クライアントはスキーマに定義してある範囲内で自由にリソースにアクセスできるようになっているため、細かい取り決めを作る必要はありませんでした。もちろん、必要に応じて適宜コミュニケーションを取って進めていますが、API の設計のために長時間の議論を要する、といったことはなかったです。

スキーマに関しては定義が実装に紐付いていることを 確認できるように しており、かつ適宜コメントを書いているので、スキーマがドキュメントとしての役割も果たしています。API を作る時にありがちな、ドキュメントと実装が乖離してしまって管理が難しい、といったことは今のところないですね。

あと、GraphiQL というライブラリが非常に優秀で、スキーマによるドキュメントと照らし合わせながら実際にクエリを叩くことができます。フロントエンドから使う際には実装に組み込む前にクエリをデザインすることができますし、バックエンドが実装を進める際にも手軽に挙動を確認できる手段としてとても便利です。

- 「Mutation が難しい」ということでしたが、どういったところに難しさを感じたのでしょうか?

GraphQL の Mutation は DB の操作に使うことが念頭に置かれているため、それ以外の事をやろうとすると途端に複雑になってしまう、という点に難しさを感じています。例えば今回リリースしたプロダクトでは、メール送信やジョブの実行などの、直接 DB を触るわけではないけれど Query とはいえない処理を Mutation に書くようにしていますが、あまり見通しが良いとはいえません。

また、DBにデータを登録をするような場合でも、複数のオブジェクトを登録しなければならないかつ順番依存があるような場合だと、ロジックが肥大してしまい、Rails で言うファットコントローラーのような状態になってしまがちです。graphql-ruby には  Graphql::Function という仕組みがあってロジックを外に切り出すこともできるのですが、それを使うことで分かりやすくなったかと言われると微妙でした。

こういったことから、更新系については REST なエンドポイントを用意してそちらを使うようにし、データの取得にだけ GraphQL を使うというのもアリなのではないか、と最近では思っています。

graphql-ruby の次のバージョンである 1.8.0 で、Query や Mutation の定義を Ruby のクラスを使って行えるようになるので、それができるようになると少しは設計が楽になるかもしれません(現在は graphql-ruby が提供する DSL を用いて定義する必要があるので)。

- EC Booster の開発における今後の展望を教えてください!

フロントエンドとバックエンドの橋渡しとして GraphQL を採用している、という事例はまだあまり見かけません。そういった中で、今回のリリースにより GraphQL をプロダクションに乗せることができましたし、事例を作ることができました。

今後は、プロダクトを運用していく中でしっかりと GraphQL のベストプラクティスを見つけていき、有用な知見を発信していければと考えています。

個人的には、実装を進めていく中で graphql-ruby にコントリビュートすることができたので、今後もそれを継続していければ良いなと思っています。

f:id:workplus:20180328181727j:plain