We have all been there: dealing with a huge monolith, trying to understand the original architecture of the project and trying to find logic in the code. Annoying, but no need to despair, because often enough there are microservices to help you out. Simply split the application into smaller applications. However… this has a lot of impact on the Frontend: different endpoints, different requests, different responses.
To keep the Frontend and the Backend best friends forever (BFFs), in this blog we welcome another type of BFF, the Backend For Frontend.
Let’s look at monoliths first
Monoliths are bad? Not by default. An advantage of a monolith is that all code stays together in one codebase. This makes build and deploy procedures often straightforward, since there is only one codebase to build and deploy.
On top of which, a monolith offers good performance in general, because it does not have to connect with other services, which increases response times. And because it is a single application, it has only one entry point: therefore it is easy (or easier) to secure. All services and functionality within the monolith are secured the same way.
Figure 1. Monolith architecture
The bigger the monolith gets though, the more drawbacks you encounter. For instance, with a huge codebase, it takes a lot of time to figure out how it is set up and how it works. It also means that every little change leads to a deployment of the whole application.
To make things worse, you are ‘stuck on stack’. There often is little room to use different programming languages to solve issues. You have to deal with the stack used in the monolith.
Finally, one of the biggest drawbacks of a monolith is that it isn’t scalable. You can only scale the entire application, but not specific parts of it.
To solve these issues we can shift to the Microservice architecture.
Microservices to the rescue!
Microservices are small and lightweight applications built for a single purpose. They are highly maintainable and testable, which enables rapid and frequent development and deployment. And, opposite to a monolith, microservices are easy to scale.
E.g. if a single microservice has a high CPU, which leads to a loss of performance, you can simply deploy another instance of this microservice, so that the load on this particular part of the application will be handled by 2 instances.
Furthermore, microservices are loosely coupled with other services, so there is no impact on other services when changing features of a certain microservice. When you develop new features in a new microservice; this does not affect other services.
Another upside is that there is no required stack or required technology. Theoretically you are free to choose what you want. In practice, however, you will have to align with what suits the application and the team best.
Figure 2. Microservice architecture
When splitting the monolith into separate microservices you encounter some trouble as well. Each microservice has to deal with its own security, since each microservice is accessible. So you probably end up with a security service or library. Like a base Docker image or a Maven archetype, which is used by each microservice.
The downside then is that for each change in such a solution, all the underlying microservice have to be updated too.
Since a microservice is an application on its own, they all create their own, unique endpoints. The frontend needs to point to all the endpoints, so all have to be updated. Furthermore, if the request to and the response from these new endpoints change, due to some changes in the code, then this has to be changed in the frontend too.
Besides the frontend changes, we now face a new struggle as well: how to keep all the microservices in line? More requests can lead to timing issues (a microservice takes too long to respond), duplicate data (multiple microservices return the same data) and information exposure (the response from a microservice contains data needed for another microservice, but might contain sensitive information which was kept internal in the monolith).
It all interferes with the balance between the Frontend and the Backend. To restore the relationship between them, please welcome the BFF: Backend For Frontend.
Backends For Frontends
A BFF (Backend For Frontend), also known as an API Gateway, is a single entry point for the Frontend. It takes care of all the requests from the Frontend and in its turn, it gathers the needed information from the underlying microservices to return the response. Whereas in the microservice architecture the routing was done in the Frontend, it is now done in the BFF, and therefore unnecessary data is not exposed in the Frontend.
By using a BFF, for the outside world, you can still work with microservices in the internal network. This way you will have the best of both worlds. With a single entry point to secure, as you have in the monolith scenario, but with a microservice architecture at hand for rapid development.
For added flexibility, you can have multiple BFFs, if that fits your architecture. For instance, you can have a BFF for each kind of client: a BFF for Web, Mobile and 3rd parties. The Mobile BFF can even be split up into an iOS and an Android one.
Figure 3. A single BFF architecture
Similar to Monolith and Microservice environments, there are also some things to consider when using a BFF. Since it is an extra layer, the response times will increase. The gathering of data among multiple microservices requires the BFF to make some extra calls. In practice this should not be that demanding on time or budget, but it is something to take into account.
Finally, since there is one entry point, it could be a bottleneck or a single point of failure. It is, again, a separate service or application in the architecture, which needs to be developed, tested, deployed, maintained, etc.
Each approach has its pros and cons. You must choose wisely which one suits your case best. This could very well be a monolith, because there is nothing wrong with a good monolith. Does the monolith grow bigger or do you foresee many services? Then a microservice architecture is fine too. Ultimately, if a lot of microservices are to be used, chances are you will ❤️ a Backend For Frontend setup.