212
164

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

BFF(Backend For Frontend)入門:なぜ中間にサーバーを置くのか?

212
Posted at

最近、マイクロサービスやフロントエンド開発の文脈でよく耳にするのが「BFF」です。「フロントエンドのためのバックエンド」という名前は知っていましたが、いざ「API Gatewayと何が違うの?」とか「具体的に何を担当させるべき?」と聞かれると、意外と言語化が難しいものです。そこで今回は、これまで曖昧に理解していたBFFの定義を整理し、なぜこの「中間層」が重要なのかを改めてまとめてみました。

1. BFF(Backend For Frontend)とは何か

BFF(Backend For Frontend)とは、その名の通り「フロントエンド専用のバックエンド」を構築する設計パターンです。一般的な定義としては、「ブラウザやスマホアプリといったフロントエンドと、基盤となるバックエンドの中間に専用のサーバーを設置し、バックエンドとの通信をすべてその中間層に移譲する」手法を指します。こうすることで、フロントエンドは、背後に控える無数のマイクロサービスと直接やり取りするのではなく、このBFFという単一の窓口とのみ通信を行うようになります。

1.1 API Gatewayとの違い

ここで混同されやすいのが「API Gateway」との違いです。

比較項目 API Gateway BFF (Backend For Frontend)
主な役割 全社共通の「門番」 特定のUI専用の「コンシェルジュ」
主な機能 認証・認可、流量制限、共通ログ、ルーティング データの集約・整形、通信方式の変換、UI最適化
主な目的 システム全体の「セキュリティ」と「統制」 特定クライアントの「使いやすさ」と「速度」
管理単位 システム全体で1つ(または少数) クライアントの種類(Web/iOS/Android)ごと
担当チーム インフラ、またはプラットフォームチーム フロントエンド、または各プロダクトチーム

このように、API Gatewayが「システム全体の身を守るための共通基盤」であるのに対し、BFFは「特定のユーザー体験を最高にするための個別最適化レイヤー」であるという違いがあります。

1.2 BFFは「APIを作る場所」ではない

BFFを設計する上で重要な視点は、BFFは「リソース(データ本体)を生成する場所」ではないということです。BFFは、バックエンドの各サービスが持つデータ構造や命名規則といった「バックエンド側の都合」が、そのままフロントエンドに流れ込まないように食い止める「境界層」として機能します。

そのため、フロントエンドがバックエンドのDB構造を意識せざるを得ない状況を防ぎ、あくまで「ユーザー体験(UI)」に最適化されたインターフェースを提供することが大切です。それがBFFというレイヤーを設ける目的です。

2. なぜ BFF が必要になるのか

「中間にサーバーを置くなんて、手間が増えるだけではないか?」と感じる方もいるかもしれません。しかし、フロントエンド(FE)とバックエンド(BE)を直接繋いだまま開発を続けると、構造上避けられない「3つの痛み」に直面することになります。

2.1 フロントエンドを苦しめる「3つの痛み」

  1. Over-fetching(データの取りすぎ)
    バックエンドのAPIは、汎用性を高めるために多くの情報を返しがちです。例えば「ユーザー名」だけを表示したいのに、APIを叩くと住所や過去の注文履歴、内部的な設定フラグまで巨大なJSONで返ってくることがあります。これはモバイルデバイスの通信帯域を圧迫し、パフォーマンス低下の直接的な原因となります。
  2. Under-fetching(データの不足)
    逆に、1つの画面を作るのに必要な情報が複数のAPIに分散しているケースもあります。商品詳細画面を表示するために「商品情報API」「在庫API」「レビューAPI」「関連商品API」と、何度もリクエストを投げなければなりません。リクエストの数だけオーバーヘッドが発生し、画面の表示速度はどんどん遅くなってしまいます。
  3. 機密情報の露出
    バックエンドのロジックがフロントエンドに透けて見えるのも問題です。APIが返す生データの中には、フロントでは隠しておきたい内部ステータスや、エンドユーザーには見せるべきではないパラメータが含まれることがあります。BFFがない状態では、これらがブラウザのデベロッパーツールなどで簡単に閲覧できてしまうリスクがあります。

2.2 マイクロサービス化で加速する「責務のズレ」

さらに、システムがマイクロサービス化されると、この問題は深刻さを増します。バックエンドは「ビジネス機能」ごとに最適化されていきますが、フロントエンドは「ユーザーの体験(UI)」ごとに最適化される必要があるからです。

APIが画面単位に設計されていないため、複数のAPIを呼び出し、複雑なパズルを組み合わせるようなデータ加工ロジックがフロントエンド側に散らばってしまいます。その結果、バックエンドが少し仕様を変えただけでフロントエンドが連鎖的に壊れてしまうといった、強い依存関係(密結合)が生まれてしまうのです。

2.3 開発プロセスの独立:待ち時間をゼロにする

BFFの導入は、技術的な解決だけでなく「開発の進め方」にも恩恵をもたらします。BFFという層をフロントエンドチームが管理できれば、バックエンドのAPIが完成するのを待つ必要がありません。まずはBFF側で「理想のレスポンス」を返すモック(ダミーデータ)を定義してしまえば、フロントエンドは先行して開発を進めることができます。これにより、バックエンドとフロントエンドの「開発速度の差」を吸収し、チーム全体のデリバリー速度を劇的に向上させることが可能になります。

BFFは単に「あると便利」な道具ではありません。フロントエンド(UI)とバックエンド(ビジネスロジック)の間にどうしても生じてしまう「責務のズレ」と「開発速度の差」を解消し、健全な分離を保つために必要不可欠な層なのです。

3. BFF でやりたいこと / やりたくないこと(役割と責務)

BFFを導入する際、大切なのは「これはBFFがやるべきことか?」を自問自答することです。よい設計とは、単に機能を追加することではなく、「何をやらないか」を明確にすることにあります。

3.1 BFFが積極的に引き受けるべき「責務」

BFFの主な仕事は、フロントエンドにとっての「情報の最適化」と「安全な仲介」です。

  • APIの集約と分解
    複数のマイクロサービスからデータを集め、1つのレスポンスにまとめてフロントエンドに返します。これにより、クライアント側の通信回数を劇的に減らすことができます。
  • フロントエンド向けのデータ整形
    バックエンドから返ってくる値を、画面表示に最適な形に加工します。例えば、日付フォーマットの変換や、バックエンド特有の「0/1」というフラグを「停止/稼働」といった表示用文言に置換する処理などがこれにあたります。
  • 通信方式の変換
    バックエンド間では高速な「gRPC」で通信し、フロントエンド(ブラウザ)との間では扱いやすい「JSON/REST」に変換するといった、プロトコルの架け橋としての役割を担います。
  • セキュリティの集約
    外部には見せたくないバックエンド用のAPIキーをBFF内部で隠蔽したり、フロントエンドには不要な機密性の高い情報をフィルタリングして削ぎ落としたりすることで、セキュリティ強度を高めます。

3.2 BFFに決してやらせてはいけない「非責務」

逆に、BFFが関わってはいけない領域もあります。ここに手を出すと、BFFは「負債の温床」へと変わります。

  • ビジネスロジックの中核
    「商品の税込み価格を計算する」「在庫の引き当てを行う」といった、サービスの根幹に関わるビジネスルール(ドメイン知識)は、必ずバックエンド側に持たせるべきです。これらがBFFに漏れ出すと、機能追加のたびにBFFとバックエンドの両方を修正しなければならなくなります。
  • データベースへの直接アクセス
    BFFはあくまで「通信の仲介役」であり、自分自身のデータベースを持つべきではありません。BFFはステートレス(状態を持たない)であるべきで、データが欲しいときは必ずバックエンドのAPI経由で取得するのが鉄則です。
  • バックエンドAPIの完全な置き換え
    バックエンドの仕様が気に入らないからといって、全ての処理をBFFでラップし直そうとするのは危険です。BFFが巨大な壁となり、バックエンド側の進化を阻害する原因になってしまいます。

4. BFF のアンチパターン

「BFFを導入したのに、むしろ開発が辛くなった」という事態を避けるためには、以下の落とし穴に注意が必要です。これらは、設計の目的を見失ったときによく現れる症状です。

4.1 ただの「パススルー(中継)」サーバー

バックエンドのAPIを、何の加工も集約もせず、ただ右から左へ受け流すだけの状態です。「将来使うかもしれないから」と、とりあえず全てのAPIをBFF経由にするのは危険です。これでは、単にネットワークのホップ数(通信の経由地点)が増えてパフォーマンスが低下し、管理すべきサーバーが1台増えただけという結果に終わります。明確な「加工・集約・変換」の必要性がないのであれば、それはBFFの出番ではありません。

4.2 「共有BFF」の肥大化

Web、iOS、Androidといった異なるプラットフォームに対して、1つのBFFで共通して対応しようとするパターンです。「コードを共通化して楽をしたい」という誘惑に負けてこれを行うと、結局どのプラットフォームにとっても中途半端な、汎用的なインターフェース(IF)が出来上がります。これでは「特定のフロントエンドのために最適化する」というBFF本来の目的が失われ、各プラットフォームの都合がBFFの中で複雑に絡み合う「スパゲッティ状態」を招きます。

4.3 「もう一つのモノリス」化

便利だからといって、あらゆるロジックをBFFに詰め込んでしまう状態です。バックエンド側を修正するのが面倒だからと、BFFで無理やり複雑な計算やデータの突き合わせを行い続けると、BFFは「誰も仕様がわからない巨大な中間層」へと変貌します。これが進むと、バックエンドはただのDB操作代行になり、BFFがかつての巨大なモノリスと同じ問題を抱えることになります。

BFFは導入すること自体が目的ではなく、導入によって「設計の難易度が上がる」という側面を持っています。明確な役割を持たせないまま「ふわっと」導入してしまうと、システム全体をより複雑にするだけの負債になってしまうのです。

5. BFF 設計で事前に考えておくべきこと

BFFは単なる「中間サーバー」ではなく、フロントエンドとバックエンドの橋渡し役となる重要な「設計レイヤー」です。そのため、事前に「誰がどこまで責任を持つか」を明確に定義しておく必要があります。

5.1 境界線の定義(ロジックの所在)

最も重要なのは、バックエンドとBFFの「境界線」をどこに引くかです。例えば、「ユーザーの名前を表示する」際に、名字と名前を結合するのはBFFでやるのか、それともバックエンドのAPIが最初からフルネームを返すべきなのか。こうした細かな役割分担を事前に決めておかないと、同じような加工ロジックが各層に散らばり、二重管理の原因になります。基本的には、「ドメインに紐づくロジックはバックエンド、表示に特化した加工はBFF」という基準を持っておくのが健全です。

5.2 認証・認可の終端をどこにするか

セキュリティの扱いも設計の要です。ブラウザからのリクエスト(Cookieなど)をBFFで一度受け取り、BFFがバックエンド用のアクセストークン(JWTなど)に貼り替えて通信を行うのか、あるいはBFFはトークンを素通しするだけにするのか。BFFを「セキュリティの壁(終端)」として機能させるかどうかで、インフラ構成や実装の難易度が大きく変わります。

5.3 エラーハンドリングの責任所在

マイクロサービスでは、呼び出し先のサービスの一部が死んでいることが珍しくありません。例えば、商品詳細画面で「関連商品API」だけがタイムアウトした場合、BFFは画面全体をエラー(500)にするのか、あるいは関連商品の項目だけを空(null)にして、メインの画面は表示させるのか。この「部分劣化」をどこまで許容するかの判断は、BFFの大切な責務の一つです。

5.4 「画面別」にするか「OS別」にするか

BFFをどの単位で作るかも重要な決断です。iOSとAndroidでデザインやリリースサイクルが大きく異なる場合、BFFを別々に分けることで、一方の変更がもう一方に影響しない「独立性」を確保できます。逆に、仕様がほぼ共通であれば、リソース効率を考えて1つのBFFにまとめる選択肢もありますが、その場合は将来的な「足の引っ張り合い」のリスクも考慮しなければなりません。

6. 技術選定の考え方(なぜその技術なのか)

BFFの技術選定において、最も重要なのは「処理性能の高さ」や「流行」ではありません。最も優先すべきは、「そのBFFを誰が開発し、誰が最後まで責任を持って運用できるか」という視点です。

6.1「フロントエンドチームが運用できること」が最優先

BFFは、UI(フロントエンド)の要求に合わせて頻繁に形を変えるレイヤーです。そのため、BFFのコードを書くのはフロントエンドチーム、あるいはフロントエンドに精通したメンバーであることが一般的です。もし、バックエンドチームしか扱えない言語でBFFを作ってしまうと、フロントエンドの細かな表示修正のたびにバックエンドチームへ依頼を出すことになり、BFFを導入した目的である「開発速度の向上」が損なわれてしまいます。

6.2 なぜ Node.js / TypeScript が選ばれるのか

現在、多くのプロジェクトでBFFに Node.js と TypeScript が採用されていますが、それには明確な技術的メリットがあります。

  • 型定義(Schema)の共有
    フロントエンドと同じ TypeScript を採用することで、APIのレスポンス型を共有したり、共通のバリデーションロジックを使ったりすることが容易になります。これにより、「BFFの型定義とフロントエンドの型定義が食い違ってバグが出る」といった事態を未然に防げます。
  • 非同期処理の強さ(I/O待ちへの耐性)
    BFFの主な仕事は「複数のAPIを叩いて待つ」ことです。Node.js は非同期処理が得意なため、大量のAPIリクエストを並列で効率的に捌くことができ、BFFの特性と非常に相性が良いのです。

6.3 インフラの習熟度と運用・監視

技術選定ではコードの書きやすさだけでなく、「リリース後の運用」も考慮に入れる必要があります。バックエンドと同じコンテナ基盤(KubernetesやAWS ECSなど)に乗せられるか、既存の監視ツール(DatadogやNew Relicなど)でパフォーマンスを追跡できるかを確認しましょう。BFFはシステム全体の単一障害点(SPOF)になりやすいため、他のマイクロサービスと同等の「堅牢な運用環境」を準備することが不可欠です。

BFFは、技術のカッコよさで選ぶものではありません。自分たちのチームが自信を持ってデプロイし、障害時に調査し、改善し続けられる言語と環境を選ぶこと。それが、BFFを負債にしないためのポイントです。

まとめ:BFFはフロントエンドの「自由」と「速度」を取り戻すための鍵

BFF(Backend For Frontend)は、単なる「中継サーバー」や「便利ツール」ではありません。それは、複雑化するバックエンドの都合からフロントエンドを解放し、ユーザー体験(UX)の向上に集中するための「戦略的な境界線」です。

最後に、今回整理した重要なポイントを振り返ってみましょう。

  • 役割の明確化:全社共通の「門番(API Gateway)」ではなく、特定のUIに寄り添う「専属コンシェルジュ(BFF)」であること。
  • 痛みの解消:Over-fetchingやUnder-fetchingといった通信の非効率を解決し、フロントエンドが扱いやすい「理想のデータ」を提供すること。
  • 設計の規律:ビジネスロジックやDB操作といった「やってはいけないこと」を排除し、BFFが太りすぎないようにコントロールすること。
  • 自律的な開発:フロントエンドチーム自身がBFFを管理することで、バックエンドとの依存関係を切り離し、デリバリー速度を加速させること。

もし今、フロントエンドのコードが「APIを叩くためのパズル」で埋め尽くされていたり、バックエンドの小さな変更に怯えていたりするなら、それはBFFを導入すべきタイミングかもしれません。もちろん、サーバーが1台増えることによる運用の手間は無視できません。しかし、それによって得られる「開発の独立性」と「変更に対する柔軟性」は、大規模なシステム開発において武器になります。

最後まで読んでいただいた方、ありがとうございました。

212
164
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
212
164

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?