Moving from the monolith Part 2, or: How I learned to stop worrying and embrace Single Page Applications

In part 1 of this two-parter, we delved into how the web evolved from its modest beginnings to the present day, and looked at how a decoupled architecture works in the context of a SPA frontend. Now, we look at why you might want to do it.

Advantages of decoupling

Better for users and site owners: Less waiting to load

According to Google, 53% of users will abandon a site if it takes longer than 3 seconds to load. Using an SPA, after the initial load, the interface elements remain loaded and painted in the user’s browser (unless you’re using server-side rendering, but let’s leave that for another blog). This means that navigating around the app involves updating what is already loaded, rather than requesting brand new (or repainting cached) content each time.

The ready-loaded app makes API requests, the responses of which contain just the raw data the app needs to correctly display. The result of this is instead of seeing a blank white window as the browser loads the content of the link they clicked, the user can see a loading bar in-keeping with the site’s design, giving developers greater control over the users’ experience.

Better for users: PWAs — websites as apps

A decoupled architecture allows easy implementation of a SPA frontend in frameworks like Vue, which make it easy to create Progressive Web Apps (PWAs). PWAs are a concept championed by Google. According to them, these are the key features:

  • Progressive — Work for every user, regardless of browser choice because they’re built with progressive enhancement as a core tenet.
  • Responsive — Fit any form factor: desktop, mobile, tablet, or forms yet to emerge.
  • Connectivity independent — Service workers allow work offline, or on low-quality networks.
  • App-like — Feel like an app to the user with app-style interactions and navigation.
  • Fresh — Always up-to-date thanks to the service worker update process.
  • Safe — Served via HTTPS to prevent snooping and ensure content hasn’t been tampered with.
  • Discoverable — Are identifiable as “applications” thanks to W3C manifests[7] and service worker registration scope allowing search engines to find them.
  • Re-engageable — Make re-engagement easy through features like push notifications.
  • Installable — Allow users to “keep” apps they find most useful on their home screen without the hassle of an app store.
  • Linkable — Easily shared via a URL and do not require complex installation.

Better for developers: Separation of concerns

Separation of concerns means that code/markup/styling is not mixed with code/markup/styling responsible for unrelated things. The creation of CSS was to separate the concern of presentation from that of the structure (HTML), for example.

In a web app, there will typically be a number of concerns. In a monolithic app, these concerns would (hopefully) be organised to keep their roles and functions distinct, but there are some scenarios it’s common for them to cross under.

For example, a PHP login page file typically might contain a block of code at the top that checks for posted credentials, attempts to authenticate them, initialise a session for that user and redirect them on success, or set an error variable on failure, before then outputting the HTML, CSS and JavaScript for the browser to enter, interpolating the error message if it has been set. The resulting file would bundle a number of concerns together.

In a decoupled app using an SPA framework, the HTML, CSS and JavaScript would be written in distinct sections of a template file, allowing the login form to be generated. Authentication would be handled by an authentication service, providing a token on successful verification, leaving the backend to handle verifying that token before performing whatever the API call requested.

Separating concerns is good, because:

  • To change a feature, there is less chance of code relating to other features requiring changes too
  • There is less chance of breaking an unrelated feature
  • If a developer is only responsible for one part of the system, they don’t need to understand other parts to work on it

Better for third parties: Services that can communicate

Your app’s frontend doesn’t need to be the only thing that communicates with your app’s backend. No sir. The great thing about having an API is that you can grant other parties access to it, meaning their system can perform operations on your system.

Say you’ve created an app that tells you the top 100 songs in the charts in a given year. If you grant applications other than the frontend you wrote for it access to its API, another developer could write a WordPress plugin that lets bloggers include that feature on their site.  

Downsides of decoupling

For all the wondrous possibilities decoupled web apps offer, I would be neglecting my responsibilities as a balanced arbiter if I didn’t address the less fine aspects of the approach.

The learning curve

As with any new skill, there are new concepts to learn. Creating RESTful APIs, the framework of choice and authentication are just a few things that may be new to monolithic application developers.

Suitability for smaller projects

Writing an app that allows users to submit their email address to a mailing list and nothing more? Don’t want to provide an API? Perhaps a decoupled app is overkill where a simple PHP page will suffice.

Additional point(s) of failure

Both monolithic and decoupled applications have client-side and server-side code, but in a decoupled application, the communication of the front and backends via the API is theoretically a potential point of failure. Similarly, if the app uses authentication, the authentication service is another.

In practice though, if the app is well made and authentication properly implemented, failures should be as infrequent as in a monolith.

CORS

In a decoupled web app, it’s common for the backend’s API to be served from a different origin to the frontend.

For example, a single page app might be hosted at example.com, with its API hosted at api.example.com. Modern browsers have a mechanism called Cross-Origin Resource Sharing that prevents requests being made from a site to a resource of a different origin (protocol, domain or port) unless the server sends a header to explicitly allow it. Cross-origin requests that contain certain commonly used headers like the Authorization header are preceded by a preflight request to make sure the server will accept the actual request before sending it.

This means that a common way to implement a decoupled web app architecture can lead to two requests being sent for each API action, which can result in actions taking slightly longer to complete. This delay is measurable in milliseconds but may be more noticeable on slower connections.

SEO

Though these days, Google’s crawler runs JavaScript to render content at the locations it indexes, meaning most of the time it can see an SPA site as it would be rendered to a user, there will always be edge-cases. Additionally, it’s easy to overlook other search engines. Bartosz Góralewicz published these results of research on moz.com into what search engines could index what SPA frameworks:

Chart showing which search engines can index which single page application frameworks.

He concludes on this:

When you launch a client-rendered JavaScript-rich website (JavaScript is processed by the browser/crawler to “build” HTML), you can be 100% sure that it’s only going to be indexed and ranked in Google and Ask. Unfortunately, Google and Ask cover only ~64% of the whole search engine market, according to statista.com.

This means that your new, shiny, JavaScript-rich website can cost you ~36% of your website’s visibility on all search engines.

If your app is fronted by pages that render static content, this isn’t an issue, but if the front and landing pages of your site are to be part of your decoupled app, consider Isomorphic JavaScript, Server Side Rendering (SSR) or prerendering.

Examples

Summary

A decoupled app architecture is not a silver bullet for every complication, nor is it the only way to make an app the world will envy, but in giving the user an interface to interact with the system before anything else, a decoupled architecture allows you to create a rich user experience, freeing users of interruptions that can turn them off a site, streamline development, more easily implement CI/CD and open up your service to work with third parties. You can also experience the joy that is developing in Vue.

Further reading