Meet Arantio – they are the guys behind the Smartum brand, providing employee benefits solutions for over 1 million users in Finland. They need to process loads of data every month and, at the same time, introduce new software solutions to their clients frequently. And if you know anything about IT, you probably realise that “enormous loads of data” and “updating your software product” aren’t exactly two things that get on well together. So, the most crucial question is how do you refresh your software without destroying the whole business logic on the backend? You can introduce the Backend for Frontend pattern.
At The Software House, we think of ourselves as of a long-time technology partner of Arantio and its sister companies. We’ve already introduced a few case studies of projects we’ve developed together throughout the years, e.g. Smartum and Vaana. The article below is a kind of a case study too – but this time it’ll be more tech-oriented. I’ll try to present you the goal we needed to achieve when cooperating with Arantio on a new product. Then, I’ll focus on the development process and the final result of introducing the Backend for Frontend solution.
How to refresh the frontend without breaking everything
Arantio has a few different software products under its wings. These products, even though slightly different, have one thing in common: they are all connected with “the heart” called Arantio Core.
Some time ago, Arantio decided to refurbish their apps. Firstly, they wanted to provide existing clients with a more appealing, smooth-working frontend of their applications. Secondly, they thought of securing a new market niche in the future by selling their products in the SaaS model, thus acquiring new clients.
Obviously, this whole idea posed quite a problem: every new application needed to be based on the Arantio Core but we couldn’t implement any major changes in the Core in required time to make sure we won’t destabilize its compatibility with the apps for existing clients.
At the same time, the list of requirements regarding the new single page applications that Arantio wanted to develop was quite long. We needed to implement the possibility to activate or deactivate certain modules (such as paying with your phone or offering vouchers in the app) for all the prospective clients. Also, we needed to offer some branding features (for example, color changes). As the code was shared by a variety of applications, it reduced the chances of any advanced customisation. It would be simply impossible to test, maintain and develop any major changes while using single codebase.
Taking into consideration all the client’s requirements and aforementioned limitations, we’ve decided to build an intermediary API – used as the “Backend for Frontend” (BFF) dedicated for single page applications (SPA).
Preparing the legacy system to introduce the Backend for Frontend pattern
The main idea was to create a proxy between the Arantio Core and SPAs. The Core had to retain almost the whole business logic and store all the data. The API needed to be simplified, as we wanted to make sure that it would ensure easy access (for our SPAs) to the data stored in the Core. Also, we had to develop a customisable SPA solution which could be tailored to the requirements of each client.
We’ve decided to use Symfony (updated to Symfony Flex at some point; now, one of the newest versions of Symfony is used) because we thought that it will fit the task perfectly. Also, we knew that we have a pretty solid experience in Symfony here at The Software House. After choosing the technology stack, we planned the development and particular tasks.
The first phase of the process was pretty demanding. We had to imitate all the functionalities of the client’s former system on our side.
It was a difficult task because, depending on the context of a particular app, similar elements had different names. We had to unify and simplify them. Also, we couldn’t do that directly in the Arantio Core, as we could affect the other applications relying on it. The work that we carried out during this first phase was extremely important: in fact, we introduced a new logic and simplified a lot of things.
To make it even more difficult, the documentation we had was incomplete and/or outdated. That’s why, when creating endpoints in the API, sometimes we relied on the docs, sometimes we asked the client for details, but pretty often we simply had to check particular things in practice (in the old system) and then reproduce them.
More details? Here were go!
The aforementioned Core is a legacy PHP API and many different web and mobile apps are relaying on it. That was the biggest restriction for us, as we couldn’t access the data directly. At the same time, we couldn’t introduce any significant change because we didn’t want to break something. The communication between our BFF API and Core was using traditional REST, but thanks to some smart infrastructure design, we were able to achieve quite low latency there.
The request payload and response from API format differs from the legacy version regarding many things. Probably the most important difference is the simplified structure and completely new field naming – to match client domain names. Some values are also being formatted to standardised format (e.g. money values, dates, statuses). One significant example could be interpreting the value of “boolean” fields which we received on some endpoints, which could be: true, null or empty string… Yeah, really!
Here are some basic examples:
At the beginning, we used simple JSON to array mapping which gave us the flexibility we needed. Currently, we are converting the JSON Core response to domain objects. We find them better than regular arrays, as they are well-defined and could simplify various logics we previously needed to implement for ourselves (e.g. by using serializer directives).
Creating the permission module
The second part of our process was preparing the new platform for the inflow of users with various permission levels. We divided the app into the modules which were available for a variety of users, depending on their scope of access (for example, some users could read and save the data, some could only read it, while others had no permission at all).
The whole authorisation had to remain on the Arantio Core side. However, we also had to mirror it on our side to make sure we don’t send any unnecessary requests which would have been rejected due to the low level of permission.
Eventually, the whole permission mini-module had to be taken from the app as a separate microservice and shared between Arantio Core and the other applications – to make sure everyone has the same permission and that it’s possible to coordinate it and manage it from one, central place.
Here comes the command pattern
Since the very beginning of our work on Backend for Frontend, we’ve decided to take advantage of the command pattern. It’s a relatively easy and effective pattern in which independent commands containing all the necessary information are being operated by a dedicated handler to execute a certain action. Thanks to that, all the operations in the service are encapsulated – therefore, easier to be managed, developed and maintained in the future.
We decided to go with the most straightforward approach as we were still constrained in terms of what would be possible to implement (even simplified CQRS would be either impossible to introduce or extremely ineffective in terms of requests made to the Core). Our commands were created directly by Symfony Forms which are handling all the incoming payload and validation which we have defined on them. When needed, these commands could be either pre-filled before the form run or appended afterwards. Handlers dedicated for each command would execute required logic for a given action – depending on specific endpoint it could be a simple request to the core or multiple requests depending on each other with some additional logic.
Each request that comes from SPA to our backend has to be in line with our requirements (coming from the analysis of what kind of data is necessary for the frontend app). In that format, a lot of parameters received a new name, as they had to better correspond with the domains of the apps. And, at the same time, it allowed for the unification of these names within different endpoints. Now, all the requests are being translated by the backend application between the Core format and our redefined format provided to the dedicated SPA.
Developing Backend for Frontend – was it worth it?
Our main assumption when creating the BFF for Arantio was to make the process of connecting new products to the Arantio Core as easy as possible. Also, we’ve concentrated on adjusting the BFF to applications of a certain kind – in our case, SPA. We didn’t have a database of the users or any other data provided by Arantio – everything like this was still stored in Arantio Core. We had only a secondary database which allowed us to cache certain data for improved performance in sensitive parts of our application.
Did we achieve our initial goals? Yes, sir. Thanks to the use of the Backend for Frontend solution, we were able to introduce new domain names, we simplified the whole process and made it smoother. Now, when opening the BFF, you can choose the client you need and then all the modules with the predefined permissions will be loaded from the backend configuration.
Thanks to the backend for frontend solution, command pattern and modular architecture of applications, you can build as many single page apps as you need and very quickly indeed. What’s more, all the SPAs can be customised in terms of modules.
That’s how we met the initial idea of Arantio. We developed a customisable solution on top of Arantio Core which may be used not only by all the existing Arantio clients, but also by any other potential partner in the future – thus allowing Arantio to introduce the SaaS model.