The great web app schism – a short story about the separation of concerns.

Damian Romanów on 23 November 2017

Historical context

The Internet in its early stage looked pretty rough. That period could be called the Middle Ages of web development. Nobody knew what the ‘User Experience’ term meant in the context of websites. Content was organized equally well as stains on abstract images, links had to appear in their underlined form and animated GIFs were everywhere. How cool was that!?

http://www.arngren.net

Some machines stored a bunch of static HTML files, ready to be sent to the client. Browsing the web was like browsing files on your computer. You asked for a particular URL and got a document in response. The web browser interpreted the document, rendered it and then the interaction was finished. All communication was bound to be a request-response cycle and fetching additional data required a full page refresh. Rarely, some JavaScript code was involved to perform “magic” tricks, a.k.a. an annoying button running away from your cursor.

Some time later, the PHP language has appeared. Websites were enriched with dynamic content. Webmasters (one of the most distinctive words of that ancient glossary) were enabled to use a bunch of Content Management Systems (like WordPress, Joomla) or even to craft their own ones. New websites started to pop up like mushrooms. Everyone could note their online presence, by having their own website. A revolution had started. Even now, we can easily find traces of that process. According to W3Tech, PHP is used in 82.2%, and WordPress in 28.5% of all websites!

Golden train on Rails

About 10 years later, the Rails framework saw the daylight. It vastly popularized the Ruby language and became a strong advocate of the Model-View-Controller pattern. But first of all, it enabled developers to quickly deliver relatively advanced features to their clients. It was famous for its ability to create custom blog engines in 15 minutes (try to google “rails 15 minute blog”). Websites were getting more and more sophisticated.

But the constantly growing requirements forced them to change again. Smooth reaction to user behavior turned out to be the selling point of many applications. Users did not want to wait. So doing a full page refresh after the “order” button had been clicked was a waste of their time. And wasted time decreases the potential revenue of your business. To meet this “responsiveness” criterion, developers started to perform asynchronous calls for additional data. This pattern is called AJAX. Generally, the more AJAX you make, the better for UX. But those additional calls also come at a cost. They add complexity both to the client and the server. That complexity shot down many great apps. Maintaining the server (Ruby, PHP, Java for instance) and the client code (Javascript) in a single project is a daunting task and usually leads to an intricate puzzle. What can we do with that? In computer science, there is a very useful paradigm, called “divide and conquer”.

Schism

Almost every modern web application makes a clear distinction between the client and the server. Clients focus on presenting data and handling user interaction. Core business processes are handled at the server side, where we have the opportunity to authorize and validate user intents. It is also common to move CPU or memory heavy computations to our backends.

Did you realize that I wrote ‘web application?’ They are not ordinary websites or webpages anymore. Of course, you can call Google Docs a website only, but from a technical point of view, that would be an oversimplification. Websites which do not require a full page refresh after the initial load are called Single Page Applications. Fetching additional data and redrawing it in the user screen is performed at the client’s browser. That results in a native-like experience. Using that kind of app is very similar to using desktop or mobile counterparts. They are often enriched with animations, performing the actions has an immediate reflection in the UI and navigation through them is very smooth. And in addition, they can keep all the advantages of traditional websites (e.g. sharing content via deep link). Those types of apps have become very popular these days. There are many frameworks and libraries which simplify bootstraping this modern pattern – like Ember.js, React, AngularJS, among others.

Single Page Apps have several advantages:

  • Untie UI from request/response cycle

In a traditional server-rendered website, resource retrieval is constrained to fetching a whole HTML document. Even if only a small part of the layout has been changed, the server is obligated to generate a whole document as a response. That attitude is very simple and has worked well for years. But the constantly growing expectations and requirements faced by today’s web-apps make it too limiting. More and more data is fetched asynchronously, after the initial render of the website has been done. That allows web-apps to better fit user intents and results in a more flexible and eye-catching UI.

Doing full page refresh only to change one button is suboptimal.
Doing full page refresh only to change one button is suboptimal.
  • Strong separation of concerns

Each part of the system is only responsible for its own duties. The backend should not be aware of the UI & UX details. In turn, frontend does not necessarily need to know about the database engine used to store data and its denormalization. That leads to a more decoupled architecture, which is more change-resilient. And that reduces the cost of maintaining the code and introducing new features.

  • Flexibility of deployment

As we have two independent applications instead of one, we can deploy them separately. Each of them needs to meet different conditions. For instance, our backend may serve as an API for a web app, Android and iOS apps. It may even expose some part publicly, in order to enable other applications to integrate with it. All those sources can generate vast amounts of traffic. Such requirements imply using a powerful machine or applying some cloud solutions. On the other hand, a server which only pre-renders a Single Page Application does not need to be that capable.

  • Flexibility of development

This attitude shines very bright also in terms of the creation process. Each part usually has its own repository. Each can be crafted using different technologies and programming languages (well, frontend is quite limited to JavaScript). They can be developed by separate teams, outsourced to subcontractors. Each part is interchangeable, as long as they keep their interfaces unchanged.

  • Reduction of bandwidth

Single Page Apps do not need to fetch a whole HTML document from the server. They contain all graphical components, styles and know the HTML structure. Data is only one “moving” part, and transferring it in a JSON form is noticeably more lightweight. That matters, especially on mobile web.

The dark side of the Moon

The programmer split up his app and saw everything that he had made, and, behold, it was very good. Well… almost everything. Life is not that easy and the IT world is not a bed of roses. It is all about trade-offs.

If you decide to split up your system into a separate backend and frontend, you can stumble across several obstacles:

  • Time to market is longer

Since we are dealing with two subparts, each with a separate codebase, starting with a simple prototype would be a bit more time consuming. Bootstrapping a new project has some initial cost, and now we have 2 projects, not one! This slowdown is particularly visible in small apps based mostly on forms. SPA in such cases may be an overkill.

Initial development velocity of a SPA is lower, but with time it gets higher.
Initial development velocity of a SPA is lower, but with time it gets higher.
  • Communication overhead

This factor needs to be taken into account for every distributed system. Communication inevitably involves a cost. This sentence is true no matter if we are talking about people or machines. If a system is developed by 2 separate teams, each of them must be aware of the changes made on the other side. That requires a responsible and transparent approach to communication. The same rule applies to computers. Fetching data through the Internet takes time and is not reliable. Transfer could be interrupted or delayed due to low network quality. The implications of that cost are clearly visible in the JavaScript code. The whole frontend ecosystem was built with asynchronism in mind.

  • Need for a clear contract between the frontend and the backend

Communication comes at a cost but should have clear boundaries, too. Data flow between the frontend and the backend is like dialogue. And what’s the necessary condition of a successful conversation? Mutual understanding. Interlocutors need to speak the same language. To make it possible, they need to state the rules and undertake to follow them. Some kind of contract needs to be established. In IT, this is usually called an API (Application Programming Interface). Documenting an API and keeping this documentation up-to-date is a cost.

There are solutions which enable API documentation to be generated directly from the code. That results in an always-up-to-date description of the contract, and eliminates the manual labour involved in developing and maintaining the documentation. One of them is GraphQL accompanied by GraphiQL. This mix delivers a dynamic, interactive and solid way of exploring API from the first day of project development. Actually, it is not possible to create a backend which uses GraphQL without documentation.

  • Initial load

As I wrote (in the “Schism” paragraph), Single Page Apps are responsible for drawing content in the user’s browser. This is generally a good thing, but also has a side effect. In order to render anything, client browser must load and interpret application code. This could take a while, especially for large apps. Until then, the user does not see any meaningful content beyond a kind request to wait paired with some loader (a white page in the worst case).

  • Availability for web crawlers

A longer initial load is a bad thing, but it can be even worse. Imagine that you have written some fancy blogpost or cooked a delicious meal and you want to let your friends know about the recipe. You have taken beautiful photos and written a decent description. Your content is available at http://fancy-spa.com/polish-dumplings, so you just pick an URL and share it on Facebook. And guess what happens? Facebook displayed no photos, no title and no description at all. On your wall, there is just a solitary link to your lovely dumplings, which looks broken nonetheless. No-one will click on it. You plunge into sorrow.

Why does it have to be like that? The Facebook robot visited the URL and got a blank page at the very first moment, just like you did. But it was not patient or smart enough to wait for the actual content to appear. It falsely assumed that the page was blank. Allowing web crawlers to correctly fetch data from your website is often a crucial factor in your business success. As we all live in the era of social networks, it would be foolish to not use that medium to our advantage. Shareable content helps your app to grow for free.

In Appchance, we overcame this constraint. When we were choosing the frontend framework, support for server pre-rendering was on the top of our priority list. We chose Ember.js, which has this feature practically built-in, thanks to the fantastic ember-fastboot addon. So we can have all the benefits listed above with minimized drawbacks.

Summary

Single-page applications have become a standard in the web industry. They offer an experience comparable to desktop or mobile apps, with all the advantages of traditional websites. They are the natural choice, when providing smooth and snappy interaction is essential. And you can be sure: your users will fall in love with your product. It is also worth noting that SPA is only one step away from PWA (Progressive Web Apps. Yeah I know, another 3-letter acronym, IT loves them), but that is a topic for another blogpost.

In spite of their undeniable superiority, adopting SPA should be a conscious decision, not a result of herd instinct. The additional complexity they introduce needs to be handled somehow.

I hope this blogpost has enabled you to thoroughly explore the world of modern web applications. A better understanding of the rules of that world could be beneficial for your next product. And maybe you already have some experience with SPA?

, , , , , , , , , , , ,

You might also like

  • Paweł Wąchalski

    Very nice article, easy to read and with colorful pictures.And very nice of me to point that out 🙂

    • Damian Romanów

      Thanks Paweł! I’m glad you like it 🙂

  • Adam Skołuda

    Really interesting article for people in IT (and not only) who don’t understand how the web works. I really appreciated paraphrase: “The programmer split up his app and saw everything that he had made, and, behold, it was very good.” I wish that every single developer and product owner could see that pros and cons of this kind of separation.
    As a nitpick, maybe only one thing I would. Nowadays on the web, the most frequent changes that we make is usually changing or even exchanging the whole frontend because it needs to be up to date according to the current UX/UI trends. The better frontend is, the more users you will have. So thanks to SPA approach it is much easier to make changes concerning UI, behavior or even write frontend app from scratch without any interference on backend side.
    I can’t wait for next article about PWA 🙂

    • Damian Romanów

      Thanks Adam, apparently the Bible is a decent source of inspiration 🙂 And excellent point! Possibility of taking an adaptive aproach to user needs or UX trends can be a decisive factor of online business success.

      PWA topic need a bit more exploration, but stay tuned 😀