Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

Why does each front-end have its own BFF?

Why isn't there just one API gateway with minimal front-end-specific endpoints?



Originally this was a Netflix pattern I believe, and the key trade-off there is that there are lots of client implementations/versions and they are hard or impossible to upgrade (eg set top boxes).

And typically you want to call a few different backend services in a given API call, with perhaps different trade-offs; one device might need cover photos up front, another might just do text summaries, to take a made-up example.

If you have one API gateway then your clients tend to be thicker as they need to figure out how to weave the different API calls together. And/or your API gateway gets clogged up with lots of usecase-specific variants.

So if you extract a per-frontend(-family) backend you can keep more of the logic in your backend system where it’s amenable to change as the upstream services evolve, and keep the device logic better modularized.

If you just have iPhone vs Android apps it may well be cheaper to just eat the complexity cost of having different APIs on your single gateway, to avoid having to pay the cost to deploy multiple bff services.


> cost to deploy multiple bff services

Pennies on the dollar.

And now you have a concrete view into exactly what Roku App v3 needs.

And with this pattern you can migrate with marginal blast radius, unlocking developer centuries of productivity. Cross my heart and hope to die.


I’ll answer your questions with another question: who is responsible for maintaining the single API gateway in your alternative scenario?

If you have a single module that needs to support customised APIs for each front-end client, and each of those APIs potentially needs to talk to the now-internal APIs for each back-end service, you’re back to the monolith problem where everyone has to co-ordinate changes and deployments with everyone else. Chances are that you adopted microservices to avoid exactly that kind of problem.

If the modules in your new layer instead correspond 1:1 with your front-end clients but each might need to depend on multiple back-end services, you create new problems if the back-end teams have any responsibility for maintaining the new modules. Now each back-end team has to understand all of the different front-end clients using its service and cater to each of them separately, and you also need all of the relevant back-end teams to co-ordinate on any changes and deployments of each front-end client’s back-end API. Again, this is adding new responsibilities and overheads that you didn’t have before.

So that brings us to the idea in the article, where each front-end team is responsible for maintaining its own back-end API module as well. This avoids the original performance problem of having each front-end client making an inefficient set of relatively slow requests to multiple general-purpose APIs for different back-end services, but without needing any extra knowledge or co-ordination between teams that you didn’t already need anyway.


I assume it's so that if your client wants, it can reach out to a different BFF to get some data not implemented in its own BFF, leading to a class of problems where the data might change, necessitating the need to build Backend for Backend for Frontends (BFBFFs) on top of the BFFs. That way you and your competing teams can wage an arms race to see whose jenga tech silo can grow faster.


Because the API is a REST API and you don't want your frontend to have to make 100 calls to render a screen. Each frontend may be a completely different app so they all need the data in their own format. And each team may control their app so you don't want all of the teams roadblocked by the API team.


If the API were a REST API then the client would only need to make 1 call to request the screen (representation of a resource) in a format (media type) the client expects.


This is not the reality when you go into most organizations. It may have started like that but a few cases of "just one more call" result in the client making a load of calls at startup followed by many others when user navigates to a detail screen. It probably caches a few items, but many others are not cached appropriately.

This is what the vast majority of developers are facing. Be thankful, if you don't have to clean these messes up only to move to another team to repeat it. It happens naturally because of the tension between shipping things and finding enough time to properly optimize.


Also, the data may be coming from multiple systems. So somewhere you have to stich that data together.


Some mix of politics, management, and prioritization, in practice, when I've seen it. (It's often hard to fully separate those three things.)

Consider an app that has a TV interface, a desktop interface, and a phone interface. The UI might be very different on each. You might want different art at different sizes/aspect ratios for different interfaces (consider different ways of browsing content on a streaming media service, including potentially "live TV guide" views and/or series-vs-show-level navigation). You might iterate on those interfaces at different rates - it's easier to release to the web than to mobile, and it's a LOT easier to release there than to, say, Samsung TVs.

So either distinct sets of APIs for each, or some sort of graphql-style "get just what you ask for" open-ended API contract becomes necessary.

The former is often easier to optimize for performance if you don't truly need unlimited permutations, but just a handful of them.

Nothing here is impossible to do out of a single API gateway, but you're likely run into some problems over time:

* at a certain number of people, a single team working in a single codebase often steps on each other's feet more than is productive

* at a certain feature complexity, the API gateway becomes much more "custom logic for each device" than "shared aggregation of stuff from individual backends"

* at a certain company/product organization/roadmap size, trying to sequence and deliver priorities for three competing client teams at the same time becomes tricky

Splitting up the teams to each focus on different clients lets you accomplish organizational resource splitting at a higher level (how much do we staff these teams) than stakeholders having to jockey for prioritization on every single feature.

Once the teams are split up, splitting up the codebases and deployables makes sense too - if you're responsible for the mobile API, you don't want to be paged because the TV team pushed something that screwed up your crap, etc. You can do finer-grained optimizations at that point, too.


You have the following constraints:

1. You do not control the update cycle of the client layer

2. You want to decouple platform support. You can do this for technical reasons and for org reasons (you can scale up teams independently)

This way, you can have the client be simple with a slow update cycle. You restrict its slowness to it alone and not to the whole product. You can then scale your backend services teams independently. You can throw away entire backend services while your front-end team modifies their API layer to ensure that legacy clients can handle things. The front-end team working on a client with a slow upgrade cycle can mock API responses or something. Meanwhile, the front-end team that's working on a client with a fast upgrade cycle can just move on.

You can thin your platform-specific client and move more logic into the platform-specific backend while keeping your platform-agnostic backend moving fast.


I recently ran across BFF and asked the same exact question. The answers to your question so far do not seem to address it in my opinion.

Correct me if you are wrong but you are saying why does IOS, Andriod, ect each have there own API gateway vs sharing one correct?

Besides different front ends needing different api calls/contracts I have not seen a good explanation yet.

BFF does solve an issue with securing front end JS sites. See here for an explanation: https://docs.duendesoftware.com/identityserver/v5/bff/overvi...


>>> why does IOS, Andriod, ect each have there own API gateway vs sharing one

You need to be aware of some lifecycle aspects when dealing with first versus third-party clients. If you don't have experience with third-party being a key component of your business model then this is hard to grasp.

When you list these mobile clients, I immediately assume that these are your first-party clients. These are clients which you deploy to various stores and manage completely. There is some chance that you are supporting old versions, but you are mostly in control and can drive the support lifecycle by deprecating old clients when analytics suggest it is OK.

When you have clients that are critical to your business (some weird set-top box) that you can't just deprecate, then it starts to become viable to do something like this. Your main system can evolve and grow leaving only a single system to maintain for these special clients. Whether it's worthwhile is going to be completely dependent on the value of the client. It's massive improvement in the quality of life for your backend team and those responsible for supporting the client.


> Correct me if you are wrong but you are saying why does IOS, Andriod, ect each have there own API gateway vs sharing one correct?

No, he's saying that a single api gateway can serve all clients.


Typically each channel takes its own course and evolves at different speeds with different needs. Trying to engineer a common set of APIs that serve all channels eventually leads to ever increasing FE logic with a backend API with leaky abstraction (by virtue of trying to accommodate different UI concerns).

By decoupling the BFF APIs which are geared towards a UI specifically, in a way you are moving a big part of the logic and orchestration to the backend and keeping the UI layer super lite. From practical experience, this has been a very helpful pattern both in my startups and enterprise career.


> Why isn't there just one API gateway with minimal front-end-specific endpoints?

After Googling, I found that we can use both API Gateway (e.g., Apache APISIX, https://apisix.apache.org/blog/) and GraphQL to achieve this:

1. GraphQL: Let developers choose which resources to receive. 2. API Gateway: Except for implementing BFF, also we could filter requests to make sure upstream service is protected. (It's more flexible IMO)


My main answer here is latency. Let me explain.

For our app the back of the frontend provides the working data model.

So for our web app we have a next style server side renderer + serverless functions

For the mobile app we stick we a queue based architecture (the web back of the frontend resolves to the same underlying data structure.)

So imo different front ends have different use cases. But in general the back of the frontend isn’t a backend it’s the frontend server. So the round trip is the same for first paint, api requests etc. For the web app at least


It's always good to give your developers autonomy as the company/team grows in size.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: