Backend for frontends

The current world demands a mobile-first approach everywhere. The service may respond differently to mobile where it has to show little content, as it has very less content. On the web, it has to show huge content as lots of space is available. Scenarios may differ drastically based on the device. As for example in the mobile app, we may allow barcode scanner, but in desktop, it is not a wise option. This pattern addresses these issues and helps to effectively design microservices across multiple interfaces:

  • Problem: With the advent of development of services supporting multiple interfaces, it becomes extremely painful to manage everything in one service. This constantly evolves change in any of the single interfaces; the need to keep services working in all interfaces can soon become a bottleneck and a pain to maintain.

  • Solution: Rather than maintaining a general purpose API, design one backend per user experience or interface, better termed as a backend for frontend (BFFs). The BFF is tightly bound to a single interface or specific user experience and is maintained by their specific teams so as to easily adapt to new change. While implementing this pattern, one of  the common concerns that occurs is maintaining the number of BFFs. A more generic solution would be separating concerns and having each BFF handle its own responsibility.

  • Take care of: While implementing this design pattern, the following points should be taken care of as they are the most common pitfalls:

  • A fair consideration of the amount of BFFs to be maintained. A new BFF should only be created when concerns across a generally available service can be separated out for a specific interface.
  • A BFF should only contain client/interface-specific code to avoid code duplication.
  • Divide responsibilities across teams for maintaining BFFs.
  • This should not be confused with a Shim, a converter to the convert to interface-specific format required for that type of interface.
  • When to use: This pattern is extremely useful in the following scenarios:

  • There are varying differences in a general-purpose backend service across multiple interfaces and there are multiple updates at any point in time in a single interface.
  • You want to optimize a single interface and not disturb the utility across other interfaces.
  • There are various teams, and implement an alternative language for a specific interface and you want to maintain it separately.
  • When not to use: While this pattern does solve lots of issues, this pattern is not recommended in the following scenarios:

  • Do not use this pattern to handle generic parameter concerns such as authentication, security, or authorization. This would just increase latency.
  • If the cost of deploying an extra service is too high.
  • When interfaces make the same requests and there is not much difference between them.
  • When there is only one interface and support for multiple interfaces is not there, a BFF won't make much sense.