🎪

SSR / SSGの理解を一段深ぼる: BFFアーキテクチャ

2020/10/22に公開

BFFとは

Backend for Frountendの略で、UI/UXを向上させる目的でフロントエンド専用のサーバーを用意したアークテクチャパターンです。

Webアプリケーションサーバーは下記の処理を行います。

  1. リクエストを受ける
  2. DBからデータの取得・更新
  3. ページを構築
    (これはクライアントですることも)
  4. ページ or データの返却

このうち、「DBからデータの取得・更新」とそれ以外をフロントエンドとバックエンドの役割に明確にわけます。

BFFの役割となるサーバーをクライアントをWebサーバーの間に設け、「リクエストを受ける」と「ページ or データの返却」、場合によっては「ページの構築」をここで処理します。

こうすることで、これまでリクエストというUX関わる部分をフロントエンドエンジニアの責務に移行することができます。

ページの構築をクライアントではなくサーバーで行う場合、これもBBFで処理すればUIの構築に関与する部分をフロントエンドエンジニアが包括して担当することができます。

結果、フロントエンドエンジニアはUIの構築とUXの改善、バックエンドエンジニアはデータを管理・操作する処理と綺麗に責務が分離でき、それぞれの処理に専念できるようになります。

BFFはスケール、バックエンドの複雑性の強い味方

Webサービスによっては複数のサービスが連携・関与して構成されるものがあります。

大きなサービスはドメインごとにサービスを分割することで複雑性を排除し、全体のサービスとして拡張性を持てるようにしようという狙いのもと、マイクロサービス化されるケースが増えてきました。

例) ショッピングサービス

これは1つ、もしくは複数存在するクライアントに対して、バックエンドは1つというn:1の組みあわせではなく、クライアントもサーバーもそれぞれ複数存在するn:mの関係であることが特徴です。

上記のようなサービスでは、下記の問題が生じがちです。

  • 複数問い合わせによる同時リクエスト数の制限やリクエストごとのサーバー側の処理コスト
  • クライアントごとにまったく同じAPIでは最適化しきれない
  • APIの変更による修正範囲が多い(修正箇所 * クライアント数)

これらの課題に対してBFFというアーキテクチャが存在します。

BFFというアーキテクチャは新しいものではなく、複数のAPIに問い合わせる必要がある、または多くのクライアントにたいおうしなくてはならないサービスでは古くから採用されてきました。

しかし、昨今ではSSR、NextやNuxtが注目されるようになり、フロントエンドエンジニアとしては自分の提案1つでBFFなアーキテクチャを採用できる、より身近なものになりました。

自分が担当するサービスの特性やUXの改善を要求された時、BFFの考え方と実践方法を知っていることは1つの武器になります。

BFFのメリット

BFFを採用することで下記のメリットがあります。

  • SSRによる検索エンジンの最適化
     BFFの1つの手段としてSSR(Server Side Rendering)を採用することで、SPAと比較した時にSEOで検索性を高めることができます。
     外部からの検索流入でユーザーを集めることを目指す検索系のサービスでは重要です。

  • 初期表示の高速化によるUXの向上
     クライアントごとに取得するデータを最適化することで、初期表示速度を向上させることができます。

  • 画面の読み込み高速化によるUXの向上
     BFFの1つの手段としてSSG(Server Side Generate)を採用することで、ブラウザで画面を構築するのではなく、あらかじめビルドしておいた画面を返却することにより画面の表示速度を向上させることができます。

  • 開発体験の向上
     BFFの開発をフロントエンドエンジニアが担当することで、バックエンドの業務と明確に線引きができ、バックエンドの進捗がブロッカーにならずに進めることができるます。

  • セキュアな認証
     認証に必要なトークンをブラウザに安全に保持する方法は確立されていません。[1]
     しかし、BFFがあればバックエンドへのゲートウェイとして使用し、トークンを格納できます。
     BFFで認証を請け負うようにすればトークンをセッションに保存して安全に認証処理を行うことができます。また認証処理をクライアントごとに実装する手間が省けます。

他にもバックエンドの観点からBFFを採用するメリットはありますが割愛します。

BFFのデメリット

  • 単一障害点になる
     BFFが何らかの理由で正常に機能しない場合、サービス全体が影響を受けます。
  • 時間コストが発生する
    スケールしないサービスにおいては得られる恩恵よりもメンテナンス工数の方が大きくなる可能性があります。

副次効果: 流動的なメンバー構成での安定した開発を支援

  • バックエンドがマイクロサービスになっていて、問い合わせ先が複数あり、どこに問い合わせたら良いのかサービス全体の仕様を把握するのに時間がかかる。
  • APIのドキュメントがないため、バックエンドの仕様を知るために直接コードを読まないといけない。

上記の問題がある時、新規にプロジェクトしたメンバーの開発効率、またその質問を受けるメンバーの開発効率は大きく低下します。

BFFを仕様に詳しいものが作ってくれていれば、新しいメンバーや業務委託のメンバーを受け入れやすい開発体制にすることができます。

UXの向上: リクエストの最適化

BFFを採用することで得られるメリットの中でも、特にリクエストの最適化と表示速度の向上はUX向上に大きく貢献できるポイントです。

リクエストの最適化をするおすすめの技術スタック事例を1つ紹介します。

GraphQL + graphql-codegen

  • GraphQL: リクエストの一本化
  • graphql-codegen: スキーマからデータを取得・更新するHooksを自動生成(TypeScript)

開発のフロー

  1. 画面単位で必要になるデータを書き出し、意味を持つくくりでまとめる。
  2. まとめたデータをもとに、バックエンドチームとスキーマを決める。
  3. バックエンドチームにスキーマにのっとり、APIだけ生やしてもらう。
    ドメインロジックは未実装のまま、適当な値を返却してもらう。
  4. スキーマ定義にのっとり、GraphQLオペレーションを生成する。
    クライアントの画面単位で欲しいオペレーションを作成します。
    自クライアントのことだけを考えてオペレーション名やリクエストする項目を自由にカスタマイズできるので簡単に最適化できます。

ざっとですが上記の技術スタックとフローで開発することで最適化の実現はもちろん、バックエンドのAPI開発の進捗がブロックにならないことによる開発体験の向上、またスキーマの時点で型が定義されているために、型に関するミスが減り、値チェック処理も一通り不要になることで開発効率もあがります。

バックエンドをGraphQLに対応してもらえれば、あとはクライアントが増えても各クライアントごとにオペレーションを作成すればよいのでバックエンドには作業が発生しません。

UXの向上: 表示速度

画面の表示を細かく分解すると、ユーザーが画面をリクエストしてから実際にサービスを利用可能になるまでにいくつかの段階があります。

レンダリングの種類によってこの表示にかかる各段階にかかる時間が変動します。

レンダリングの種類

レンダリングをするタイミングによって3つに種類わけがあります。

1つめはクライアントでレンダリングするCSR(Client Side Rendering)。
BFFの観点ではサーバーでレンダリングするSSR(Server Side Rendering)とアプリケーションのビルド時にレンダリングしておくSSG(Server Side Generate)の理解・利用が重要になってきます。

SSR(サーバーサイドレンダリング)

SSRではユーザーからリクエストを受けたあと、サーバーでレンダリングを画面をレンダリングするための処理に該当するJavaScriptファイルをクライアントに送信する必要がなくなるため読み込みするデータ容量を抑えることができます。

これによりTTLの状態になるまでの時間が短縮されます。
一方、サーバーでのレンダリングを待機する分、TTFBまでの時間が遅くなるという欠点もあります。

それでは結局プラスマイナス0なのか、意味がないのかというと、そういうわけでもありません。
FCPからTTLの間の「見えているけど操作は受け付けない」状態が長いほどユーザーにはストレスがかかると言われています。

SSG(静的レンダリング)

SSGでは画面はビルドのタイミングでレンダリングされます。
ユーザーからリクエストがきたらサーバーはURLに応じた画面をそのまま返却します。
レンダリング処理はすでに終わっているためFP, FCP, TTLはどれも最速になります。

Netflixでは極力静的レンダリングを使っています。
対話の多い画面でのみ、JSファイルを事前読み込みするSSRを使うという切り分けをしています。

SSGはCDNによって提供されるためSSRよりはるかに表示速度が早くなります。

しかし、SNSなどのリアルタイムに表示が変わる画面には向きません。
極力SSGを採用し、動的な画面にはSSRを使いましょう。

表示速度向上で大切なこと

どのレンダリング手法が1番良い。というものはありません。

サービス、そして各画面を鑑みて画面単位で最適なレンダリング手法を検討、選択することで大きくUXの向上に繋げることができます。

最適なレンダリングを選ぶ際に、この図が参考になります。

最後に

今回はあくまでフロントエンドエンジニアのコントローラブルな範囲でのBFFを紹介しましたが、BFFを実践するには上記の例以外にも様々な方法があります。

最近注目されているSSR, SSGを採用する前に、もう少し深い理解をと考え、それらが誕生する土台となったBFFについてまとめました。

脚注
  1. httpOnly cookieであればセキュアにトークンを保持できるのかもしれません。未調査です。 ↩︎

Discussion