Slide 1

Slide 1 text

もし今からGraphQLを採用するなら BuriKaigi 2025 2025. 02. 01

Slide 2

Slide 2 text

3 自己紹介 早瀬和輝(@KazukiHayase) ● 2021年BuySell Technologies入社 ● 開発2部 販売グループ EXSチーム ● PjM / テックリード ● Go / TypeScript / React / GraphQL ● 酒 / ポケカ(ポケポケ) / アニメ / 映画 ● 大学が金沢なので、富山にはよく来ていた

Slide 3

Slide 3 text

4 本セッションについて ● GraphQLと周辺技術における技術選定の実例 ● 上記を踏まえた上で、今ならどのような構成にするか 話すこと ● GraphQL自体の紹介 ● GraphQL関連以外の技術選定の詳細 話さないこと

Slide 4

Slide 4 text

5 本セッションについて GraphQLの選定の実例を通じて、 今後GraphQLを採用する際の参考にして欲しい

Slide 5

Slide 5 text

01 02 03 04 05 目次 Index プロダクト特性と全体構成 GraphQL採用の振り返り 周辺ライブラリの技術選定の振り返り もし今ならどのような構成にするか まとめ

Slide 6

Slide 6 text

プロダクト特性と全体構成 01

Slide 7

Slide 7 text

事業紹介 買取・販売の循環を実現する総合リユースビジネスを展開しています。 お客様のニーズに合わせた各種買取・販売チャネルで、自宅に眠るさまざまな不要なものを、誰かの必要なものへと変えています。

Slide 8

Slide 8 text

プロダクト群「バイセルリユースプラットフォーム Cosmos」の開発が進行中 リユースに必要なすべての機能を提供する「リユースプラットフォーム Cosmos」の開発が進行中です。 Cosmosを活用して、バイセルグループ全体での業務効率改善やデータドリブン経営の深化を目指しています。 リユースプラットフォームCosmos 自社開発のリユース特化業務基幹システムでありサービス群の集合体 買取申込 買取・査定 在庫管理 販売 多様なチャネルで収益最大化 CRM -顧客対応- 買取種別に応じた最適なシステム構築 Visit -訪問買取- Store -店舗買取- Promas -商材マスタ- Appraisal -専門査定- Stock -在庫管理- EXS -販売管理- Core -会員管理- Portal -データ利用- Pocket -データ基盤- 買取 専門チームによる真贋・査定と連携 査定 申込 効率的な顧客対応 在庫 在庫管理の最適・効率化 販売 データ 各事業プロセスにある データを一元管理 :基幹システム

Slide 9

Slide 9 text

10 EXSについて EXSとは複数のECサイトへの出品・受注業務を一元管理するWebアプリ 各ECサイトの仕様差異を吸収することで、ユーザーの業務をEXSのみで完結させる

Slide 10

Slide 10 text

11 プロダクト特性 ● BtoBシステムで、認証されたユーザーのみが利用 ● 外部サービスとの連携が非常に多く、それらを非同期で処理する ● 一括出品・受注処理が主な機能で、検索機能と一括操作が重要 ● 主にPCで利用され、将来的にはモバイルにも対応予定

Slide 11

Slide 11 text

12 チーム体制 ● エンジニアは5〜10名 ○ 比較的ジュニアメンバーが多い ● スクラムを採用 ● 開発領域は分割していないが、状況によって分割することもある

Slide 12

Slide 12 text

13 技術スタック インフラ Google Cloud、PostgreSQL、 Cloud Run、Elasticsearch バックエンド Hasura、Go、gqlgen、GORM フロントエンド React(Next.js)、TypeScript、 Apollo Client、GraphQL Code Generator

Slide 13

Slide 13 text

14 全体構成図

Slide 14

Slide 14 text

15 全体構成図 ● Hasuraは簡単なCRUDを担当 ● 同期コンテナはHasuraでは行えない複雑な処理を担当 ● Hasura↔同期コンテナはRemote Schemaという機能で連携 フロントエンド↔バックエンドの通信はGraphQL

Slide 15

Slide 15 text

16 全体構成図 ● 非同期コンテナへはCloud Tasks経由でリクエスト ● 外部サービスとの連携は非同期コンテナで実行 同期コンテナ↔非同期コンテナの通信はREST

Slide 16

Slide 16 text

GraphQL採用の振り返り 02

Slide 17

Slide 17 text

18 GraphQLを採用してみて 総合的に判断してGraphQLを採用して良かった ● データフェッチの柔軟性 ● 型安全性 ● 契約としてのスキーマファースト ● Fragment ColocationによるUXとDXの両立 GraphQLの代表的なメリットを享受できている

Slide 18

Slide 18 text

19 GraphQLのデメリットについて GraphQLの代表的なデメリット ● Queryの自由度の高さ ○ 高負荷なリクエストを簡単に実行できる ● スキーマ設計の難しさ ● 学習コストの高さ

Slide 19

Slide 19 text

20 Queryの自由度の高さ レビューとLinterの2軸で危険なQueryの実行を防止 レビュー スキーマ定義とQueryの両方を テックリード2人が必ずレビューを行う Linter graphql-eslintで Queryのネストなどを自動的に制限

Slide 20

Slide 20 text

21 Queryの自由度の高さ リファインメントの時点で、スキーマやQueryの定義はチケットを分解している

Slide 21

Slide 21 text

22 スキーマ設計の難しさ プロダクトの特性もあり、スキーマはそこまで肥大化していない モール連携などのコアロジックは非同期コンテナで実装されており、 プロダクト全体の規模に対して、必要なGraphQL APIの数は多くない

Slide 22

Slide 22 text

23 スキーマ設計の難しさ 連携先を追加する場合も、引数の追加のみでGraphQLスキーマの変更は不要

Slide 23

Slide 23 text

24 スキーマ設計の難しさ ドメイン的に商品と注文という大きな2つのオブジェクトがあり、 基本的にそれらにフィールドが追加されていく そのため、グラフ構造の複雑化よりも、オブジェクト単体の肥大化が進みやすく オブジェクトが肥大化する方が考慮するべき点が少ない スキーマの拡張の特性も設計の難易度に影響する

Slide 24

Slide 24 text

25 学習コストの高さ 学習コストは非常に高い 使いこなすには一定の学習期間が必要で、それを許容できる体制が必要 特にGraphQL未経験でHasuraを使用する場合は、 GraphQLとHasuraの境界が曖昧になり、混合しやすくなるので注意

Slide 25

Slide 25 text

26 学習コストの高さ GraphQLでより恩恵を受けるのはフロントエンドのため、 深く理解し活用を推進するフロントエンドエンジニアがチームに1人は必要 そうでなければ、総合的に見た時にデメリットの方が目立ってしまう フロントエンド の メリット バックエンド の メリット

Slide 26

Slide 26 text

27 GraphQLを採用する際に考慮すると良いこと ● チームにGraphQLを深く理解しているフロントエンドエンジニアがいるか ● プロダクトの特性上、グラフ構造の方が肥大化しやすいか ○ その場合は設計難易度が上がりやすい ● そのチーム・プロダクトにおいて、デメリットを許容できるか ○ 必ず想定外の事態は発生するので、それに向き合い続ける覚悟も必要 ● キャッチアップ期間を確保できるか ○ 開発初期だけでなく、その後加入するメンバーに対しても

Slide 27

Slide 27 text

周辺ライブラリの技術選定の振り返り 03

Slide 28

Slide 28 text

29 周辺技術の振り返り マッチしたもの ● gqlgen ● GraphQL Code Generator ● graphql-eslint マッチしなかったもの ● Hasura ● Apollo Client 採用した周辺技術に関して、マッチしたものとマッチしなかったものに分けて紹介

Slide 29

Slide 29 text

30 周辺技術の振り返り マッチしたもの ● gqlgen ● GraphQL Code Generator ● graphql-eslint

Slide 30

Slide 30 text

31 マッチしたもの - gqlgen ● GoでGraphQLサーバーを構築するためのライブラリ ● GraphQLスキーマから、構造体やリゾルバを自動生成してくれる gqlgenとは ● スキーマファーストで開発できる ● GraphQL関連の機能が豊富 採用理由

Slide 31

Slide 31 text

32 マッチしたもの - gqlgen ● 当初の目的のスキーマファーストを実現できている ○ 一番最初にスキーマ設計の認識を合わせることができる ○ フロー効率が上がる ● カスタムスカラーやカスタムディレクティブの追加も簡単 ○ 検索した際の情報量も多い ● 現状のユースケースの範囲では、特に大きな不満はない マッチした点

Slide 32

Slide 32 text

33 マッチしたもの - GraphQL Code Generator ● GraphQLスキーマやQueryから、様々なコードを自動生成するツール ● 主にTypeScriptの型定義や関連コードの生成に使用 GraphQL Code Generatorとは ● スキーマファーストで開発できる ● プラグインが豊富 採用理由

Slide 33

Slide 33 text

34 マッチしたもの - GraphQL Code Generator ● スキーマファーストに関してはgqlgenに同じ ● TypedDocumentNodeによる型推論の使い勝手が良い ● fragment-maskingにより、Fragment Colocationを強制できる マッチした点

Slide 34

Slide 34 text

35 マッチしたもの - graphql-eslint ● The Guildによって公開されているESLintのプラグイン ● GraphQLのスキーマやオペレーションに対してLintを実行できる graphql-eslintとは ● GraphQLに関するルールを自動で検証できる 採用理由

Slide 35

Slide 35 text

36 マッチしたもの - graphql-eslint ● GraphQLに関するベストプラクティスなどを強制できる ● カスタムルールの作成が簡単 マッチした点

Slide 36

Slide 36 text

37 周辺技術の振り返り マッチしなかったもの ● Hasura ● Apollo Client

Slide 37

Slide 37 text

38 マッチしなかったもの - Hasura ● データベースのスキーマから、GraphQL APIを自動で構築してくれるOSS ● 外部のGraphQL APIを統合するRemote Schemaという機能もある Hasuraとは ● APIの自動生成による開発速度の向上 ● GUIで簡単に認可制御できる 採用理由

Slide 38

Slide 38 text

39 ● テーブル構造がそのままGraphQLスキーマになる ● 想定よりもHasuraの利用頻度が少なかった マッチしなかった点 マッチしなかったもの - Hasura 想定よりも開発速度が上がらなかった 😢

Slide 39

Slide 39 text

40 マッチしなかったもの - Hasura テーブル構造がそのままGraphQLスキーマになる

Slide 40

Slide 40 text

41 マッチしなかったもの - Hasura ● Queryを定義するのに、テーブル構造の理解が必要 ○ ピュアなフロントエンドエンジニアには難しい ● 欲しい形式で取得できず、フロントエンドで整形処理が肥大化 ○ フロントエンドの実装コスト増 ● テーブル設計がフロントエンド実装のブロッカーになる ○ スキーマファーストではなくなり、GraphQLのメリットが薄れる テーブル構造がそのままGraphQLスキーマになる

Slide 41

Slide 41 text

42 マッチしなかったもの - Hasura ● 発行されるSQLが複雑で、Queryに対応するSQLを変更することはできない ○ 特にAggregation Queriesという、集計用のQueryが重い ● Hasuraのみで解決が難しく、同期コンテナで実装する場面が増加 想定よりもHasuraの利用頻度が少なかった

Slide 42

Slide 42 text

43 ● Queryの定義にテーブル構造の理解が必要 ● フロントエンドでのロジックが肥大化しやすい ● パフォーマンスチューニングの方法が限られる ○ e.g. インデックス追加、Query変更、インフラのスペックアップ ○ 上記で解決できない場合は、Remote Schema等の外部実装が必要 ● 大規模になると上記の問題が発生したり、設定の管理が大変になる ○ 小〜中規模のプロダクトやPoCにはおすすめできる Hasuraを採用する際の注意点 マッチしなかったもの - Hasura

Slide 43

Slide 43 text

44 マッチしなかったもの - Apollo Client ● GraphQLオペレーションの実行するためのGraphQLクライアント ● キャッシュと状態管理に対応した包括的な状態管理ライブラリ Apollo Clientとは ● メジャーなライブラリなので情報量が多い ● 学習コストが低く導入しやすい 採用理由

Slide 44

Slide 44 text

45 ● キャッシュの必要性が低かった ● 機能が豊富な反面、それに伴う課題も発生した マッチしなかった点 マッチしなかったもの - Apollo Client 要件に対してオーバースペックだった 😢

Slide 45

Slide 45 text

46 マッチしなかったもの - Apollo Client ● 最新のデータを表示する重要性が高く、キャッシュを利用しないことが多い ○ e.g. 検索機能、複数箇所から更新されるデータ キャッシュの必要性が低かった

Slide 46

Slide 46 text

47 マッチしなかったもの - Apollo Client ● キャッシュが必要な場合でも、正規化されていて欲しい場面はあまりなかった ○ Query単位でキャッシュできていれば十分 ○ 正規化されているとキャッシュの部分更新など考慮事項が増える キャッシュの必要性が低かった

Slide 47

Slide 47 text

48 マッチしなかったもの - Apollo Client ● 他のGraphQLクライアントと比べて開発が遅い ○ e.g. Suspense、useFragment ● 暗黙的な挙動の把握が大変 機能が豊富な反面、それに伴う課題も発生した https://github.com/apollographql/apollo-client/issues/11151#issuecomment-1730186108

Slide 48

Slide 48 text

49 Apollo Clientを採用する際の注意点 ● 多機能な状態管理ライブラリということを念頭におく ○ 要件に対してtoo matchなケースは少なくない ● 要件から必要な機能を逆算する ○ Apollo Clientしか対応していない機能はそこまで多くない ○ 最低限の機能しか使わないのであれば、他の軽量なライブラリで良い ● 正規化されたキャッシュが必要かを考える ○ 検索機能が重要な場合や、複数箇所からデータが更新される場合は扱いづらい マッチしなかったもの - Apollo Client

Slide 49

Slide 49 text

もし今ならどのような構成にするか 04

Slide 50

Slide 50 text

51 もし今ならどのような構成にするか 振り返りを基にマッチしたものそのまま採用、マッチしなかったものを変更する マッチしたもの ● gqlgen ● GraphQL Code Generator ● graphql-eslint マッチしなかったもの ● Hasura ● Apollo Client

Slide 51

Slide 51 text

52 もし今ならどのような構成にするか Before After Hasrua 不採用 Apollo Client urql

Slide 52

Slide 52 text

53 もし今ならどのような構成にするか

Slide 53

Slide 53 text

54 ● 振り返りで話した通り、プロダクトの特性的に開発速度がそこまで出なかった ● 総合的に見た時に得られるメリットよりも、運用コストの方が高くつく ● 全てgqlgenで実装する方がスキーマファースト開発でき、管理しやすい Hasuraを不採用にする理由 もし今ならどのような構成にするか

Slide 54

Slide 54 text

55 ● 現在Apollo Clientで使っている機能は備わっている ● Graphcacheという正規化されたキャッシュを使うことも可能 ● 正規化されたキャッシュは不要なのでRelayは候補外 urqlを採用にする理由 もし今ならどのような構成にするか

Slide 55

Slide 55 text

まとめ 05

Slide 56

Slide 56 text

57 まとめ ● GraphQLはプロダクト特性やチーム体制などを総合的に判断して採用する ● HasuraやApollo Clientを採用する際は今回紹介した注意が必要 ● 要件を満たせるかだけでなく、過不足ない技術選定が重要 ○ 大は小を兼ねるが、運用コストは高くつく

Slide 57

Slide 57 text

THANK YOU