My Perfect 2020 Stack

A new full stack, for a new generation

by Joe Honton

The journey from “full stack” to “2020 stack” has a few surprise winners and losers.

Remember when Web stacks were simple? When the layers could be scrunched into a four-letter acronym like LAMP or LEMP or LEPP? When all you needed was cheap commodity hardware, some open source software, and perseverance?

My first successful website, vintage 1999, was built with just a handful of layers: HTML4, CSS2, JavaScript3 and Apache 1.1, all running on a Linux 2.0 kernel. It had 38,000 pages, and after 20 years it's still pushing them out.

But we've all changed since then. And oh, how our stacks have risen!

My Perfect 2020 Stack

It's a new decade, and a new generation. So it's time for a new stack — a 2020 stack. *

What does a 2020 stack look like? Well, it's heavily influenced by what you're trying to do. Picking the right layers depends in large part on how much scalability you need.

My sweet spot is small websites. The ones that fit comfortably on a virtual server. The ones that don't need load balancers or stateful data stores. The CMS niche that's been occupied by WordPress for a long time. But not a Marie Kondo minimalist server. Rather, one that can handle sustained traffic without the need for peak-hour auto-provisioning.

My sweet spot now has twelve layers. From bottom to top I have:

At the base, Digital Ocean, a cloud provider that caters to the do-it-yourself crowd. I used to run my own servers, until the cost became prohibitive. Rack space leasing, dedicated IP address and bandwidth all added up to $$ per month. But the real killer was the cost of electricity. A $5 Digital Ocean droplet was far cheaper than the $1.25/day I was sending to my electricity provider. Multiplying those numbers out, I ended up saving hundreds of dollars per year.

Next, a Fedora Linux distribution with SELinux. Security is a big concern for all of us. SELinux is a wide safety net running in the kernel. Paired with a good iptables firewall configuration, there's no safer feeling. In case you doubt the need, consider this: spin up a new server on your favorite cloud provider, and watch how quickly it will be attacked by bad actors. I've seen new servers subjected to SSH brute force login attempts in under 10 minutes!

Next, my web server is Read Write Serve, with TLS certs from LetsEncrypt. I used to be a rock-star with Apache, configuring and launching new websites in just minutes. But since I've migrated from PHP to JavaScript, there's no path left for me there. Express seemed like a no-brainer, until I tried to mimic all the functionality Apache used to give me: content negotiation, conditional caching, compression, rewrites for SEO, CORS, and content security policies. I've switched to Read Write Serve which handles all of this by default.

Application logic on the server is handled with Node.js. The NPM ecosystem seems to have a package for everything, so assembling exactly what I need and plugging it into Read Write Serve is a straightforward task. Sending mail, interfacing with payment gateways, accessing databases, and all the other server-side APIs that I write, don't require heavy lifting.

My database server is MariaDB, the rebranded fork of MySQL adopted by the open source community. When I need to store unstructured JSON, I rely on PostgreSQL, because I can perform queries directly on specific JSON properties — it's a bit like MongoDB, but with the familiarity of SQL syntax.

For communication across the wire, I rely on HTTP/2 with persistent sessions and multiplexed streams. These two refinements to the venerable HTTP/1.1 protocol have changed the way I assemble my documents. First, the head-of-line blocking problem is gone, so there's no need for image sprites, even when I have dozens of tiny images. And second, there's no need to optimize my JavaScript and CSS files into bundles. Once a connection is established between the browser and server, all those little files zoom across the wire without interruption.

For HTML templating, I use Blue Phrase, which is a complete lossless expression of HTML, with shorthand notation. The days of unmatched opening and closing tags, and unreadable tag soup, are over for me. I tend to use just a few variables in each template (title, description, keywords, seo, splash, date, etc.), and sprinkle them into the template in a declarative language style.

When writing new web pages, I focus on what I'm trying to express, not on the decorations. For this I use Read Write Doc, which has a distraction-free writing experience. I use it even when my final target is a blog post to a Medium publication (which has an unrivaled online WYSIWYG editor). As a veteran of code editors, I feel more at home with a page of monospaced characters, and with my hands on the keyboard, not the mouse. Anyway, whenever I want to see my work in all its CSS glory, I can use a simple keystroke to alternate between preview and edit modes.

For web components, I follow the W3C standards using: shadow DOM, custom elements, HTML <template>, and ECMAScript modules. These allow me to completely encapsulate everything in packages that I distribute over NPM. The biggest advantage for me has been the isolation that shadow DOM provides. It gets rid of the namespace pollution that has been the bane of CSS.

Client side scripting is all modular object-oriented ECMAScript. I make use of the newest language features only as they become available in the latest browser releases. That is, I'll use it only when caniuse.com signals green across the board for each of the major browser's latest releases. I stay away from polyfills.

CSS is all about typography and layout, and typography starts with the right choice of font faces. I favor readability over all else. Nowadays I also make it a rule to host all of the font files I use on my own server so that I'm not blocked by third-party bandwidth limitations. For example, something like this: <link href='/fonts/source-serif-pro-400-latin.woff2' rel=preload as=font crossorigin />. The added benefit to doing it this way is that there's no worry about FOUT — the "flash of unstyled text".

Finally, for graphic arts, I find myself turning to GIMP for raster PNGs and InkScape for vector SVGs.

The losers

Some old favorites and short-lived flings are no longer part of my stack:

  • Photoshop & Illustrator. Two very fine apps that fulfilled my graphic arts needs for years. I say a fond farewell to these with reluctance. Their free and open-source replacements now meet all my needs.
  • jQuery. I haven't needed this since the cross-browser compatibility wars came to an end. The only real killer feature was its selector syntax, which was so useful that it was added to the DOM as querySelector back in 2009.
  • AJAX. The progenitor of Web 2.0 is now a relic of that age, with XMLHttpRequest being replaced by the modern, and much simpler fetch, and XML being supplanted by JSON.
  • SASS/SCSS. I'll admit that writing CSS without variables was not efficient, so SASS got off to a good start. And modules were an important effort too. But in the end it required too much mental power to be effectively put to use in JavaScript. CSS has come a long way since then, and code wranglers and manglers such as this are on their way out.
  • BEM naming. The Block Element Modifier approach to CSS classnames does solve the global namespace problem, but at the expense of being way too verbose. I've switched to parent/child selectors on semantic elements, eschewing identifiers and classnames for a lighter approach, like:
  • header > ul > li {
    ...
    }
    nav > ul > li {
    ...
    }
    footer > ul > li {
    ...
    }
  • Georgia & Verdana. These two topped my font-stacks for years. I could depend on them being available, and being readable. But once @font-face rules became available, and foundries began distributing open source typefaces, I began looking elsewhere.
  • Babel, Grunt, Gulp, Browserify, WebPack. The first four are no big surprise. But it is a bit surprising to say that WebPack has outlived its usefulness. Here's the back-story.
    1. Before HTTP/2 with persistent sessions and multiplexed streams, we depended on these tools to bundle our resources. But bundling gives us nothing in the new world of HTTP/2.
    2. As ECMAScript 2015 was cusping, we all rushed to use the new language features the minute they landed, but there was one problem. We couldn't deploy our code in the wild without transpiling it back into ECMAScript 5. We relied on Babel as a standard step in our build process. Today, all the new language features I need are available everywhere, so Babel is unnecessary.
    3. Before dynamic imports became available in the browser we needed to transpile our files back into CommonJS format. Most of the major browsers now support <script type='module'> (with Edge 76+ coming soon), so we can finally say hello to ECMAScript modules, and goodbye to all the rest.
  • JSX. Why anybody thought this was a good thing is beyond me. “But you get used to it,” was never a compelling argument.
  • Functional programming. I limit my functional programming to one liners, like numbers.sort((a, b) => a - b); For everything else I use object oriented programming.

The winners

The layers that have been real star performers for me are:

  • JavaScript modules. Modules in server-side Node.js are proven winners. And I'm delighted that I can finally begin using them on the client-side as well.
  • Object oriented JavaScript. Which can be summarized in five golden rules: 1) replace anonymous objects with named classes, 2) declare and initialize all properties in the constructor, 3) immediately seal all objects, 4) define methods with invariant signatures, 5) bind this to every callback.
  • Blue Phrase. For templating, authoring, and declarative programming. I rely on this to produce HTML that's easy on the eyes and a pleasure to write.

It's a new generation, and the four layered stack of decades past is now a twelve-layered stack. At the risk of sounding cliché, I'll part by stating the obvious: “Your stack may vary”. I'll be curious to see what others come up with as their perfect 2020 stack.


* “It's a new decade.” Of course if you're a purist and you believe the new decade won't begin until January 1st 2021, you can save this article and read it next year. But you'll miss out on a perfect year of fun.

My Perfect 2020 Stack — A new full stack, for a new generation

🔎