Web development (Frontend) has come a long way from its inception. There was a time when static websites were designed using tables for layouts and some styles around it which were only built for desktops.
But today web apps can be created with complex user interfaces and for cross devices. SAAS which are built as web applications allow us to stream movies and music on demand, order pizza, handle bank processes, even book a cab, and do more and more things which makes our life easier.
Over time to create apps which provide so much capabilities, security, flexibility, and also are manageable and scalable, organizations experimented with multiple architectures.
As a developer, architect, or tech lead, when we start a fresh project we need to decide which architecture we will be following. There are an array of options to choose from, but not all of them are fit for every job. We need to understand the challenges we will face along the way to make the right decision for our projects.
Let us explore the current architectures which are available to us for the frontend development.
Server side rendered websites were a thing back when they had not become the web apps. All they did was display text and images and very minimal interactivity.
These websites were built with server-side rendering which means the HTML was generated on the server along with all the data and it is returned to the browser and then the browser used to render it.
When a page refreshes or the user navigates to a different page, the servers used to send new HTML. This will be repeated every time if your browser does not have the cached version of that page.
As each time when you make the request to the server, the server regenerates the whole HTML even if we are only expecting for minor changes, this hampers the speed of the website.
Though the speed of the website varies on many factors like your internet speed, location of the server, number of users who are trying to access the site, etc.
For small websites these issues are negligible but for modern websites which have more than thousands of lines of code as well as complex logics will take more time for processing. Now imagine when you browse through the website and you have to keep waiting for each web page which you visit.
But the good thing about server-side rendering is that it is great for SEO. Your content is present before you get it, so search engines are able to index it and crawl it just fine.
In the current time, SPAs are the most used implementations. In single page applications client-side rendering is used. The browser loads the initial page from the server, along with the scripts (frameworks, libraries, app code) and stylesheets required for the whole app.
Using SPAs has many advantages like the whole application code is downloaded just once on initial load and then the entire application logic is available throughout the user session.
As the SPAs only deal with the client side logic, it can be developed independently and to get the data it communicates with APIs by exchanging data with the persistent layer (backend or server side).
The client side and server side are decoupled, which means that we can independently develop new clients for different platforms (e.g. mobile, chatbots, smart watches) without having to modify the server code. The client can also be developed using a new tech stack.
As we don’t have to repeatedly fetch the same resources again and again, we have to make fewer HTTP requests, also the payloads size is smaller which is faster to process.
Because both client and server side are decoupled which means they are smaller in size and faster to download, interpret and process.
All these features enhance the user experience and give an expression of what we usually have when we interact with a native application for mobile devices or desktop.
SPAs also allow us to decide how we are going to split the application logic between server and client. We can have either “thick-client” and “fat-server” or “fat-client” and “thick-server” depending upon which type of problem we are addressing.
Majorly “thick-client” and “fat-server” is used as by keeping all the logic on the server we can use that across multiple clients, that way if we update the logic on one platform it will be available on each client.
The bad thing about this is as the majority of the resources are fetched when the web app loads for the first time it can hamper the initial load time of the application majorly on devices with less processing power and slower networks.
There’s an additional step to be done on your server which is to configure it to route all requests to a single entry point and allow client-side routing to take over from there. All the client side routing is managed internally using HTML5 history API.
As the pages in the SPAs are dynamically generated on the run-time, another disadvantage of using SPAs relates to search engine optimization (SEO). When a crawler tries to index your website, it won’t have an easy job indexing all the contents served by an SPA unless we prepare alternative ways for fetching it.
Another disadvantage of using SPAs is on the organizational side. When the SPA is a large application being developed and maintained by coalted teams working on the same codebase, could end up with a mix of approaches and decisions that could confuse team members.
With the above two approaches we learned that server-side rendering can be used to solve the SEO related issues and client-side rendering can be used for performance optimization. What if we could use both of them together and use the best of both to create faster web applications which are also very well SEO optimized.
Isomorphic or universal applications are web applications where the code between server and client is shared and can run in both contexts.
The complexity of this approach is majorly among the state management. One way to solve this is to create and save the state on the server side and then provide this state to the browser. The browser uses this state to bootstrap the SPA, without this the user must wait for the server side page to render and wait more for the complete re-render process in the browser.
With these we can also solve the routing issue, you can either render the pages complete on the server-side or use the hybrid approach. Use the server-side rendering for initial view and then load an SPA, where the server will do the macro routing that serves different SPAs, each with its own routing system to navigate between views.
Isomorphic applications can suffer from the scalability problems if the web app is visited by a large number of users. Having a right caching in place could solve this problem as pages are rendered on server-side.
Micro-Frontend is a fairly new and emerging architecture which is inspired by the micro-services architecture of backend development.
When multiple teams are involved in the development of a single application, it becomes difficult to manage the code base and applications itself as multiple people will be touching the same code base.
This approach tends to solve this problem by splitting the application in different parts depending on the requirement and each of them would be developed independently which would be shipped as a single application. The main idea behind this is to break down a monolithic codebase into smaller parts, allowing to spread out the work among various teams, whether collocated or distributed.
There are different approaches for architecturing a micro-frontends application. Certain architectural decisions have to be made upfront because they will cave the road for future decisions. The decision majorly covers four key areas.
- Defining different micro-frontends.
- Composing micro-frontends.
- Routing micro-frontends.
- Communicating between micro-frontends.
You can decide multiple micro-frontends for the same view or having one micro-frontend per view and based on this we can split the application.
The application can be split horizontally or vertically.
In the horizontal split we split the views of the pages into multiple micro-frontends and different teams will be responsible for the development of these views. This approach provides great flexibility as certain micro-frontends could be reused across different views, but it also needs more discipline and governance to make sure we don’t end up with large amounts of micro-frontends.
In the vertical split we split the pages or module completely. For example different teams will be responsible for the development of different modules like authentication, streaming services, search, etc.
The primary advantages of these architectures are better performances, cheaper infrastructure and maintenance considering they can be served directly by a CDN, great scalability because static files are served, higher security due to decrease of attack surface and easy integration with headless CMS.
JAMStack is a great companion for many websites we have to create especially considering the frictionless developer experience.