- Sam Newman - Backends For Frontends
- マイクロサービスの思想から捉える Backends for Frontendsとその類似パターン
- BFF's cosmos in FOLIO sec at uit
- BFF(Backends For Frontends)超入門――Netflix、Twitter、リクルートテクノロジーズが採用する理由 (1/2):マイクロサービス/API時代のフロントエンド開発(1) - @IT
- BFF(Backends For Frontends)の5つの便利なユースケース:マイクロサービス/API時代のフロントエンド開発(2) - @IT
- BFF @ SoundCloud | ThoughtWorks
- wrote in 2015/11/18
- Intro
- UI提供の変遷(デスクトップアプリ->Web)
- 近年では更に提供先が増えた(新たなモバイル端末とか)
- もともとデスクトップPCのWebUI用であることを前提としたAPIも対応に迫れることとなった
- UI提供の変遷(デスクトップアプリ->Web)
- General-Purpose API Backend
- 最初の解法は汎用のAPIを作って新たなUI対応に必要となった機能を随時足していくこと
- どのUIでも同じような呼び出ししかしないならコレでうまくいく
- けどまあPCとモバイルとでは体験は大きく変わるもので、そうなると呼び出すものも変わる
- モバイルはあまりたくさんのデータを表示したり沢山のコネクションをはったりし辛い
- 解像度、バッテリー、通信プラン…
- そもそもインタラクションもPCと大きく違うものを提供したいことがある
- 色んなUIに対応するための機能をAPIが持つと機能変更が集中してボトルネックになる
- 多くの仕事が必要になり各UI・APIとで専任チームができるようになる
- これが更に自体を悪化させうる
- フロントエンドチームはAPIに加えられた変更を得るために隔離されたチームとコミュニケーションを取る必要があり、
- APIチームは複数のクライアントチームやAPIを使う下流のチームへの仕事の優先順位でバランスを取らなければならない
- ここでビジネスドメインに全くフォーカスしないミドルウェアを設置することについて議論が出てくる
- 最初の解法は汎用のAPIを作って新たなUI対応に必要となった機能を随時足していくこと
- introducing the backend for frontend
- 元 SoundCloud の人が初めて提唱した(Phil Calçado)
- 汎用的なAPIを設置するだけでなく、1UIごとに1つのバックエンドを設置する
- BFF は特定のUIと強く結びつき、UIを作るチームがメンテする
- それによりUIが求めるAPIを作りやすい・統合しやすい
- リリースもAPIとは完全に独立して特定のUXのチームだけで行える
- BFFを単一かつ特定のUIに強く焦点を当てた設計にすることで小さくできる
- how many bffs?
- 同じUIだけどプラットフォームが違うときにBFFはどうする?
- REA はそれぞれ、SoundCloud は1つでやってた
- プラットフォームごとに分けちゃうのが筆者は好き
- 複数UI/単一BFFにするとUIが増えるほど複数の関心事をハンドリングするようBFFを膨らませたくなる
- 複数UI/単一BFFにするなら、いくらBFFを共有するとはいえ、全てのクライアントで同じUIクラスを使うことを理解するのがポイント
- 例えば SoundCloud では iOS/Android のアプリは単一のBFFだったけど、Pulse では別の BFF を使っている
- iOS/Android/BFFを同じチームがみるならまあいいけどそれぞれを別のチームがみるならもっと厳格な構成でやったほうが良さそう
- そのへんは会社の組織に合わせて選ぶ
- 'one experience, one BFF' from Stewart Gleadow
- チームの境界に合わせてBFFを作ると良い from Pete Hodgeson (著者の同僚)
- システムデザインよりチームの方が流動しやすい
- モバイルチームを iOS/Android チームに分けることになったときに BFF を分けるより、
- BFF を分けておいて後からチームを分ける方が楽
- システムデザインよりチームの方が流動しやすい
- 同じUIだけどプラットフォームが違うときにBFFはどうする?
- And Multiple Downstream Services (Microservices)
- バックエンドが少ないときにもBFFは有用なパターンだった
- バックエンドが沢山ある組織だと特にBFFは重要
- 複数のAPI呼び出しの結果を集約する必要性が大きく高まるから
- 3つのAPIを叩くサービスがあったとして
- 1つ目の API の結果を元に残りの2つの API を叩くようなやつ
- 順序を保証するように書いていくと、順序が複雑になると一瞬で管理がきつくなる
- Rx が得意な分野の1つっすね
- Reuse and BFFs
- 単一UI/単一BFFにする懸念の1つはBFF間の実装に大量の重複が出ること
- そこで重複した箇所を1つのAPIに切り出そうとすると複数UI/単一BFFにしたときと同じ問題がおきる
- サービス間でコードが重複することは気にならない by 著者
- 単一のサービス無いでの重複はもちろんやれる限り適切な抽象化で解消するだろうけど、サービス間で同じようなことはしない
- サービス間でコードが重複することよりも、重複を抽出して共有されたコードによってサービス間が強く結びついてしまうかもしれないことのほうが怖い
- Pete 氏が言うには
- BFF が無いときはクライアント間でコードが重複していることは誰も気づかない
- クライアント間で技術スタックが全然違うから
- けれども組織内で共通の技術スタックで複数の BFF を使い始めると、重複に気づき始める
- BFF が無いときはクライアント間でコードが重複していることは誰も気づかない
- もし共通コードを切り出すなら↓の選択肢がある
- ライブラリに切り出す
- 各サービス内の関心事だけを抽出したものならまあいける
- 下流サービスの呼び出しとかを抽出すると BFF 間が結びつくことになるのでダメ
- 新しいサービスとして切り出す
- 問題になっている領域に関しての何かであることを上手く概念化できるならワークしそう
- このパターンの変形として、重複している箇所を API 側に任せるパターンもある
- 新たなサービスを作るトランザクションコストが十分に低かったり、更にUIが増えて3箇所とかになったら考えるかも
- ライブラリに切り出す
- 単一UI/単一BFFにする懸念の1つはBFF間の実装に大量の重複が出ること
- BFFs for Desktop Web and Beyond
- デスクトップは接続環境が良くて強いマシンで複数回のAPI呼び出しにかかるコストも扱いやすいから BFF ナシに複数の API 呼び出しを直接実行できる
- BFFを使って便利化した例だと、サーバーサイドでデカいUIを生成するときに BFF にそれをやらせるパターン
- BFF の前にあるリバプロに複数のAPI呼び出しを集約した結果をキャッシュさせることができる
- 常に最新の情報が集約されるようにキャッシュコントロールを設定する必要がある
- けど実際はこれやってた現場だとBFFとは呼んでなくて、汎用APIなんだよね
- BFF の前にあるリバプロに複数のAPI呼び出しを集約した結果をキャッシュさせることができる
- 別の例として、他社がAPIを叩く窓口として会社ごとにBFFを立てるパターンがあった
- つまり、使われるAPI呼び出しを変更できない場合
- 汎用APIの場合だと呼び出しを変更できない人たちのために古いバーションを保守し続けたりする
- BFFを使うことでこの問題を減らせる
- And Autonomy
- 各フロントエンドと各バックエンドをそれぞれ別々のチームで作ってる組織がよくある
- 普段はビジネスの縦割りに沿うようにマイクロサービス化するけど、難しい場合もある
- フロントエンドの開発とAPIの開発の足並みが揃わないときはフロントエンドチームが UI と BFF を同時に開発していくことで解消できる
- 各フロントエンドと各バックエンドをそれぞれ別々のチームで作ってる組織がよくある
- General Perimeter Concerns
- UI と BFF の間に認証・認可とかUI/BFFの境界線でよくやる処理を切り出したBFFを作る人達がいる
- けどそれは nginx を多重に重ねてるようなもんでは…
- レイテンシも増えるし
- BFFは大抵Microservices環境で利用されるから通信の数がそもそも多くレイテンシにはシビア
- レイヤ増やすとデプロイが大変になり開発・テストも複雑になる
- BFFs が同じ技術で作られてるなら、共通処理はライブラリに切り出すのも手、そんなに大変じゃないはず
- UI と BFF の間に認証・認可とかUI/BFFの境界線でよくやる処理を切り出したBFFを作る人達がいる
- When To Use
- Web UI しか提供しないなら、大量にあるバックエンドからのデータを集約するときくらいしか効果を発揮しない
- モバイル UI とか 3rd パーティとかに特定の機能を提供するならそれぞれの手前に BFF 置くの超オススメ
- 追加サービスによってデプロイコストが大きく高まるなら再考するけど、関心が分離されることの説得力は大抵のケースでデカい
- 人間たちが別れて UI / API を作ってる場合は BFF 使う
- Conclusion
- BFF はマイクロサービス環境におけるモバイルアプリ開発の問題を解消する
- とは言えモバイルアプリ開発だけに限らない
- BFF は汎用APIを代替するもの
- サポートする購読者数を制限する単純な働きが、
- 連携や変更を楽にする
- ユーザーに特化したアプリ作るチームをより自立した状態に保つ
- BFF はマイクロサービス環境におけるモバイルアプリ開発の問題を解消する
- バックエンドでやるべきことを BFF が担わないようにする。極力バックエンドに寄せる
- BFF はクライアントを強く意識した設計にすべき
- 目的が単一
- RESTful でなくてよい
- React のフロントを Node.js の BFF で受けてる
- App - BFF は REST API, BFF - バックエンド は Thrift
- BFF が担うのはサービスの集約、SSR、認証・セッション管理
- どこで・どこまで BFF でやるかは最初に方針決めといたほうが良い
- 日付の変換とか
- ゲートウェイアダプタでやるのかユースケース内でやるのか
- バックエンド: データの取得や更新に責任を持つ
- フロントエンド: ページを構築したりユーザーの入力を得る
- ↑のように役割を分担させたときに、それぞれの領域をより専門分野に集中できるようにするものが BFF
- BFF が必要になった背景:アプリケーションの内部構造が時代とともに変化し続けていること
- 従来
- 1枚のモノリスが DB や全文検索エンジンにつながってるだけ
- 2000~
- サーバー側は API だけの存在に
- 昨今
- クライアントの種類が増えたことで API は特定のリソースに特化したものを個別に作る形に(Microservices)
- BFF登場
- クライアント間の要求差異を吸収する API を作るのが困難に
- HTTP1.1の同時コネクション数6の限界
- => HTML作成やコネクション数の削減
- 従来
- BFF がもたらす効果
- フロントエンド専用のバックエンドを立てることで UI 構築を楽にする
- フロントエンドとバックエンドの境界を分けレイヤーを分離することで独立して開発を勧めやすくする
- BFF が活きるとき
- バックエンドとフロントエンドとが組織的に別れて開発を進めるとき
- 同じ API を複数のクライアントから使う構成でクライアントごとに API をまとめたいとき
- Web アプリにおける HTML 構築を任せたいとき
- BFF を使わないほうが良いとき
- クライアントの種類が1つしか無いとき
- APIサーバがビジネスのドメインロジック部分を担当するのに対して、BFFはあくまでユーザーインタフェースをサポートするサーバ
- BFF の代表的なユースケース5つ
-
- API Gateway
-
- SSR
-
- セッション管理
-
- ファイルアップロード
-
- WebSocket、Server Sent Events、Long Polling
- 大別すると2種類
-
- クライアント機能を肩代わりするもの(SSRとか)
-
- セッション管理のような API の実装をシンプルにするもの
-
-
- API Gateway
- 複数の API をまとめてクライアント用に翻訳するなど
- Aggregation, Translation, Cache, Filter(クライアントに不要なレスポンスを省く)
- API Aggregation
- コネクション数の削減
- リクエストごとに API 側でセッション確認しなくてよくする
- SSR
- SEO の改善
- クローラが JS を完璧に動かせるとは限らない
- 検索エンジンに対してはできればインデクシングさせたい情報は初期 HTML に載せておくことが推奨されている
- 初期ページの表示を高速化する
- HTML の構築の JS を取得するコストがかかる
- SEO の改善
- ...
- Motivation
- 色んなクライアントがいる中で、モノリシックな API を使っていた
- 機能の追加に時間がかる問題とプラットフォーム間で要求が異なる問題