Why shouldn't we use $backendLanguageName to manage a Web Application UI state

Tags

While exchanging with other programmers from all horizons I often had backend developers eventually wanting to make things better by (taking back) controlling all aspects on the server side and leave the FrontEnd developers to "make it prettier".

It happened a few times already, sometimes at a conference, other times at a new company I’ve just joined. This conversation happened often enough that I had been collecting an argumentary in my personal wiki about it.

The rationale to have a solid foundation in programming and serious tooling for all possible business cases an application would have to handle is a reasonable assumption. Since the backend team will have to support the features, why not try finding a way to only let FrontEnd developers "make things prettier".

But making a business decision only with that as a reason, hire extensively and "bet" only on that strategy might be costly.

Because this —returning HTML over HTTP— isn’t the first time that question happened. (If you want one more proof, have a look at this page on MDN)

Context

Ideally, a web application should be loading fast, respond quickly to interactions, and display things consistently. This definition should fit any well-behaving and consistent UI.

Consistency is key, when we're on an building's elevator, when we push a floor number, we expect to have the number light up. It's a behavior we’re used to. The feedback is immediate, and is consistent.

In a Web Browser, an equivalent feedback would be done by adding a styling class name.

We would either change URL in the address bar, and have the button be aligned at the same place and look different.

Before we had modern FrontEnd technologies, clicking a link would involve "navigating" to another address, throwing everything that was already loaded, and have a server completely regenerate HTML.

Back around 2004 with Google Maps, Google shown that it was possible to use the web browser without that flow. The idea of changing things without reloading was colloquiallly referred to as AJAX (Asynchronous JavaScript And XML). Nowadays we have actual asycnronous code and coroutines, but the Asynchronous was referring to the fact that the page was loaded, and we want to load more data without throwing everything.

Making web applications is a craft that many others extensively documented. If you look at other successful web application maintainers and what they've documented in the last decades, you’ll also see that they did also use a server-side programming language to regenerate HTML.

You’ll also see attempts to make an hybrid of the two. Server-Side, then JavaScript sugar.

And because we want to make things efficient, and have a manageable code base surface to maintain, eventually some thought: how about writing JavaScript, and use the same code client and server-side.

Learn from experience of others

In order to make an informed choice, I wanted to take a few well made web applications and see what they’ve learned. There’s many articles and talks about that subject.

I’ve limited to companies who has a good reputation for their well-made web applications.

  • Google
  • Facebook
  • Netflix
  • Mozilla
  • Yahoo! (from back in 2005)

Yahoo! from back in 2005 was among the most visible (from my own recollection).

What do they have in common is that they all heavily relied on a backend stack such as Ruby on Rails, Java or PHP.

JavaScript always had been the way of updating elements in the web browser, they were all making the backend language to conditionally return JavaScript based on backend logic.

Sometimes the logic was written at least twice. One in the server-side stack, and partially validated in JavaScript.

And they’re relying more and more on letting the UI interactions to be client side.

Quality

  • Error messages are meaningful, in your preferred language

  • Labels, content, calendar and numeric notation are all in your preferred language

  • Everything is aligned and consistent

  • Validation rules are enforced consistently from both client and backend

  • Have their UI in many human languages (or "locale", e.g. Canadian French), measuring system, Date formats, Number formats, etc.

Sharing their experience

Maintainability

To make things maintainable, we might want to be able to see the same vocabulary between the layers of the stack.

Before, writing JavaScript involved writing logic mingled with different ways to either detect a feature or in a syntax that was supported. The code we were writing was closely tied to the platform it would run on, and we would have to manually detect if a feature was available or not.

When we were doing, we would also need to copy paste logic around in different module loader systems so we could re-use between Node.js server-side, and Microsoft Internet Explorer, and Google Chrome.

It was tedious, and confusing.

Over the years, the language evolved at a more regular pace (Thanks ECMA TC-39), and more and more tooling has been published so we have more than a set of compromises The Good Parts

Since 2015, ECMA released ES6 (a.k.a. ECMASCript 2015), and in 2020 Node.js 14 shipped with native ESM modules support so we can write and load our code exactly the same way on both modern web browsers and Node.js.

Most of the progress made towards achieving maintainability are possible because of tools like Jest, AVA, builders like esbuild, Rollup and Babel, and WebPack to allow us to split code for different runtime targets (e.g. Client-Side, Server-Side, for a specific browser, etc.)

With all this progress on the platform side, we have all the prerequisite to make building a business application maintainable by:

  • Maintaining the least amount of code (i.e. most of the code is our app business logic, and less boilerplate)

  • Avoiding to having to write same logic more than once between stacks

  • Avoiding to having to looping and stitching long strings of hopefully valid HTML, with many switch-case or if conditional blocks

  • Systematically load code when needed, instead of everything at first load

  • Allowing to use the same business logic, on tablet, phones, desktop app (Electron).

  • Maintaining less markup and styling and truly achieve Responsive AND Adaptative UI

Can it ever be a good idea?

Writing Server-Side ONLY code (i.e. Java/PHP/Erlang/Scala/Python/Go/Rust/Ruby) to manage HTML UI is not a bad idea in itself.

If you can have a service over HTTP that returns self-contained HTML markup, that can be made compatible to be loaded onto a host page with conventions for CSS and JavaScript.

Injecting such partial could then take the style of the host page, and respond to events as soon as it’s injected.

The idea isn’t new, it's been done many times.

Before we wouldn’t deal with JavaScript, only HTML patterns where the classNames and other HTML attributes would be as expected by the host JavaScript code.

A modern twist is called Micro-Frontends that pushed the boundary further.

Open-Source UI specialized projects

Unrelated to JavaScript

  • HHVM (Facebook, back around 2011) Rewrite of PHP, called Hip-Hop VM

    • Hack: Extended PHP Language for Strict typing as part of HHVM parsing engine
    • XHP: Extended PHP Language for supporting XML notation within language (i.e. NOT as strings) for data model validation, and reduce cross-site attack vectors (better input filtering, harder to pass JavaScript code through unintended places)

Another syntax, into JavaScript

  • CoffeeScript

  • ReasonML

  • Clojure LISP syntax, running inside a Java VM, receive server-rendered HTML

  • Elixir

  • Flow (Facbook) where we add comments in JavaScript files, and declare typings, and provides tooling to validate code based on hints. We have to adjust the parser to make *.js files to support otherwise syntax.

    • React is written using Flow, so was Vue.js v2 before its v3 rewrite in TypeScript
  • TypeScript (Microsoft) A Superset of ECMAScript. Write code in *.ts files, modern ECMAScript plus notations for typings. The typings notations are similar to Flow’s, but at least they’re in files with their own extension.

Another language, manage server-side and JavaScript client-side

JavaScript

Generating UI in JavaScript only had been done in the past too

While looking those projects, and others you might find on the web, you will notice is that most of those projects are less and less popular, and the companies sponsoring them now would talk about frameworks such as Vue.js, Svelte, React with their new Fiber internals, or Angular with Ivy.

As it’s been observed in 2019 after a few years into the evolution of React, Angular.js being deprecated by Angular to full usage of TypeScript, RxJS, NgRX, etc. we see less and less non ECMAScript/JavaScript frameworks.

Nowadays

Nowdays, with the craze of 'micro-services', most companies typically consumes their APIs in some format and handles their UI in JavaScript

Requirements

Technical requirements

  • Describe UI components (a list of inputs, with how to validate, and what data to use)
  • Describe what View to show for a given UI (User-Agent) Router
  • Describe how to get data and how to walk through it to get a result
  • Ability progressively roll-out code feature based on what's configured for a given deployment (or client), and what's currently available

Quality indicators

  • Has unit-tests and a community for all layers: UI Components, Data Abstraction Layer, Data Access Layer, etc.
  • Is actively maintained
  • Has documentation and tutorials available that covers our usage-scenarios
  • We can write isomorphic code (i.e. write code once, and can be run with same result from both Client and Server-Side)
  • We can toggle off expensive parts of application and the UI follows

Objectives

  • Maintaining a Web Application with Domain Specific data, we're not an Open Source project maintenance team (i.e. use what's there, not write our own.)
  • Write a piece of logic once, favorize code re-use
  • Write piece of code with testing in isolation easily accessible beside the code
  • We can consistently render UI, without too much boilerplate code and LEAST possible vectors where to do the same thing differently

Isomorphism?

How do you tell if what's picked actually is "isomorphic".

  • Nuxt.js (and React’s Next.js) allows telling in an accessible way what UI to show for an URL, and that if we do a "full page reload", the HTML sent to the Web Browser is fully rendered, yet if we change page, only what's changed gets updated
  • Axios (or another HTTP Client) allows us to tell GET /foo/bar and regardless of where the code is run (Client or Server-Side), configuration variations will already be taken into account
  • Koa supports modern JavaScript as run time (including asynchronous code), its newer code-base simplify importing our "modern code" -- less boilerplate and tweaks and will look the same as how we'll use in Nuxt/Vue code

But Why can't we use a Backend to Generate UI?

Because, in the end, once we’ve received the initial HTML payload, any actions will be needed to be made visible in the UI.

Those changes to be visible will inevitably be written using JavaScript.

Solving the problem of affecting UI in a Web Browser is still a very active subject, and there are many ideologies.

A trend seem to be clear, having a backend language write HTML strings and whisfully stick jQuery scripts together is no longer viable.

It is now frowned upon, because it makes it hard to maintain.

If you re-consider, modern JavaScript with React,Vue.js,Angular,Svelte is an iteration after what’s been known as (in no particular order):

  • Progressive Enhancement and/or Graceful Degradation
  • Object-Oriented CSS
  • Mobile Design
  • Responsive Design
  • Reactive Programming
  • Progressive Web Applications

Continuing on what's been elaborated earlier in this document;

We can.

After-all, an HTML form, when we click "submit" button, WILL ALWAYS work.

Showing images, link, and so on are natively supported since the beginning of the Web.

There is a thing we call "JavaScript fatigue" ([2])

But nowadays, the argumentary is typically about how it becomes quickly cluttered.

Which is very different than back in 2015 (before ECMAScript 5), when JavaScript ecosystem was too brittle.