A living-room and mobile streaming product in Twitch's mould has four backend-for-frontend services - web, iOS, Android and a TV app. All four are owned by one platform team. Web and iOS have 80% identical code. The TV BFF is different and awkward. Review this. What would you remove, what would you change, and what would you leave alone?
Show the full answer Hide the answer
What is actually required
A BFF exists for one reason: a client's needs change at the client's cadence, and the client team should be able to change its own aggregation without waiting for anyone. Everything else people claim for the pattern — fewer round trips, smaller payloads — is available from a well-designed shared API.
So the test is not "how many clients are there" but "who owns this, and does its release cadence match the client's?" Four BFFs owned by one platform team fail that test by construction: the platform team is still the bottleneck, and the four services have multiplied its work rather than removing a dependency.
What I would remove
The web and iOS BFFs, merged into one. 80% identical code across two services owned by one team is duplication with no compensating independence. Merging halves the surface and loses nothing, because neither team was releasing independently anyway. Keep the 20% as client-specific endpoints or response variants inside the merged service.
I would also remove any endpoint in a BFF that only forwards. A pass-through adds a hop, a timeout, a retry policy and a deployment, and contributes no aggregation or shaping. Those calls should go to the underlying service directly.
The one change that matters
Move ownership to the client teams, or stop calling them BFFs. Either the web team owns the web BFF and deploys it when it ships a feature — in which case the pattern is doing its job — or the platform team keeps ownership and should consolidate to one gateway with client-aware response shaping, which is cheaper to run and honest about where the bottleneck is.
This is the decision, and it is organisational rather than technical. A BFF the client team does not own is a distributed monolith with extra deployments.
What I would leave alone, even though it looks odd
The awkward TV BFF. Living-room devices are the strongest case the pattern has. Their constraints are genuinely different: devices in the field for 5 to 8 years, app updates gated by the device vendor's store and sometimes by firmware, limited memory and a slow JavaScript engine, and a remote-control navigation model that needs a completely different payload shape. The release cadence is set by someone outside the company, which means the TV client cannot adapt to a change in a shared API on the company's schedule.
That BFF's job is to keep serving the response shape that the 2021 firmware expects while the underlying services evolve. It looks awkward because it is absorbing awkwardness that would otherwise be spread across every backend service. Leave it, and give it an explicit long-term compatibility contract with a stated support window per device generation.
When this is the wrong pattern, and what breaks if you keep it
The failure mode of four unowned BFFs is availability arithmetic. A BFF that fans out to 9 services and cannot answer without all of them has the product of their availabilities: nine dependencies at 99.9% each give about 99.1%, roughly 6 hours a month, worse than any single dependency. The fix is per-dependency fallbacks and partial responses, and whoever owns the BFF must decide, per field, what a degraded answer looks like. An unowned BFF has nobody to make that decision, so it fails whole instead of degrading.
How I would argue this in the review
With the duplication number and the ownership question, in that order. 80% identical code is uncontroversial. Then one question: when the web team wants a new field, who deploys? If the answer is the platform team, the pattern is not delivering what it costs, and the choice is to move ownership or to consolidate.