🫣

【技術選定】 0→1 の SaaS に採用して感じた GraphQL への向き合い方

2024/10/21に公開

この記事では、ハコベル配車計画の0→1フェーズのSaaSプロダクトにおいてGraphQLを採用した経験から感じたGraphQLへの向き合い方について紹介します。

スライドでも公開していますのでぜひご覧ください。

また、この内容についての発表は下記で配信されていますので、こちらもぜひご覧ください。

https://findy.connpass.com/event/328076/

プロダクトの背景

2022年に、物流DXを実現する新たなSaaSを作るプロジェクトが始まりました。

今まで経験と勘を頼りに行われていて属人化していた配車計画業務にフォーカスしています。この業務を仕組み化し、AIアルゴリズムを用いて配車計画を支援することで業務効率化と属人化の解消を目指したプロダクトです。

しかしながら、当時はアルゴリズムの精度やUIなどが本当にお客様にとって使えるものなのか、仮説が正しいか確証が持てていない状態でした。そのため、先行導入頂いたお客様にフィードバックを得ながら、共同で仮説検証を進めることになりました。

アジャイルに開発を進めていくため、要求の変化に機敏に対応し、持続的に発展可能な体制が求められました。

これまで:経験と勘で策定され、無駄な台数・コストが発生。 業務の属人化により業務負荷・リスクが高まる。 導入後:AIにより、最適な台数・配送コストを実現。 システム化により属人化の解消・業務の高速化。
ハコベル配車計画

プロダクトのアーキテクチャと目論見

これらの背景を踏まえ、「持続的に発展可能」をキーワードにチーム内で技術選定しました。

フロントエンドはTypeScript、バックエンドはGoと、静的型付け言語を採用しました。そして、フロントエンドとバックエンド間のAPI通信にGraphQLを採用しました。

バックエンドはそれぞれ開発に最適な言語で書かれた複数のサービスと連携しており、これらとはgRPCで通信しています。

このアーキテクチャを採用した目論見としては、3つあります。

  1. スキーマファーストで議論し、フロントエンドとバックエンドやマイクロサービス間のコミュニケーションコストを削減
  2. 多種のクライアントからのアクセスが想定されていたため、柔軟なデータ取得が可能
  3. 静的型付け言語を採用したことから、スキーマから型を自動生成することで、型安全性の担保

フロントエンドはTypeScript、バックエンドはGoと、静的型付け言語を採用しました。そして、フロントエンドとバックエンド間のAPI通信にGraphQLを採用しました。バックエンドはそれぞれ開発に最適な言語で書かれた複数のサービスと連携しており、これらとはgRPCで通信しています。
フロントエンドとバックエンド間のAPI通信にGraphQLを採用

GraphQL活用の現状

そして、プロダクトを構築してから、約2年が経過しました。プロジェクトの進捗とGraphQLの活用について、スキーマファイルを計測してみました。

2022年3月~2024年9月までに、スキーマは356回変更され、スキーマの行数は2224行にも及んでいます。

スキーマを見るだけでも、多くの変更が行われGraphQLと共にプロダクトは大きく成長したことがわかります。

2022年3月~2024年9月までに、データ取得のQueryは11個、データ更新のMutationは69個作られています。そして、開発開始から現在までの間に、スキーマは356回変更され、スキーマの行数は2224行にも及んでいます。
2022年3月~2024年9月の実績

GraphQLを採用したメリット

それでは、今回のプロダクトにGraphQLを採用して得られたメリットについて3点、紹介していきます。

1. スキーマ駆動開発が実現

1つ目が、スキーマ駆動開発が実現したことです。

モデルの変更やUIの変更が必要なとき、まずスキーマの変化から考えることで各コンテクストの参照がスムーズになり、設計議論が促進されました。

さらには、スキーマファイル自体が立派なドキュメントとなりました。例えばフロントエンドを開発しているときに、バックエンドのソースコードを読みに行くことがなくなったり、レスポンスをPostmanでチェックするといったことも無くなりました。

さらには、スキーマが先行して決まることで、APIの開発を待たずにモックサーバを活用してフロントエンドで先行して開発することが可能になりました。モックで動く画面を先行して準備できたことで、ステークホルダーからのフィードバックを得やすくなったのは大きかったです。

スキーマ駆動開発が実現し、API設計におけるコミュニケーションコストが削減され、スムーズな開発が実現しました。

2. クライアントからクエリライクに取得可能

2つ目が、クライアントからクエリライクに取得可能であることです。

フロントエンドは、クエリを用いて1回でまとめてデータを取得できます。 RestfulAPIのように複数のAPIを呼び出す必要がなく、オーバーフェッチを防げます。

UIが変わるといった機会が多発したのですが、フロントエンドでクエリを変更するだけで修正が完了します。エンドポイントの追加編集削除といった作業をせずに実装が完了するという大きなメリットがありました。

クライアントからクエリライクに取得可能であることで、要求の変化に対し、最小限度の実装で応じることが可能で、変更コストが最小化しました。

3. 変更の影響範囲が型で検知可能

3つ目は、変更の影響範囲が型で検知可能であることです。

ライブラリを活用しGraphQLのスキーマからほぼノーコンフィグで型を生成できます。

フロントエンドのTypeScriptでは graphql-code-generator を、バックエンドのGoでは gqlgen を採用しました。

https://github.com/dotansimha/graphql-code-generator

https://github.com/99designs/gqlgen

仮説検証にあたり、モデルの変更やスキーマの変更は日常茶飯事でした。そんなとき、スキーマ変更に伴う影響範囲が型制約として静的に検知できました。スキーマの変更があっても型エラーになる部分だけを着目して修正すれば反映できます。

変更の影響範囲が型で検知可能であることで、仕様やモデルの変化を迅速かつ安全に反映でき、アジリティが向上しました。

GraphQLを採用したデメリット

しかし、私たちはGraphQL採用したうえで大きなデメリットを感じていました。それは、柔軟性が高いが故の設計難易度の高さです。

定められた仕様は最低限度なため、設計側での決定が多数必要となります。GraphQLは、Query Resolver, Dataloaderなどの概念や仕様を理解し、世の中のベストプラクティス、様々なルールをプロダクト・チーム特性に応じて検討する必要があります。

私たちはこれらの型化を行わずに、メンバーがそれぞれ判断して開発を進めていたため、後から設計の見直しが発生してしまいました。

そのため、私たちは後追いで Design Patterns を作成しました。

Design Patternsとは、設計パターンの意思決定とその結果を言語化してドキュメントとして記録したものです。具体的には、エラーレスポンスカスタムスカラバリデーションの明示を記録しました。

さらには、意思決定をさらに洗練させるため、内容をそのままテックブログで社外に公開しています。

Hacobell GraphQL Design Patterns
社内のNotionで管理しているDesign Patterns

例えば「エラーレスポンススキーマの定義方法」においては、ある特定のフォームのバリデーションエラーを事例に、エラーレスポンスを設計のパターンを紹介していますが、ドキュメント内だけでも3パターンを挙げています。

以上の経験から、GraphQLは同じようなことを実現しようとしても様々な設計の方法が取れる柔軟性を持っていますが、一度設計に失敗すると、後からの軌道修正は難しくなることがわかりました。

早い段階からプロダクトやチームの特性に応じた設計を行い型化してくことが必要です。そして、後からの軌道修正をしやすくするため、当時の意思決定を言語化して参照可能にすることが重要です。

GraphQLへの向き合い方

GraphQLを0→1のSaaSプロダクトで採用した経験を踏まえ、GraphQLへの向き合い方を3行でまとめました。

GraphQLは、多種クライアントを想定した不確実性が高いプロダクト開発に向いている。しかし、柔軟性が高いが故のカオスを生み出す。初期段階から設計を型化していくことが重要。

設計を型化していくことはGraphQLに関わらず、アーキテクチャや技術選定において、大切な考えだと感じています。React Server Componentsなどの新たなアプローチも登場し、GraphQLに対する時流も変わってきています。

疎結合でいつでも軌道修正できるよう、ADR, Design Doc, Design Patternsなどのツールを活用してチームで合意を取りながら、プロダクトやその時のチームに合った最適なアーキテクチャを引き続き考えていきたいです。

技術選定に関する私の考えはこちらの記事にもまとめていますので、ぜひご覧ください。

https://zenn.dev/bicstone/articles/technology-selection

Hacobell Developers Blog

Discussion