79 ms·
Backend for Front-end
- sshine 4y agoWhy does each front-end have its own BFF? Why isn't there just one API gateway with minimal front-end-specific endpoints?
- deleted 4y ago[deleted]
- codenesium 4y agoBecause 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.
- codenesium 4y agoAlso, the data may be coming from multiple systems. So somewhere you have to stich that data together.
- smadge 4y agoIf 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.
- zerkten 4y agoThis 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.
- pcthrowaway 4y agoI 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.
- theptip 4y agoOriginally 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.
- echelon 4y ago> 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.
- keneda7 4y agoI 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/overview/ https://docs.duendesoftware.com/identityserver/v5/bff/overvi...
- jsnk 4y ago> 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.
- zerkten 4y ago>>> 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.
- guoqi 4y ago> 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/ 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)
- slrainka 4y agoTypically 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.
- renewiltord 4y agoYou 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.
- didip 4y agoIt's always good to give your developers autonomy as the company/team grows in size.
- edgyquant 4y agoMy 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
- majormajor 4y agoSome 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.
- Chris_Newton 4y agoI’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.
- vore 4y agoI feel like another alternative in this space is to use GraphQL: while it does introduce complexity in terms of query handling, it does allow each frontend to more precisely query the data model and avoids having to tightly couple the frontend data model to the backend data model.
- jjzhiyuan 4y agoYes, by using GraphQL's Query DSL, the client can control what to fetch :) From my opinion, the mainly difference is API Gateway can filter requests and protect the upstream services (GraphQL can't).
- doctor_eval 4y agoGraphQL can totally do these things, with an appropriate resolver. I mean, in the end, anything you can do using REST can be achieved with GraphQL. But shouldn’t the individual services be protecting themselves? That said, I think there’s a case for BFFs - even ones implemented in GQL - when there is a need to support devices or customers which you can change, and which may live longer than your API.
- eurasiantiger 4y agoIf you’re writing resolvers manually for something like this, your stack sucks. Use federation.
- doctor_eval 4y agoEdit: I meant to say "can't" change.
- bbatha 4y agoGraphQL is practically designed to support this pattern. Facebook was one of the early proponents of this architecture and GraphQL was a product of that. The federation features allow individual teams to maintain their slice of the pie and communicate with the real backends over RPC.
- 4y ago
- chrisweekly 4y agoI like Remix's take on it: https://remix.run/docs/en/v1/guides/bff https://remix.run/docs/en/v1/guides/bff
- jjzhiyuan 4y agoAnother good post!
- ransom1538 4y agoCall me an old gray beard here. But, IMHO the client is x10 more complex in all platforms. Pumping out crud api calls is fast. Dealing with React/swift/state management/product managers is not. So with this project BFF I feel it's going the wrong way. We need ways to help the clients do less work faster. Not the backends. Client team members don't need more work - working on a BFF. They need less work, maybe Backend team members do more client work near the api layer.
- yen223 4y agoIf it is true that the client is 10x more complex than the server, then shifting some of the client-side complexity to a 10x simpler BFF server is going to be a net positive.
- vore 4y agoLogically if you want to rip out work from the client you would put more work into the backend? I don't understand what you're getting at. CRUD may be fast on the server side, but if the client is performing a complex workflow of CRUD calls, you're incurring the round-trip network cost each time. The more you can coalesce the workflow on the server side, the lower round-trip network costs you'll incur, which is the real bottleneck here (10ms server processing time vs a wild range of 10ms-1000+ms network latency, depending on where you are/what you're on).
- foobiekr 4y agoagreed. also it creates an incredibly obnoxious security surface.
- imron 4y agoFeels like it would fit right in to this architecture: https://www.youtube.com/watch?v=y8OnoxKotPQ https://www.youtube.com/watch?v=y8OnoxKotPQ
- yawnxyz 4y agoI really like SvelteKit's way of helping you create a similar BFF with their endpoints system. I still have my "real" backends, but w/ SvelteKit endpoints I can even turn my BFFs into real APIs. And it's trivial to create an interface for getting/posting data from those BFF APIs, which I use for admin.
- vyrotek 4y agoHuge fan. Our company has been working on a new large platform built around BFF and it's been really nice to work with. We have several SPA and mobile apps which interact with our data very differently. It took a bit to break the mindset of using the HTTP layer as the "point of reuse" but now it's far easier to add and maintain functionality. We feel much more productive compared to past projects where we spent a lot of time trying to make "one API to rule them all" with a single ever-changing model.
- grose 4y agoBFF is perhaps the purest example of Conway's law. When the backend team cannot or will not make the necessary changes for the frontend team, another layer is introduced: the BFF. There is no particular reason why the real backend can't solve this problem; it is purely political.
- mixedCase 4y agoIt's not political that microservices owning well-defined slices of a pie can't cater to the frontend's every whim without creating a dependency spaghetti everywhere that you have cross-cutting concerns. It's just common sense. If you're arguing that most microservice vs monolith decisions represent a political and not a technical decision, I'll grant you that.
- montanalow 4y agoThose well defined slices of pie you’re referring to are often exactly the political boundaries OP is referring to. This is the degenerate form of Conways Law.
- softveda 4y ago100%. A backend API can be used from multiple frontends. Just one from my experience working for an electricity provider, API from Desktop webapp, android mobile app, IOS mobile app all retail customer facing. Then from a Sales pipeline for new customers in a CRM app. From B2B customers (Electricians building new homes requesting connections) in a different web app.
- grose 4y agoI don't think it's necessarily bad. In fact it is quite an elegant solution to issues between frontend and backend teams. I just think it's a great example of Conway's law. Conway's law (IMO) was never a negative thing, merely an observation of the realities of software development. Your post brings up an interesting angle which is that the frontend and backend people can have different expectations of what the backend should actually do (perhaps leading to dependency spaghetti). In this case, introducing a BFF can be a way to isolate that from the rest of the architecture.
- xyst 4y agoIsn't "BFF" layer really graphql? craft a GQL query to return exactly what the client needs. No less, no more.
- rugdobe 4y agosometimes these are called Middle Tier -- an aggregation layer between frontend and backend services
- jillesvangurp 4y agoIn the nineties, people were talking about n-tier architectures. This was of course before browsers were a common thing. But we did have networks already since the nineteen seventies. And actually, a lot of the architectural solutions people use today aren't that different from what people were doing a few decades ago. Things like resolving names, passing messages, figuring out security, etc. have been things that people have been figuring out for different systems. If you compare Kubernetes to CORBA for example, you'll see some common features between the two. Not surprising because they both provide a solution for allowing networked components to talk to each other. Basically, the whole frontend/backend distinction is a simplification. There are more than two layers. And you can probably even identify layers in the frontend as well these days given that a typical SPA actually does a lot of stuff before it even talks to a server. Local browser storage for example is a storage layer. And you probably have some layer in between that and e.g. event handlers. The reason the frontend/backend boundary is important is because they are physically separated by a network but also have relatively independent life cycles. You don't update them at the same time for example. You might have different versions of the frontend talking to the same backend. Or even multiple different frontend applications. And many companies have multiple backends as well. So, it's an ecosystem of frontends and backends talking to each other. Providing some kind of facade layer for that complexity is of course an obvious solution when you have a complicated backend with its complexity spilling over to frontend layers.
- akrymski 4y agoIndeed, there was tonnes of n-tier architecture stuff in Java EE land in the 90s. SOAP - Service Orchestration and Automation was/is another concept from the 90s that is conceptually similar to GraphQL. I don't like the terms front-end and back-end. In reality applications are using a variety of internal & external services these days, and not all of them are behind a backend necessarily. Your own micro-services are meant to be used in much the same way as any third party's endpoint.
- thebricksta 4y agoMy company uses this pattern extensively, just as indicated in the post. Frontend teams deliver their own backend-for-frontend and the backend teams just worry about their own microservices. Generally, it works out pretty well most of the time. The big issue I've been seeing is that occasionally frontend teams will decide to develop "features" by stringing together massive series of calls to the backend to implement logic that a singular backend could do much more efficiently. For example, they commonly will have their backend-for-frontend attempt to query large lists of data, even walking through multiple pages, in order to deliver a summary that a backend service could implement in a SQL query. Unnecessary load on the backend service and on the DB to transmit all that data needlessly to the BFF. I know the easy answer is to blame the frontend devs, but this pattern seems to almost encourage this sort of thing. Frontends try to skip involving the backend teams due to time constraints or just plain naivety, and suddenly the backend team wakes up one morning to find a massive increase in load on their systems triggering alerts, and the frontend team believes its not their fault. This just feels like an innate risk to promoting a frontend team to owning an individual service living in the data center.
- em-bee 4y agothis is what happens when you give frontend teams tools with to much power in an environment where frontend and backend team don't communicate well with each other. i have seen this first hand with a customer. to their credit, they didn't even have a backend team, until i was brought on board to help them rewrite some of their slower frontend functionality into some more efficient backend functions
- ako 4y agoMany of these backend systems will be Off-the-shelf products, e.g., SAP, Salesforce, Marketto, and lots of other systems people use. Many of these systems don't have APIs that work well for interactive frontends. And you have many different frontends, for your sales people, your project engineers, your marketing department, your different suppliers and partners. These different apps have different data & api needs, and will need to aggregate data from different systems. Systems that cannot be modified to execute the most optimal SQL query for your frontend. And it's too much business logic to put in an API gateway. And all these systems have their own lifecycles, so different project timing, different releases, etc. A BFF makes a lot of sense to make all of this manageable.
- kuang_eleven 4y agoI can't say I see the point of this, unless you have a criminally unresponsive backend dev team. Any half-decent backend API will offer parameters to limit the response of an endpoint, from basic pagination to filtering what info is returned per unit. What's the use of extra complexity of a "BFF" if those calls can be crafted on the fly. And to be clear, I am not suggesting that custom endpoint be crafted for every call that gets made, that just seem like a strawman the article is positing; but rather that calls specify when info they need.
- thebricksta 4y agoThe article doesn't do a great job at explaining that this isn't always just filtering, sometimes it's aggregation too. A mobile client may need data points to display a single page that require calling 20 different APIs. Even if every single backend offered options for filtering as efficiently as possible, you may still need an aggregation service to bundle those 20 calls up into a single (or small set) of service calls to save on round-trip time.
- rajin444 4y agoYou still have to aggregate somewhere. You can do it on the client or the frontend backend, it still has to get done. In the case of the latter we’re adding one extra hop before the client gets their data. This pattern is advocating for reduced technical performance to accommodate organizational complexity, which I think the parent finds odd. You either have the client call 20 service/data?client_type=ios or you have the frontend backend call 20 different service/data?client_type=ios (after the client called)
- awofford 4y agoI agree with your assessment here, but one additional benefit is the capability to iterate faster on the backend. You have control over _where_ the aggregated data is coming from without waiting months for users to update their mobile app so that it sends requests to a new service, for example.
- 4y ago
- jcolella 4y agoAt my last company, when we were building a greenfield application, we leveraged this pattern, at a time when GraphQL was not yet available. In my new company, I look at GraphQL and realize that this solves the BFF pattern in a standardized way
- henning 4y agoBased on my experience seeing this in action, adopt this at work if you want to have every team create their own shitty ad-hoc service mesh that sucks. Now adding a column to a table takes three PRs and three deploys! And you have to write redundant tests for each stupid layer.
- gregmac 4y agoThere's a massive benefit missed here: backwards compatibility! Or more specifically, the lack of a need for it. If you force your frontend to only use what makes sense as a "general" backend API, it ends up being inefficient. There are 1:n calls needed to get all data, or a lack of a specific filter requires pulling back everything to do client side filtering, etc. On the other hand, if you build out your back-end to support every single front-end use case, it gets massive quickly. If other third parties start using it (as part of your published API) you now are forced to support it long term - even if your frontend changes and no longer consumes it - until you finally decide to break backwards compatibility (and the third party app). Break things enough and your users will quickly hate you. This is especially true early on, when your frontend is going though rapid and radical changes. I see BFF as the intermediate, giving best of both. You can rapidly adapt to front-end needs but don't commit to long-term support. There's actually no need for BC support at all if you can deploy front-end and BFF atomically. If you build your code in a structured way, you're sharing the actual business and data logic, and it's trivially easy to "promote" a BFF resource to the official API, with whatever BC commitment you want to provide. The key thing is you are doing this deliberately, and not because the front-end is trying something out that might completely change in the next iteration.
- rane 4y agoI think there might be a middle ground here that avoids introducing a BFF to be maintained and operated: in the back-end, introduce "faster moving" endpoints that are specifically targeted for front-end clients and that don't commit for long-term support.
- gregmac 4y agoWhat do you see as the difference between a BFF and "fast-moving endpoints"? To me, BFF is an unpublished API for internal use only. I can change BFF whenever I want (as long as I do the corresponding change to frontend) and don't have go through the effort of building+maintaining facades/wrappers/whatever for backwards-compatibility. If you have a 3rd party using an endpoint, it kind of changes things. Providing short-term instead of long-term BC is maybe slightly less effort, but any BC at all is an order of magnitude more work than none. With no BC, you would basically say "Hey on Thursday afternoon we're deploying a new version and the old one goes away -- be ready!". That nearly guarantees a 3rd party will have downtime, and is frankly a very hostile way to treat them. If I was the 3rd party I'd either be hounding your business for a long-term BC commitment for anything I use, or complaining about how it's a garbage API that constantly breaks on us and advocating switching away to a competitor ASAP.
- nomdep 4y agoI think it’s a great idea, except that instead of BFF, we should call that layer “a view”. The microservices can be then called “controllers and models”
- __del__ 4y agoi think you're onto something
- codemusings 4y agoThat was my first thought, too. OP is describing the view layer of an architecture.
- layer8 4y agoI’d say the BFF is an instance of the Facade GoF pattern.
- joe_fishfish 4y agoSo, what do we call the mobile app layer? The view of the view?
- zach_garwood 4y agoIt will also have a view and controllers and models. It is it's own application, after all.
- mkl95 4y agoThis looks like overengineering to me. The frontend cannot be that dumb. Every modern frontend technology out there can parse a bunch of JSON efficiently. If for whatever reason you don't want to call a few REST endpoints to render some stuff, then you should probably replace those endpoints with some other technology.
- yashap 4y ago> Hence, over-fetching is not an option If you actually measure real latencies (e.g. collect metrics from your mobile apps), this is not true most of the time, at least in my experience. Most responses are fairly small, making them a bit smaller doesn’t have much impact on mobile app performance in the real world. I’d guess for most apps, there are maybe a handful of endpoints where the response size can be reduced a tonne for mobile clients, AND that makes a big performance difference in practice. But instead of hopping straight to BFFs, or other approaches to solving this like GraphQL, you can just add a “fields” query param to those few key endpoints. If provided by the caller, you return only the fields they ask for. No massive re-architecture to BFFs or GQL, just a small change to a couple endpoints that a single dev can implement in a day or two. Now, there are other benefits to BFFs than minimal, client specific payloads. One is that you can make breaking changes to underlying APIs, and not break always-so-slow-to-upgrade mobile clients, by preserving backwards compatibility in your mobile BFF layer. Another is coordinating multiple calls - turning many sequential round trips into a single round trip can be a big win. But if your main concern is payload size, BFFs are probably an over engineered solution.
- eurasiantiger 4y agoOverfetching is a massive problem when your entity has multiple N-ary references to other entities, and those entities have multiple N-ary references to other entities, and those entities have multiple N-ary references to other entities. Suddenly, your frontend or API exhibits high-degree polynomial time complexity.
- cjonas 4y agoAre those references not split out as separate api "resources" that can be queried independently?
- eurasiantiger 4y agoThat just moves the problem to the frontend. Often it can be worked around with HATEOAS at the architectural level or lazy loading, pagination, etc. in the frontend, but not always.
- dajonker 4y agoI'm happy that the conclusion for this article starts with: > You probably shouldn’t implement microservices. Because the whole article just seems like making more problems on top of your existing problems.
- langsoul-com 4y agoAnyone got an example of this being implemented in real life? Hard to understand from just text and the concepts.
- throwawaylala1 4y agoI mean it's a pretty simple concept. Your frontend team needs an API call that retrieves only friend requests with user names/avatars because the current API call is too heavy. Normally they'd go to the back-end team and ask them to add an endpoint or modify an existing endpoint to give them the exact data they need. The problem with that is global API surface area becomes more complicated. Complexity is bad because more mistakes are made. With this model your front-end team can implement the endpoint themselves in the BFF and model the response data exactly as they need it. They also don't need to deal with that one zealot on the back-end team that gives everyone a hard time about tiny irrelevant issues.
- azangru 4y agoI see people say "graphql" a lot in this thread. There are a number of downsides to graphql that arise from its overly generic (and yet, at the same time, not generic enough) nature. No HTTP caching of graphql requests is one. Very deeply nested payloads is another. Difficulty of expressing complex query logic through parameters. Inability to natively represent structures such as trees of unknown depth. Special efforts spent on preventing arbitrarily deep/complex queries. And so on. A BFF does not have any of these problems. It can be made as closely tailored to a particular frontend as possible. It does not need to concern itself with a generic use case.
- dustedcodes 4y ago> The latter [BFF] is responsible for: > > Getting the data from each required microservice > > Extracting the relevant parts > > Aggregating them > > And finally returning them in the format relevant to the specific client I am pretty certain that the only reason why BFF were invented is for security in mobile and SPA applications, to securely deal with OAuth tokens. If you don’t need that don’t use a BFF, keep things simple. Start by not building a SPA when it can be a classic server client web app. I feel like most of the web should just be that.
- sweetgiorni 4y agoMaybe this works out for some engineering organizations, but man am I glad not to work with this style of "backend" anymore. The folks at my last gig did this and never have I seen such a mess of services. One particularly annoying pain point was that one of the engineering directors made it his personal mission to ensure that every service's Protobuf definition conformed to some platonic ideal. We'd have a BFF service Foo that essentially provides a wrapper around another service, Bar (among other things). Naturally, Foo's service definition included some Protobuf messages defined in Bar. Now the simple thing to do here would be to include those Protobuf message definitions in Foo.proto and expose them to consumers of the Foo service, but that apparently couples clients too tightly to Bar's service definition (?). So, it was decided that Foo's Protobuf file would contain actual copies of the messages defined in Bar. Adding a new field to a message in Bar wouldn't expose it to clients of Foo unless you also update the message definition in Foo.proto as well as the code that converts from Bar::SomeMessage to Foo:SomeMessage. Now imagine that the backend service is something commonly used, like UserService, and that there are potentially dozens of BFF services that contain copies of the definition of UserService::User. Welcome to hell. The aforementioned engineering director would hunt down BFF services that dared to include a message dependency instead of copying the definition. He would then open a ticket and assign it to the service owner, informing them that they were not in compliance with the "Architectural Decision Record": the indisputable, no-exceptions, holy-of-holies log of technical mandates that were decided by a handful of people in a meeting three years ago. This issue isn't necessarily inherent to BFF architecture, but I think it comes from the same place of overengineering and architectural astronautics.
- danbmil99 4y agoI've seen this pattern frequently lately -- front-end team develops "full stack" MVP using a react/node type stack. Then someone like me comes along when real back-end features are needed, and writes something in python, like an admin page. The point of contact is the db (typically Mongo) - and later on someone will add postgres to properly handle the data...
- jensneuse 4y agoI really like the BFF pattern as it can solve a lot of problems. That said, I've always found it quite complicated to build BFFs because there was no such thing as a "BFF Framework", which was one of the reasons we've built WunderGraph. One of the core use cases is to make building BFFs easy and solve a lot of cross cutting concerns. The idea is that you don't really "write" a BFF but rather generate most of it by treating APIs (origins) as dependencies. I'd love to hear what you think about this approach on implementing the BFF pattern: https://docs.wundergraph.com/docs/use-cases/backend-for-frontend https://docs.wundergraph.com/docs/use-cases/backend-for-fron...
- arein3 4y agoIs this really a problem? Why care about of a few kilobytes? Seems like bait.
- throwaway0asd 4y agoThat is still complicated. To maximally reduce complexity you need less. After all the word complexity literally means many. 1. Use a single traffic receiver at both the browser application and the terminal application. This thing works like a load balancer. It receives messages from a network and sends them where they need to go. There is only 1 place to troubleshoot connectivity concerns. You can still choose between monolith and multi-service applications and have as many micro services as you want. 2. Reduce reliance on HTTP. HTTP is a unidirectional communication technology with a forced round trip. That is a tremendous amount of unnecessary overhead/complexity. I prefer a persistent websocket opened from the browser. Websockets are bidirectional and there is no round trip. This means no more polling the server for updates. Instead everything is an independent event. The browser sends messages to the server at any time and the server independently sends messages to the browser as quickly as it can, which is real time communication happening as quickly as your network connection has bandwidth and your application can process it.
- trey-jones 4y agoYour first sentence was my primary takeaway from this article. Rather than dealing with complexity, I feel like these ideas create more. Issue has already been taken with "overfetching is not an option". It certainly is an option, albeit a non-optimal one. In this business, non-optimal is probably optimal for now, for most of us. I would like for there to be solutions to the problems identified in this article. I don't have them, and I also would like for the solutions to not be the ones laid out in this article. Better to build something new (?) than to put these band-aids on the existing framework.