Let's say you want to build an e-commerce project that can scale to meet all the needs across different clients. One of the solutions that will come to your mind will be micro services. You have micro services for Payments, Users, Reviews, etc.., and exposed APIs to be used by the frontend.
But each time, to put some bit of information on any device to show the user you are making multiple network calls to all of these services, engaging at that point in time and then aggregating the data before rendering the user interface.
The problem in the above case is -
- Clients (Frontend) has to do a lot of processing in composing the data.
- Make a lot of network calls to different micro services.
Other than micro services, the other most common architecture is of monolithic applications.
We have a single API gateway in monolith applications that serves multiple clients ranging Android app, IOS app, and Web Interface.
The challenge with monolith applications are-
- Not all clients consume the data in the same way, i.e., what you want to display on a web interface will be significantly different from what you want to show on your android/iOS app. This can make the code bleated as we now need to write code to detect which client is making the call to tune the data to be easily consumed.
- If we use the same API on mobile clients that we use for our web clients, we send too little or unnecessary data in API response. Because mobile clients have limited space compared to web applications, most of the data in the response are not helpful for mobile clients.
The common problem that we can find in both the services, i.e., monolithic and micro services, is that every single time we need to add some new data in the API or update the response, somehow we need to introduce a new API for the same as the current API response can be used other services at that given point of time.
In such cases, you can use a BFF to shift some of the logic to an intermediate layer. The middle transient layer will be the BFF.
What is BFF?
A technique where a dedicated layer serves a specific frontend platform is BFF. With BFF now, each platform will have a layer in front of it that facilitates its services, i.e., instead of directly making calls from our application, we will make a call to the BFF. And then this BFF will make calls to all these micro services. The BFF pattern was first used at SoundCloud. REA, Netflix, and IBM have since adopted it.
How does it fit in for the above mentioned problem?
The following image shows how each micro service connects with the devices through BFF.
In the above image, as you can see, now each client has its BFF. It will help with optimising responses by the services.
What will BFF do?
- Will make the relevant call to the appropriate services
- It will compose the results and then presents the data in a consumable way to the client.
- We can consume the data according to our needs, i.e., ask only for the required parameters.
By this, we will have minimal logic on the front end. It will help to streamline data representation and take up the responsibility of providing a well-focused interface for the frontend. From the ownership perspective, Front-end teams are responsible for managing their BFF.
We can have multiple BFF in our applications.
Advantages of having a BFF
Some of the advantages of having BFF are-
- Make clients independent: Clients (Frontends) will have a common source to fetch the data, but the end-user data is separated as they are sitting behind different BFF layers. This simply means that if you want to add a specific feature in Android only, then most of the changes will be done at the BFF level without bothering any other clients.
- Migrating from Monolith to Micro service: It can be helpful when you are trying to migrate from monolith to micro service architecture (especially when you have multiple clients) as before you even start moving services or creating the new services, you can create a BFF and make sure that you applicate all the call being driven by a particular client BFF so that we can decouple it from the single API Gateway.
- Better error handling in the frontend: Most of the time, server errors are meaningless to the frontend user. You can use BFF to configure the user readable errors instead of directly returning the errors that the server sends. It can improve the user experience.
- Avoid multiple calls: Instead of making several network calls from frontend client, we can make one single call to BFF, further calling the required service(s).
- Making Apps light: One of the advantages the web has over native mobile applications is that if you want to add a new feature, you need to make changes and push it out there, and as clients connect, they just see the new feature outright. But with mobile, one needs to build the feature into a new binary and then distribute it, and depending on which platform you're on, you might need to go through the process of reviewing the application (like Apple Store). If you use BFF, then it will allow you to control certain features and make changes. If you are doing an a/b kind of testing, you could have a feature sent out in the mobile app, but the way we implement the feature will be different in the BFF to find out whether it works or doesn't work. We can easily change it without having to rebuild the mobile application. In summary, with BFF we get 2 layers of control.
When to use the BFF pattern?
- Mobile app talking to multiple services: You have different clients communicating to the same application but not necessarily consuming data in the same way. Herewith use of BFF, you make your clients independent.
- Migrating to micro services architecture: If you are trying to migrate from a monolith to a MicroServices approach, it's another good reason to try out the BFF pattern as it will allow you to streamline the data flow and introduce a lot of efficiency to your application.
- Require third-party integration: Let say you have one web client, and that's the customer-facing part of your application. You want to expose certain services in your application to a third party. In this situation, what you could do is build a BFF for that integration.
Because if you're using the same API Gateway, it means adding more code to that layer. And for situations like this where you have a third-party integration, you find out that the third-party integration might not necessarily use the same services or endpoints that you have configured for your application, so you could easily have just moved that out into a BFF. That will make the flow independent.
Best practices to follow in practice:
Like any other technology or pattern, BFFs have pitfalls. Let's discuss some best practices that you can avoid when developing this kind of system.
- Avoid having self-contained APIs in BFF: One thing that developers forget when using BFF is that they start to implement the service level APIs in the BFF. BFF is only a translation layer between the client and the services. The purpose of the BFF is to transform the data into the data type specified by the client application. Self-contained inclusive APIs should be in the micro services layer.
- Avoid logic duplication: We should have different BFFs for different client types if we want a different user experience at each device which is not the case in the usual situation. Most of the time, all mobile devices, i.e., iOS, Android, etc., share the same user experience. In that case, one BFF for all the mobile clients is sufficient. There is no need to have a separate BFF for Android and iOS.
- Over-Reliance on BFF: BFF is not meant to serve more than a layer of translation. Yes, it's very tempting to use this concept as a front-line for security, for extended functionality, but one should not rely on it more than one should. Even after BFF is present, the main API codebase should handle all the functionality and things that API suppose to cover from the logic perspective.
The BFF pattern not only helps developers in development but also helps in improving the user experience drastically. It can be used in your applications to meet the diverse and evolving needs of consumers.
Let me know your experience of using BFF in your applications 😃