Implementing a Mediating Layer
Implementing a backend for frontends, or as we at Apegroup call it “a mediating layer” is something we have found to be greatly beneficial in enhancing and optimizing the user experience and scalability for our clients’ digital products.
A little background
Apegroup has worked with design and development of digital products for almost 15 years and one recurring big challenge during this time has been client-server integration. Our role has traditionally been to design and develop the client parts (such as native applications) which integrate directly with APIs provided by our customers.
In most cases a rich user experience got compromised, and to some extent, lost when we had this little influence on the way API’s were developed. Instead of putting time into delivering the best possible experience, lots of effort and time was put into discussions with the customer’s backend development teams regarding the format of an API specification and how to prioritize releases for functionality needed for the frontend development team consuming the APIs.
Even though a lot of effort was put into the work with the API specifications, the final documentation from the customer’s backend team still left our developers with a fair amount of guessing in the interpretation. On top of that, the API responses was sometimes incorrect or didn’t match the latest specification.
Our challenge:
- We often needed to compromise the user experience since we couldn’t design APIs in an optimal way. Big multi-purpose APIs to suite both native and web applications at the same time made us cut corners both on performance and data structure.
- Frontend and backend development teams do not always share an understanding of each others priorities or challenges. In many cases this led to lead times when the team waited for functionality to be released from the backend development, and we spent a lot of time in creating a mutual understanding of the API specifications.
- Most applications we built integrated directly both with the customer’s APIs and multiple 3rd party services. This required the frontend applications to make many requests, which is inefficient. Sometimes even towards APIs not created or adaptable for mobile use.
- Business logic and transformation of data that couldn’t be built by the customer’s backend team often needed to be built into the frontend applications, and when working with native applications that means the same logic had to be developed twice (or even thrice sometimes) for different platforms. This occasionally resulted in unconsistent behaviour between platforms and duplicated work to implement features and/or bug fix the same thing in multiple places.
- We have a long experience in creating digital products for mass markets and millions of simultaneous users, but when the applications integrate directly towards the customer’s backend we can only trust the customer and cross our fingers when they say: “Sure, we know that the solution will scale to hundreds of thousands of users the first day. We have done extensive load testing and we don’t want to pay for you helping us to verify it again!” More than once a massive surge in traffic made the service unusable because there was no way for us to quality assure the scalability.
So what did we do to solve this problem?
Step 1 — An integration sprint
Before starting the regular development sprints, where we would consume the APIs, we decided to start with a dedicated integration sprint. The goal of the sprint was to decide on how the API specifications should be documented. A secondary goal was to give the developers a chance to get to know each other to improve collaboration.
Knowing how to document the APIs, the developers could then agree upon delivery dates for when the API specification and an available mock could be ready, and when the actual API would be implemented, for each of the required APIs. This approach was then tested on a simple API to start with.
Letting the frontend and backend developers work together with the format of the specification, reduced a lot of misunderstandings.
At Apegroup today, we use Apiary for documenting the API specification. Apiary also automatically creates live mocks for the API which can be consumed instantly. To automate testing of the implemented APIs, we are using Dredd, a HTTP API testing framework.
During the concept and definition phases of the project, a solution architect holds workshops with the customer in order to gather technical insights. The insights include architectural requirements, understanding of the system architecture and security impacts. With these insights, the architects assess the feasibility of different solution, which is fed into the integration sprint.
Step 2 — A mediating layer approach
The integration sprint helped to reduce the risk of misunderstanding and created a common understanding between the frontend and backend developers on how to design and document the APIs. However, it didn’t really enhance the user experience that much.
To enhance the user experience, we had to decouple the development of the frontend clients from the backend APIs. Some years ago, we started to talk about Backend for Frontends, or as we call it, a ”mediating layer”.
A mediating layer is a server-side application that acts as a mediator between the frontend applications and the customer’s IT environment and third party services. This allows the frontend application to have only one backend service to consume.
The mediating layer will communicate with the customer’s IT environment and third party services, and even orchestrate multiple calls in order to concatenate information. The information retrieved can be cached and transformed into domain models that is tailored for each frontend client and thus will enhance the user experience as only the data required by the client will be sent. Implementing good caching also improves quality of service, as the calls to the mediating layer become deterministic.
Not only does the mediating layer improve the user experience. It will also enable us to move logic from the clients to the mediating layer, logic that would have to be implemented in all clients. This increases code reusability and modularisation which shortens time to market.
By optimising the communication between the clients and the mediating layer we can reduce the payload in each request and also optimise to make fewer requests from the client. This vastly improves user experience.
With the mediating layer in place, we could easier adapt the clients to new requirements driven by user behaviour as we are in control of both the clients and the mediating layer. Also, changes in the backend APIs does not affect the clients as the mediating layer could manage the updated specification and keep the client APIs consumed by the client unmodified.
Today, when we build applications, we almost always reuse our blueprint architecture, where we have one or more client applications and a mediating layer deployed to the cloud. This setup allows us to scale instantly to various loads and to modularise and reuse business logic. This way we start simple and avoids to introduce an oversized architecture.
Over time, and if required, we can always refactor our API and introduce dedicated APIs for each client/platform respectively, which further enhance the user experience.
Conclusion
We strongly believe we can add a great deal of value by using mediating layers as part of the solutions we build for our customers. I think that it solves a lot of the problems we have experienced when working together with our customers’ backend teams over the years.
- Enhanced user experience — Tailored APIs for each platform including optimized payload and reduced request frequency results in better experiences for the end user
- Project efficiency — API changes initiated by the frontend application are decoupled from the backend development team so that the frontend development team can manage its own work and mock data until real data is available
- Frontend-backend decoupling — Enables easier migration of backend systems and much easier integration of 3rd party service integrations done in other projects. Public APIs used by current services can also remain intact coexisting with new platform specific optimized APIs consumed through a mediating layer.
- Reusability — Modular scalable architecture for existing integrations which results in increased code reuse, together with the possibility to move logic from the clients to the server when working with several platforms such as iOS, Android and web simultaneously.
- Scalability — The mediating layer is built on cloud-based services and can easily handle autoscaling when load increases, content distribution for increased performance, load balancing and more. We can be confident that when we build a digital product for the masses we can scale instantly according to our needs.
My name is Joakim and I’m head of technology at Apegroup. We’re a design and technology studio in Stockholm, Sweden. If you want to know more about us, check out our website.