Step 1: How I chose React

I'm working for a company that has a lot of legacy code, where "legacy" means "nothing on the client newer than AngularJS". Recently, I essentially volunteered to figure out how to stop building more technical debt by proposing a "modern" JavaScript templating engine (and associated tools) to use going forward for new feature work.

But since there's very little pure greenfield work for us in the near future -- and plenty of new features on the backlog -- my solution needed to be able to operate in a lot of different environments without causing ramp-up headaches for each new team of developers. Finding a solution to that is the real challenge I'm going to describe here.

I should note that, even in a working museum of obsolete code, the idea isn't and shouldn't be to toss the legacy code and start over, no matter how tempting that might feel. As Spolsky said years ago...

The sheer volume of bugs [in Netscape 6 on release], it seems, proves that rewriting code from scratch does not make for a better code base, it makes it worse. Old code doesnโ€™t rust, it gets better, as bugs are fixed.

Lou Montulli ['one of the 5 programming superstars who did the original version of Navigator' -Spolsky] again: โ€œI laughed heartily as I got questions from one of my former employees about FTP code the he was rewriting. It had taken 3 years of tuning to get code that could read the 60 different types of FTP servers, those 5000 lines of code may have looked ugly, but at least they worked.โ€ [emphasis mine -mfn]

In brief, you want to keep as much as your legacy code running as is realistically possible, refactoring it as your resources and priorities allow.

I've split my response into two posts.

  1. The sort of research and thinking that went into picking a solution.
  2. Code examples where I'm exhibiting the solution I've selected Is Not Wrong ยฉ 1842.

What follows is part 1...


Researching a solution

There seem to be three clear candidates for a modern browser-based templating solution/stack:

  1. Angular.io
  2. React
  3. Vue

I mean, there are other super-cool options (where "cool" means "better" given the right developers on your team), like Svelte, but I'm trying to stay super-conservative here to match our culture and existing devs. Remember, this is a system that's largely AngularJS (that's Angular 1.x for those not in the know) but it may include even more lines of code in ASP.NET than AngularJS!

That is, at start, my newest existing code is AngularJS. The rest is all *.aspx, jQuery, even some knockoutjs. There are devs currently adding new features with ASP.NET for whom AngularJS remains the "new" stack they haven't learned yet.

So that pushed me to measure templating systems on these three registers:

  1. Popularity
    • Can I find devs easily?
    • Can devs find docs, videos, and support easily?
  2. Ease of dev onboarding/training
  3. Our use case/requirements
    • Need to bolt-on to AngularJS, jQuery, and vanilla JavaScript powered font-end code
    • Does not require a build system
      • Unfortunately, webpack, babel, snowpack, etc are foreign ideas.
        • No, really, I know you use them and they're table stakes
        • Doesn't mean they aren't heavy lifts for people trapped in the past!!!
      • I didn't want to complicate the legacy build process, as getting build updates implemented could add months to roll-out (so more tech debt generating stories in old stacks)
      • Again, the number of different outdated stacks means the simplest integration is best.

Why not use React?

Admittedly, I was pretty sure I had 1 & 2 (Popularity and Ease of dev onboarding) answered going in.

In my experience, React seems to be both the most popular framework (both in what's known and what devs want to know) and the technology developers get up to speed on quickest. Our recent job applicants' skills also seem to bear out this preference for React.

Out of hundreds of resumes (where React was most common), we had 15-20ish interviews that, aside from one 100% Vue expert, gave us exactly zero applicants who were lacking React completely.

Further, I've used both Angular.io (6+) on a $30 mil/yr revenue project with four dev teams and React on a healthcare practice management project that was a little smaller, for about 18 months in each. Developers do better, in my experience, ramping up and developing quality code with React than Angular 2+.

Those two together made me think that rather than looking for the best fit from the available templating systems, my job could be more to the point: Are there any reasons React shouldn't be our new templating system?

(TL;DR: The quick answer is no.)


Jerry, SHOW ME THE NUMBERS!!!1!

But, like the scouts they kicked out of Oakland in Moneyball, managers don't want to make decisions based on wizened, experienced devs' feels; they want numbers so they can't get fired if things go sideways.

For React, at least, we've got 'em.

From statista.com:

Most popular web frameworks among developers worldwide 2021

Published by Feb 23, 2022

React.js overtook jQuery to become the most used web framework among software developers worldwide, as of 2021. According to the survey, 40.14 percent of respondents reported to be using React.js, while 34.43 percent were using jQuery.

From stackoverflow.com (these are amazingly close to Statista's without being exact matches):

This year, React.js surpassed jQuery as the most commonly used web framework.

Also from stackoverflow.com (and notice that Svelte pokes its head out again):

Newcomer Svelte takes the top spot as the most loved framework. React is the most wanted, desired by one in four developers [emph mine, both times -mfn].

66,202 responses

% of developers who are not developing with the language or technology but have expressed interest in developing with it

React.js 25.12%
Vue.js 16.69%
Django 9.21%
Angular 8.47%
Svelte 6.57%
Flask 5.89%
Express 5.84%
Angular.js 5.8%
ASP.NET Core 5.2%
FastAPI 4.13%
Spring 3.89%
jQuery 3.67%
Ruby on Rails 3.28%
Gatsby 2.74%
Laravel 2.67%
ASP.NET 2.39%

Vue and the Problem of the Progressive Framework

This brings me to #3: A framework that matches our current use case.

I've liked Vue for years because it's a "progressive" framework -- which should not be confused with the "progressive" in "Progressive Web App" (PWA).

For Vue, progressive means:

[Your app is] designed from the ground up to be incrementally adoptable.

And Vue does deliver. I've created transpilation-free Vue projects in the past, and I wanted to preserve that option for us here. You can sprinkle Vue almost anywhere in your existing app if you need to.

This would allow us to start using a modern framework anywhere in the app without the barrier to entry of normal build requirements. I wanted us to be able to insert our new client stack into any new UI work, even if it was an addition to legacy code in AngularJS or knockout.

I didn't want to preclude using conventional builds [for new projects], but I didn't want builds to be a technical blocker during a design phase so that we ended up with more new code in twenty year-old stacks. Instead, I wanted new code to be able to be "eaten" by a modern project with minimal porting.

That is, if we have five new features and only one is greenfield, I don't want to have to set up four slightly different builds before I can get modern stacks into those four. Nor do I want to maintain those two-staged builds as legacy and modern requirements fight going forward.

This was the number one reason I originally wanted to use Vue over React. Vue has some other debatable advantages; I'd say Vue is "as good as" React in most ways. But it was this conscious decision to be progressive that stood out as a clear Vue advantage.

Opposed to Vue, doing React "by hand" was a pain in the rear. I mean, you can code React by hand, making no changes before releasing to browsers...

The render method returns a description of what you want to see on the screen. React takes the description and displays the result. In particular, render returns a React element, which is a lightweight description of what to render. Most React developers use a special syntax called โ€œJSXโ€ which makes these structures easier to write. The <div /> syntax is transformed at build time to React.createElement('div'). The example above is equivalent to:

React.createElement("div", {className: "shopping-list"}, 
    React.createElement("h1", null, "Shopping List for ", props.name), 
    React.createElement("ul", null, 
        React.createElement("li", null, "Instagram"), 
        React.createElement("li", null, "WhatsApp"),
        React.createElement("li", null, "Oculus")
    )
);

Source of full code for that example over here.

... but this is not a sustainable way to write apps, and quickly loses React's component framework advantages.

Though, spoiler, you're right. The real hang up isn't React (though it is sizeable at 133 kB), it's JSX. More on that in just a second.


Preact

When we were looking at using FullCalendar to add calendars to our app for a feature slated to be done before we adopted a modern stack, I read about Preact.

From the Fullcalendar.io blog:

We've been leveraging a framework called Preact. It's a nearly-API-compatible implementation of React that's only 3k. It sounds too good to be true, but I promise you, it's real. It's meant to be fast, small, and embedded into other products. The powerful abstractions it provides are simplifying our code to more than compensate for the 3k dependency bump. We'll likely break even in filesize.

What's more, Preact, when paired with a special template literal processor type called htm, allows for what Preact bills as its no build tools route:

Preact is packaged to be used directly in the browser, and doesn't require any build or tools:

<script type="module">
  import { h, Component, render } from 'https://unpkg.com/preact?module';
  // Create your app
  const app = h('h1', null, 'Hello World!');
  render(app, document.body);
</script>
...

Writing raw h or createElement calls can be tedious. JSX has the advantage of looking similar to HTML, which makes it easier to understand for many developers in our experience. JSX requires a build step though, so we highly recommend an alternative called HTM.

HTM is a JSX-like syntax that works in standard JavaScript. Instead of requiring a build step, it uses JavaScript's own Tagged Templates syntax, which was added in 2015 and is supported in all modern browsers. This is an increasingly popular way to write Preact apps, since there are fewer moving parts to understand than a traditional front-end build tooling setup.

<script type="module">
  import { h, Component, render } from 'https://unpkg.com/preact?module';
  import htm from 'https://unpkg.com/htm?module';

  // Initialize htm with Preact
  const html = htm.bind(h);

  function App (props) {
    return html`<h1>Hello ${props.name}!</h1>`;
  }

  render(html`<${App} name="World" />`, document.body);
</script>

[emph mine -mfn]

Transpilation-free Preact via HTM sounds exactly like the missing piece that makes React (well, the "React family") a progressive framwework in the same sense that Vue uses the term. We can literally embed this version of Preact anywhere without requiring a build to transpile to JavaScript a browser can easily digest.


What's next?

This was enough for me to think pitching "the React family" via Preact was the best plan. Before doing so, though, I wanted to play around with injected Preact components inside of an AngularJS project.

That code is what we'll look at in Part 2 [which has not yet been published].

Labels: , , , , ,