肥大化したGraphQLスキーマを整理する進め方
「GraphQLを入れたときは綺麗だったのに、気づけばスキーマが2000行を超えて誰も全体像を把握していない」——これはGraphQLを採用したプロダクトが2〜3年運用されると、ほぼ確実にたどり着く状態です。似た名前のフィールドが3つ並び、どれが正しいか誰も分からない。特定の画面を開くとレスポンスが数秒かかる。新機能を1つ足すのに既存スキーマへの影響調査だけで1日潰れる——こうした相談を私たちはよく受けます。
GraphQLは「クライアントが必要なデータだけ取れる」という触れ込みで導入されることが多いですが、スキーマ自体の設計統制がないと、REST以上に負債が溜まりやすい技術でもあります。この記事では、既に運用中でクライアントも複数動いているGraphQLスキーマを、サービスを止めずに整理していく進め方を解説します。
肥大化したスキーマで実際に起きる症状
まず、相談段階でよく見る具体的な症状を挙げます。どれか1つでも当てはまれば整理の優先度は高いです。
- 同じ意味のフィールドが複数ある:
user.nameとuser.fullNameとuser.displayNameが併存し、どれを使うべきかコードコメントにも残っていない - N+1クエリでレスポンスが遅い: 一覧画面で100件表示するのに、関連データ取得のSQLが100回以上発行されている(DataLoaderが入っていない、または途中から入れたが全リゾルバに展開されていない)
- 非推奨フィールドが消せない:
@deprecatedは付いているが、どのクライアントがまだ使っているか分からず1年以上放置されている - 1つのQueryやMutationが太りすぎている: 引数が15個を超え、null許容の組み合わせで何通りもの意味を持つフィールドになっている
- N+1を隠すためにキャッシュで誤魔化している: 根本のリゾルバ設計を直さず、Redisキャッシュを足して延命している
これらは個別に直せますが、共通する根本原因は1つです。スキーマの変更を誰も一元的にレビューしていないこと。機能追加のたびに担当者が「とりあえずフィールドを足す」判断を積み重ねた結果、全体設計の一貫性が失われていきます。
進め方1: スキーマの棚卸し(現状把握なしに手を入れない)
いきなりリファクタリングに着手せず、まず現状を可視化します。
- 使用状況の計測: Apollo StudioやGraphQL固有のロギングミドルウェアで、各フィールド・各リゾルバの呼び出し回数を数週間分取得する。使われていないフィールドは削除候補、多用されているフィールドはパフォーマンス最適化の優先対象になる
- クライアントの棚卸し: このAPIを叩いているクライアントを全て洗い出す(Webフロント、モバイルアプリ、社内ツール、パートナー向け外部API)。社内で把握しきれていないクライアントが後から出てくることも珍しくありません
- N+1の検出:
graphql-rubyならGraphQL::Batchや bullet gem、Node系ならdataloaderの導入状況とカバー範囲を確認し、実際にSQLログを見てN+1が起きているリゾルバを特定する
この段階で「重複フィールドが47個」「N+1が起きているリゾルバが12箇所」のように定量化できると、優先順位づけが感覚論から離れます。
進め方2: deprecationを運用に乗せる
GraphQLには @deprecated(reason: "...") という仕組みがありますが、多くの現場で「付けただけで終わっている」状態になっています。運用に乗せるには以下が必要です。
- 廃止理由と移行先を必ず書く:
@deprecated(reason: "Use fullName instead. Will be removed after 2026-10-01.")のように、代替フィールドと削除予定日をセットで書く - 利用状況を継続的に監視する: 廃止予定フィールドへのクエリが来たらログに残す仕組みを入れ、呼び出しがゼロになったタイミングで削除する。呼び出し元が社内クライアントだけなら数週間、外部パートナーが絡む場合は最低でも1〜2ヶ月の告知期間を見る
- 削除は別リリースで行う: deprecated化と実削除を同じPRでやらない。deprecated化だけを先にリリースし、監視期間を置いてから削除する2段階にする
ここを飛ばして「使われていなさそうだから消す」を繰り返すと、想定していなかったクライアントを本番で壊します。GraphQLのスキーマは一度公開すると「誰が使っているか分からない」という性質を持つため、RESTのエンドポイント削除より慎重さが必要です。
進め方3: N+1対策はDataLoaderの導入範囲を広げる
N+1問題への対処は「気づいたリゾルバに個別にDataLoaderを足す」対症療法になりがちです。整理のタイミングでやるべきは範囲の拡大と一貫性の担保です。
- バッチロード対象を洗い出す: 「あるオブジェクトのリストから、関連する別オブジェクトを取得する」パターンを持つリゾルバを全て棚卸しし、DataLoaderの適用漏れを潰す
- 1リクエスト内でのキャッシュとバッチの粒度を揃える:
graphql-rubyのGraphQL::Batchは1クエリ実行内でロード要求をまとめてバッチ化する仕組みなので、これに乗らない独自実装のキャッシュ層が混在していると効果が半減する - N+1検出をCIに組み込む:
bulletgem のようなツールをテスト環境で有効化し、N+1が新規に混入したらCIで落とす。手動レビューだけに頼ると、次の機能追加でまた同じ問題が再発する
体感として、一覧画面のレスポンスタイムが3〜5秒かかっていたケースで、DataLoaderの適用漏れを潰すだけで500ms〜1秒程度まで改善することは珍しくありません。インフラのスケールアップより先に、まずここを疑う価値があります。
進め方4: 命名とスキーマ構造の整理
命名の揺れは後から直すほどコストが増えるので、棚卸しの結果をもとに一度方針を明文化します。
- 命名規則を1つに決める:
camelCaseかsnake_case(GraphQLの慣例は前者)、単数/複数の使い分け、getやfetchのような冗長な接頭辞を付けない、といったルールをドキュメント化する - 巨大なQuery/Mutationを分割する: 引数が多すぎるフィールドは、input型に切り出す、あるいは目的別の複数フィールドに分割する
- スキーマをドメイン単位でファイル分割する: 1ファイルに全型が入っている状態は、
graphql-rubyなら型ごとにファイルを分け、モジュールやディレクトリでドメインを表現する。これ自体はAPIの互換性に影響しない内部整理なので、比較的リスクなく着手できる
命名整理は既存フィールドの改名を伴う場合、必ずdeprecation運用(進め方2)を通します。「名前を変えたいから即リネーム」はクライアントを壊す典型パターンです。
いきなり作り直さない、段階移行が基本
スキーマが酷い状態でも、私たちは「全部作り直しましょう」を最初の提案にはしません。理由は3つあります。
- 稼働中のクライアントを一度に全部移行するコストが高い。GraphQLはクライアントごとに使っているフィールドの組み合わせが異なるため、全面刷新は影響範囲の見積もりが極めて難しい
- 段階移行のほうが検証しやすい。棚卸し→deprecation→N+1対策→命名整理、と1つずつ進めれば、各段階でパフォーマンスや不具合の変化を切り分けて確認できる
- ビジネス側の機能追加を止めずに進められる。全面刷新プロジェクトは往々にして「並行して新機能開発も止めない」が難しくなり、両方が遅延します
例外は、スキーマの設計思想自体が根本的に間違っている場合(例: REST APIをほぼそのままGraphQLの型にラップしただけで、GraphQLの利点を全く活かせていない)です。この場合は新スキーマを別名前空間(例: v2 プレフィックス)で並行稼働させ、クライアントを1つずつ移行してから旧スキーマを削除する、という段階的な作り直しになります。それでも「ある日突然全部切り替える」という進め方は避けます。
外注でこの作業を進める場合の注意点
GraphQLスキーマの整理を外部チームに依頼する場合、発注者側で確認しておくとよい点です。
- 棚卸しフェーズを飛ばして見積もりを出す業者は避ける。現状の使用状況を計測せずに「全部綺麗にします」という提案は、後から想定外のクライアント破壊が起きるリスクを見落としている可能性が高い
- deprecation期間をスケジュールに含めているか確認する。フィールド削除までの監視期間を無視した見積もりは、実際には「消せない」状態で終わることが多い
- N+1対策の効果を数値で示せるか。改善前後のレスポンスタイムを計測し、Before/Afterを提示できる進め方かどうかは、実質的な改善が起きているかの試金石になります
既存プロダクトの改善全般に共通する見極め方は、既存プロダクトの改善、外部チームが最初に見る観点でも整理しています。またAPIそのものの設計を見直す場合は、モノリスからAPIファーストへの移行も合わせて参考にしてください。
まとめ
- GraphQLスキーマの肥大化は、フィールド重複・N+1・放置されたdeprecatedフィールドという具体的な症状で現れる。まず使用状況を計測して定量化することが整理の出発点
- deprecationは「付けて終わり」ではなく、利用状況監視と削除予定日をセットにした運用に乗せる。命名変更やフィールド削除は必ずこのプロセスを通す
- 全面作り直しではなく、棚卸し→deprecation運用→N+1対策→命名整理という段階移行で、クライアントを壊さずに進めるのが基本方針
torcheeesでは、稼働中のGraphQL APIを対象にした診断と、継続的な改善支援を提供しています。スキーマの現状把握から段階的な整理まで、既存のクライアントを壊さない進め方で伴走します。まずはお問い合わせフォームからご相談ください。