In this webinar, Leif Åstrand, Product Architect here at Vaadin, discussed the complexities of building modern web applications. He challenged the notion that endpoint APIs should be managed by backend development teams, by making the case for the Backends for Frontends (or BFF) pattern.
You can watch the video on Youtube below or continue reading for the text version.
Coupling between the ends
We begin by looking at everything that goes into an endpoint with Vaadin:
@Endpoint
public class GreetEndPoint {
public String sayHello(String name) {
return “Hello, “ + name;
}
}
And then the corresponding client-side code:
import * as greeter from './generated/GreetEndpoint';
async function greet(name: string) {
let greeting = await greeter.sayHello(name);
console.log(greeting);
}
When people look at this, they often react to the coupling between the backend and frontend, but there’s a but… let’s take a look at what's what.
Basic application structure
This was the typical architecture of an application in the early years of software development:
Application |
Just one thing that runs on a computer, locally.
If you want to exchange data with other users, we need a separate database and then a client, often referred to as a “fat client” or “rich client”:
Application ____________ Data |
Now you have all your application logic in one place, running locally on your computer, and then you have some data, on a server somewhere, that your application and everyone else's application can communicate with.
This is already an improvement to a locally confined application since you can exchange data among users.
However, this division wasn’t enough to keep up with demand. It was followed by what we now know as a “traditional three tier application”:
Presentation _____________ Logic _____________ Data |
The application (not the data) is split into presentation and logic. This is because you often use different technologies and approaches to build them. Having them split up helps keep development of each in its own slot.
What happens next is that the application scales and grows larger, which requires more people or often separate teams to build and maintain it. So, one team focuses on the visual presentation and user interaction, while the other team deals with the business logic and database etc.
But then, as development scales even further, teams are often split up again and cross-cutting teams are formed between them. This allows development to grow much larger without too much communication overhead.This way, a team can focus on the presentation, logic and data of only a specific feature of a web application. For example, the product listing on a web shop app can be implemented and updated by one responsible team, while another team owns the checkout experience.
The cost and benefits of separation
The separation into feature-specific teams not only tackles an architectural problem, but also an organizational problem.
But what does it cost to separate things this way?
Cost of separation:
- Complexity
- API Design
- Stability expectations
- Reduced visibility
Benefits of separation:
- Enforces structure
- Allows independent deployment
- Enables separate ownership
Separation results in specialized teams for every part of the application; each team can do their work without stepping on the other’s toes. This adds complexity to the work of each team.
How does this apply to web applications?
Let’s look at a typical, modern, web application:
Angular / React / Vue - for frontend ____________________________________ Rest / GraphQL - for communication between them ____________________________________ Whatever, as long as it’s stateless - for backend |
This is a pattern with several benefits, such as:
- The presentation has declarative definitions of what the UI looks like.
- You can define UI as a function of your state, which helps avoid a lot of bugs.
- A stateless server is great if you wake up one morning to a million new users!
At Vaadin, we came to the same conclusion; lots of people like this and we can contribute to it by improving things even further.
Vaadin is about combining Java with “web stuff”. You can, of course, use whatever endpoint system you want, but if you opt to use our endpoint solution, together with our frontend solution, they fit together like the pieces of a jigsaw puzzle. Yes, you need to use Java on the server, but you get a lot of benefits in return, i.e. an integrated solution where everything works hand-in hand with type safety and so forth.
Java } web >
Returning to the code snippet we had right in the beginning; we can see the endpoint function and TypeScript in the browser (presentation) and the coupling between them:
@Endpoint
public class GreetEndPoint {
public String sayHello(String name) {
return “Hello, “ + name;
}
}
import * as greeter from './generated/GreetEndpoint';
async function greet(name: string) {
let greeting = await greeter.sayHello(name);
console.log(greeting);
}
What we wanted to achieve with this integrated solution is end-to-end type safety.
For example, if we change the endpoint to require a number
instead of a string
, then your fronted immediately gives a compilation error.
So Vaadin provides the end-to-end type safety benefits at the cost of the coupling. However, this isn’t necessarily that big of a problem.
This is how we spontaneously think about application structure:
Presentation ➡ Browser _____________ Logic ➡ Server _____________ Data ➡ Database |
But, we already see that those layers don’t have an exact match; when you use the JPA, for instance, for data layer stuff, then you implement that using Java, your server-side language.
And the same goes for the frontend stuff.
The trick is to separate the layers, so that your endpoints are architecturally a part of the presentation layer, owned by the presentation / frontend team, but they actually run on the server.
Presentation ➡ Browser @Endpoint _____________ Logic ➡ Server _____________ Data ➡ Database |
That’s the theory. So yes, the frontend developers should be building their endpoints. In practise, this impacts both the architecture and the organization. One implication is that your frontend team needs Java knowledge.
This practise is known as Backend for Frontends, or the BFF pattern.
Presentation Backend For Frontends _____________ Logic _____________ Data |
Backend for Frontends
This pattern originated from having separate frontends, for example, a web client and mobile client, where the desktop version was data heavy compared to the performance-optimized mobile version.
Presentation 1 / Presentation 2 BFF 1 / BFF 2 _____________ Logic _____________ Data |
A common concern with this practise is the need to integrate with a 3rd-party application. However, that external Rest API is just another presentation layer. This pattern is therefore not excluded by an external API.
Presentation 1 / External API BFF 1 / BFF 2 _____________ Logic _____________ Data |
The next piece in the puzzle
‘Architecture is any kind of technical decision that would be difficult to change later’
How you separate, attach, slice and combine teams, impacts everything in your application development process.
Meet Vaadin
Vaadin Fusion is made for those with a Java backend who want to use a declarative UI as a functional state.
To get the best possible integration, we ended up with code generation that leads to coupling
To deal with the coupling, we come back to the Backend for Frontend idea; that originally came from when you had multiple frontends, but it also applies where you want to have coupling with server-side and client-side code.
Furthermore, it’s easier for you to design a great UX when you can optimize how to fetch things; data can be loaded faster when you can easily customize how things are loaded over the network.
Check the YouTube recording for a post presentation Q&A session and don’t forget to sign up for our next webinar with Justin Fagnani from Google!