691 lines
36 KiB
Plaintext
691 lines
36 KiB
Plaintext
[1]Ben Hoyt
|
||
|
||
• [2]Home
|
||
• [3]Resume/CV
|
||
• [4]Projects
|
||
• [5]Tech Writing
|
||
• [6]Non-Tech
|
||
• [7]Email
|
||
|
||
• [8]benhoyt.com
|
||
• [9]benhoyt@gmail.com
|
||
|
||
The small web is beautiful
|
||
|
||
March 2021
|
||
|
||
Summary: I believe that small websites are compelling aesthetically, but
|
||
are also important to help us resist selling our souls to large tech
|
||
companies. In this essay I present a vision for the “small web” as well as
|
||
the small software and architectures that power it. Also, a bonus rant
|
||
about microservices.
|
||
|
||
Go to: [10]Software | [11]Web | [12]Server-side | [13]Static sites | [14]
|
||
Dependencies | [15]Analytics | [16]Microservices
|
||
|
||
About fifteen years ago, I read E. F. Schumacher’s Small is Beautiful and,
|
||
despite not being interested in economics, I was moved by its message. Perhaps
|
||
even more, I loved the terse poetry of the book’s title – it resonated with my
|
||
frugal upbringing and my own aesthetic.
|
||
|
||
I think it’s time for a version of that book about technology, with a chapter
|
||
on web development: The Small Web is Beautiful: A Study of Web Development as
|
||
if People Mattered. Until someone writes that, this essay will have to do.
|
||
|
||
There are two aspects of this: first, small teams and companies. I’m not going
|
||
to talk much about that here, but [17]Basecamp and many others have. What I’m
|
||
going to focus on in this essay is small websites and architectures.
|
||
|
||
I’m not the first to talk about the “small web”, but, somewhat surprisingly,
|
||
only a few people have discussed it using that term. Here are the main web
|
||
pages I can find that do:
|
||
|
||
• [18]Rediscovering the Small Web by Parimal Satyal: a fabulous article about
|
||
the joy of small, independent (and sometimes retro) websites in contrast to
|
||
the “commercial web”.
|
||
• [19]What is the Small Web?, by Aral Balkan of the Small Technology
|
||
Foundation: more of a manifesto against the surveillance of Big Tech than
|
||
something concrete, but still interesting.
|
||
|
||
Why aim small in this era of fast computers with plenty of RAM? A number of
|
||
reasons, but the ones that are most important to me are:
|
||
|
||
• Fewer moving parts. It’s easier to create more robust systems and to fix
|
||
things when they do go wrong.
|
||
• Small software is faster. Fewer bits to download and clog your computer’s
|
||
memory.
|
||
• Reduced power consumption. This is important on a “save the planet” scale,
|
||
but also on the very local scale of increasing the battery life of your
|
||
phone and laptop.
|
||
• The light, frugal aesthetic. That’s personal, I know, but as you’ll see,
|
||
I’m not alone.
|
||
|
||
So let’s dive in. I want to cover a bunch of different angles, each with its
|
||
own subheading.
|
||
|
||
Small software
|
||
|
||
If we’re going to talk about a small web, we need to start with small software.
|
||
|
||
As a teen, I learned to program using x86 assembly and [20]Forth – perhaps odd
|
||
choices, but my dad was heavily into Forth, and I loved how the language was so
|
||
simple I could write [21]my own bootstrapped compiler.
|
||
|
||
In terms of career, I started as an embedded programmer – not as in “embedded
|
||
Linux” but as in microcontrollers where 16KB of RAM was generous. My current
|
||
laptop has 16GB of RAM, and that’s not a lot by today’s standards. We were
|
||
building IP-networked products with one millionth the amount of RAM. Those
|
||
kinds of micros are as cheap as chips (ahem), and still widely used for small
|
||
electronic devices, sensors, internet-of-things products, and so on.
|
||
|
||
You have to think about every byte, compile with size optimizations enabled,
|
||
and reuse buffers. It’s a very different thing from modern web development,
|
||
where a JavaScript app compiles “down” to a 1MB bundle, or a single Python
|
||
object header is 16 bytes before you’ve even got any data, or a Go hello-world
|
||
binary is 2MB even before you’ve added any real code.
|
||
|
||
How do you create small programs? I think the main thing is that you have to
|
||
care about size, and most of us don’t think we have time for that. Apart from
|
||
embedded development, there’s an entire programming subculture called the [22]
|
||
demoscene that cares about this. They have competitions for the smallest 4KB
|
||
demos: who can pack the most graphical punch into 4096 bytes of executable.
|
||
That’s smaller than many favicons! ([23]Elevated and [24]cdak are two of the
|
||
highest-rated 4K demos.) Many demosceners go on to become game developers.
|
||
|
||
It’s not just about executable size … when you’re developing your next command
|
||
line tool, if you use Go or Rust or even C, your program will be much faster,
|
||
smaller, and use less memory than a Python or Java equivalent. And easier to
|
||
install. If you don’t understand why, please do learn. (It’s out of scope for
|
||
this essay, but to summarize: Go, Rust, and C compile to ready-to-execute
|
||
machine code, don’t carry around a virtual machine, and don’t have memory
|
||
overhead for objects like integers.)
|
||
|
||
But why not apply some of the same principles to web development? In the web
|
||
world, I think the main trick is to be careful what dependencies you include,
|
||
and also what dependencies they pull in. In short, know node_modules – or maybe
|
||
better, no node_modules. More about this [25]below.
|
||
|
||
Niklaus Wirth of Pascal fame wrote a famous paper in 1995 called [26]A Plea for
|
||
Lean Software [PDF]. His take is that “a primary cause for the complexity is
|
||
that software vendors uncritically adopt almost any feature that users want”,
|
||
and “when a system’s power is measured by the number of its features, quantity
|
||
becomes more important than quality”. He goes on to describe Oberon, a computer
|
||
language (which reminds me of Go in several ways) and an operating system that
|
||
he believes helps solve the complexity problem. Definitely wirth a read!
|
||
|
||
I’ve been mulling over this for a number of years – back in 2008 I wrote a
|
||
sarcastic dig at how bloated Adobe Reader had become: [27]Thank you, Adobe
|
||
Reader 9! It was a 33MB download and required 220MB of hard drive space even in
|
||
2008 (it’s now a 150MB download, and I don’t know how much hard drive space it
|
||
requires, because I don’t install it these days).
|
||
|
||
But instead of just complaining, how do we actually solve this problem?
|
||
Concretely, I think we need to start doing the following:
|
||
|
||
• Care about size: this sounds obvious, but things only change when people
|
||
think they’re important.
|
||
• Measure: both your executable’s size, and your program’s memory usage. You
|
||
may want to measure over time, and make it a blocking issue if the
|
||
measurements grow more than x% in a release. Or you could hold a
|
||
memory-reduction sprint every so often.
|
||
• Language: choose a backend language that has a chance, for example Rust, C
|
||
or C++, or for servers, Go. These languages aren’t right for everything
|
||
(like data transformation scripts), but they produce small executables, and
|
||
they’re good for CLIs and desktop apps.
|
||
• Remove: cut down your feature set. Aim for a small number of high-quality
|
||
features. My car can’t fly or float, and that’s okay – it drives well.
|
||
• Say no to new features: unless they really fit your philosophy, or add more
|
||
than they cost over the lifetime of your project.
|
||
• Dependencies: understand the size and complexity of each dependency you
|
||
pull in. Use only built-in libraries if you can.
|
||
|
||
Small websites
|
||
|
||
I’m glad there’s a growing number of people interested in small websites.
|
||
|
||
A few months ago there was a sequence of posts to Hacker News about various
|
||
“clubs” you could post your small website on: the [28]1MB Club ([29]comments),
|
||
[30]512KB Club ([31]comments), [32]250KB Club ([33]comments), and even the [34]
|
||
10KB Club ([35]comments). I think those are a fun indicator of renewed
|
||
interested in minimalism, but I will say that raw size isn’t enough – a 2KB
|
||
site with no real content isn’t much good, and a page with 512KB of very slow
|
||
JavaScript is worse than a snappy site with 4MB of well-chosen images.
|
||
|
||
Some of my favourite small websites are:
|
||
|
||
[36]Hacker News: I personally like the minimalist, almost brutalist design, but
|
||
I love its lightness even more. I just downloaded the home page, and loading
|
||
all resources transfers only 21KB (61KB uncompressed). Even pages with huge
|
||
comment threads only transfer about 100KB of compressed data, and load quickly.
|
||
Reddit has become such a bloated mess in comparison. Hacker News, never change!
|
||
|
||
[37]Lobsters: a similar news-and-voting site, with slightly more “modern”
|
||
styling. It uses some JavaScript and profile icons, but it’s still clean and
|
||
fast, and the total transfer size for the homepage is only 102KB. You just
|
||
don’t need megabytes to make a good website.
|
||
|
||
[38]Sourcehut: I like the concept behind Drew DeVault’s business, but I love
|
||
how small and anti-fluff the website is. He has set up a mini-site called the
|
||
[39]Software Forge Performance Index that tracks size and browser performance
|
||
of the prominent source code websites – Sourcehut is far and away the lightest
|
||
and fastest. Even his homepage is only 81KB, including several screenshot
|
||
thumbnails.
|
||
|
||
[40]SQLite: not only is SQLite a small, powerful SQL database engine, the
|
||
website is fantastically small and content-rich. Even their 7000-word [41]page
|
||
about testing is only 70KB. How do they do this? It’s not magic: focus on
|
||
high-quality textual content, minimal CSS, no JavaScript, and very few images
|
||
(a small logo and some SVGs).
|
||
|
||
[42]LWN: I’m a little biased, because I’ve written [43]articles for them, but
|
||
they’re an excellent website for Linux and programming news. Extremely
|
||
high-quality technical content (and a high bar for authors). They’re definitely
|
||
niche, and have a “we focus on quality content, not updating our CSS every
|
||
year” kind of look – they’ve been putting out great content for 23 years! Their
|
||
homepage only downloads 44KB (90KB uncompressed).
|
||
|
||
[44]Dan Luu’s blog: this is one of the more hardcore examples. His inline CSS
|
||
is only about 200 bytes (the pages are basically unstyled), and his HTML source
|
||
code doesn’t use any linefeed characters. Kind of a fun point, although then he
|
||
goes on to load 20KB of Google Analytics JavaScript…
|
||
|
||
As a friend pointed out, those websites have something of an “anti-aesthetic
|
||
aesthetic”. I confess to not minding that at all, but on the other hand, small
|
||
doesn’t have to mean ugly. More and more personal blogs and websites have
|
||
adopted a small web approach but are more typographically appealing:
|
||
|
||
• [45]Armin Ronacher’s Thoughts and Writings
|
||
• [46]Chris Wellons’ “Null program” blog
|
||
• [47]Eric Radman’s BSD and SQL blog
|
||
• [48]Hugo Tunius’ programming blog
|
||
• [49]James Hague’s “Programming in the Twenty-First Century”
|
||
• [50]Julia Evans’ programming blog
|
||
|
||
There are many, many more. Programmer Sijmen Mulder created a nice list of [51]
|
||
text-only websites – not quite the same thing as small, but it definitely
|
||
overlaps!
|
||
|
||
However, it’s not just about raw size, but about an “ethos of small”. It’s
|
||
caring about the users of your site: that your pages download fast, are easy to
|
||
read, have interesting content, and don’t load scads of JavaScript for Google
|
||
or Facebook’s trackers. Building a website from scratch is not everyone’s cup
|
||
of tea, but for those of us who do it, maybe we can promote templates and tools
|
||
that produce small sites that encourage quality over quantity.
|
||
|
||
For this website, I lovingly crafted each byte of HTML and CSS by hand, like a
|
||
hipster creating a craft beer. Seriously though, if your focus is good content,
|
||
it’s not hard to create a simple template from scratch with just a few lines of
|
||
HTML and CSS. It will be small and fast, and it’ll be yours.
|
||
|
||
Loading this essay transfers about 23KB (56KB uncompressed), including the
|
||
favicon and analytics script. It’s small, fast, and readable on desktop or
|
||
mobile. I don’t think it’s too bad looking, but I’m primarily aiming for a
|
||
minimalist design focussed on the content.
|
||
|
||
In addition to making sure your HTML and CSS are small, be sure to compress
|
||
your images properly. Two basic things here: don’t upload ultra-high resolution
|
||
images straight from your camera, and use a reasonable amount of JPEG
|
||
compression for photos (and PNG for screenshots or vector art). Even for large
|
||
images, you can usually use 75% or 80% compression and still have an image
|
||
without JPEG noise. For example, the large 1920x775 image on the top of my [52]
|
||
side business’s homepage is only 300KB.
|
||
|
||
Speaking of hero images, you don’t need big irrelevant images at the top of
|
||
your blog posts. They just add hundreds of kilobytes (even megabytes) to your
|
||
page weight, and don’t provide value. And please don’t scatter your article
|
||
with animated GIFs: if there’s something animated on the screen, I can hardly
|
||
concentrate enough to read the text – and I’m [53]not the [54]only one. Include
|
||
relevant, non-stock images that provide value equal to their weight in bytes.
|
||
Bare text is okay, too, like a magazine article.
|
||
|
||
[55]IndieWeb.org is a great resource here, though they use the term “indie”
|
||
rather than “small”. This movement looks more organic than the [56]Small
|
||
Technology Foundation (which has even been [57]critiqued as “digital
|
||
green-washing”), and their wiki has a lot more real content. IndieWeb also
|
||
promotes local [58]Homebrew Website Clubs and [59]IndieWebCamp meetups.
|
||
|
||
Emphasize server-side, not JavaScript
|
||
|
||
JavaScript is a mixed blessing for the web, and more often than not a bane for
|
||
small websites: it adds to the download size and time, it can be a performance
|
||
killer, it’s bad for accessibility, and if you don’t hold it right, it’s [60]
|
||
bad for search engines. Plus, if your website is content-heavy, it probably
|
||
isn’t adding much.
|
||
|
||
Don’t get me wrong: JavaScript is sometimes unavoidable, and is great where
|
||
it’s great. If you’re developing a browser-based application like Gmail or
|
||
Google Maps, you should almost certainly be using JavaScript. But for your next
|
||
blog, brochure website, or project documentation site, please consider plain
|
||
HTML and CSS.
|
||
|
||
If your site – like a lot of sites – is somewhere in between and contains some
|
||
light interaction, consider using JavaScript only for the parts of the page
|
||
that need it. There’s no need to overhaul your whole site using React and Redux
|
||
just to add a form. Letting your server generate HTML is still an effective way
|
||
to create fast websites.
|
||
|
||
[61]Stack Overflow is a case in point. From day one, they’ve made [62]
|
||
performance a feature by rendering their pages on the server, and by measuring
|
||
and reducing render time. I’m sure the Stack Overflow code has changed quite a
|
||
lot since the Jeff Atwood days – it now makes a ton of extra requests for
|
||
advertising purposes – but the content still loads fast.
|
||
|
||
[63]Hacker News (there’s that site again) is a server-side classic. With only
|
||
[64]one tiny JavaScript file for voting, the HTML generated on the server does
|
||
the rest. And [65]apparently it still runs on a single machine.
|
||
|
||
Around fifteen years ago there was this great idea called [66]progressive
|
||
enhancement. The idea was to serve usable HTML content to everyone, but users
|
||
with JavaScript enabled or fast internet connections would get an enhanced
|
||
version with a more streamlined user interface. In fact, Hacker News itself
|
||
uses progressive enhancement: even in 2021, you can still turn off JavaScript
|
||
and use the voting buttons. It’s a bit clunkier because voting now requires a
|
||
page reload, but it works fine.
|
||
|
||
Is progressive enhancement still relevant in 2021? Arguably not, though some
|
||
die-hards still turn JavaScript off, or at least enable it only for sites they
|
||
trust. However, I think it’s the mentality that’s most important: it shows the
|
||
developer cares about performance, size, and alternative users. If Hacker News
|
||
voting didn’t work without JavaScript, I don’t think that would be a big
|
||
problem – but it shows a certain kind of nerdish care that it does work. Plus,
|
||
the JavaScript they do have is only 2KB (5KB uncompressed).
|
||
|
||
Compare that to the 8MB (14MB uncompressed) that the [67]Reddit homepage loads.
|
||
And this across 201 requests – I kid you not! – most of which is JavaScript to
|
||
power all the ads and tracking. Lovely…
|
||
|
||
You don’t need a “framework” to develop this way, of course, but there are some
|
||
tools that make this style of server-side development easier. [68]Turbolinks
|
||
from the Basecamp folks was an early one, and it’s now been superseded by [69]
|
||
Turbo, which is apparently used to power their email service [70]Hey. I haven’t
|
||
used these personally, but the ideas are clever (and surprisingly old-skool):
|
||
use standard links and form submissions, [71]serve plain HTML, but speed it up
|
||
with WebSockets and JavaScript if available. Just today, in fact, someone
|
||
posted a new article on Hacker News which claims [72]“The Future of Web
|
||
Software Is HTML-over-WebSockets”. If Hey is anything to go by, this technique
|
||
is fast!
|
||
|
||
On the other hand, sometimes you can reduce overall complexity by using
|
||
JavaScript for the whole page if you’re going to need it anyway. For example,
|
||
the registry pages on my wedding registry website are rendered on the client
|
||
(they actually [73]use Elm, which compiles to JavaScript). I do need the
|
||
interactivity of JavaScript (it’s more “single page application” than mere
|
||
content), but I don’t need server-side rendering or good SEO for these pages.
|
||
The homepage is a simple server-rendered template, but the registry pages are
|
||
fully client-rendered.
|
||
|
||
Static sites and site generators
|
||
|
||
Another thing there’s been renewed interest in recently is static websites
|
||
(these used to be called just “websites”). You upload some static HTML (and CSS
|
||
and JavaScript) to a static file server, and that’s it.
|
||
|
||
Improving on that, there are many “static site generators” available. These are
|
||
tools that generate a static site from simple templates, so that you don’t have
|
||
to copy your site’s header and footer into every HTML file by hand. When you
|
||
add an article or make a change, run the script to re-generate. If you’re
|
||
hosting a simple site or blog or even a news site, this is a great way to go.
|
||
It’s content, after all, not an interactive application.
|
||
|
||
I use [74]GitHub Pages on this site just because it’s a free host that supports
|
||
SSL, and automatically builds your site using the [75]Jekyll static site
|
||
generator whenever you push a change. I have a standard header and include the
|
||
same CSS across all pages easily, though you can have multiple templates or
|
||
“layouts” if you want. Because most people only view one or two articles on my
|
||
site, I include my CSS inline. With HTTP/2, this doesn’t make much difference,
|
||
but Lighthouse showed around 200ms with inline CSS, 300ms with external CSS.
|
||
|
||
Here’s an example of what a simple Jekyll page looks like (the start of this
|
||
essay, in fact):
|
||
|
||
---
|
||
layout: default
|
||
title: "The small web is beautiful"
|
||
permalink: /writings/the-small-web-is-beautiful/
|
||
description: A vision for the "small web", small software, and ...
|
||
---
|
||
Markdown text here.
|
||
|
||
I’ve also used [76]Hugo, which is a really fast static site generator written
|
||
in Go – it generates even large sites with thousands of pages in a few seconds.
|
||
And there are [77]many other options available.
|
||
|
||
Fewer dependencies
|
||
|
||
There’s nothing that blows up the size of your software (or JavaScript bundle)
|
||
like third party dependencies. I always find a web project’s node_modules
|
||
directory hard to look at – just the sheer volume of stuff in there makes me
|
||
sad.
|
||
|
||
Different languages seem to have different “dependency cultures”. JavaScript,
|
||
of course, is notorious for an “if it can be a library, it should be” attitude,
|
||
resulting in the [78]left-pad disaster as well as other minuscule libraries
|
||
like the 3-line [79]isarray. There are also big, heavy packages like [80]
|
||
Moment.js, which takes [81]160KB even when minified. There are ways to shrink
|
||
it down if you don’t need all locales, but it’s not the default, so most people
|
||
don’t (you’re probably better off choosing a more modular approach like [82]
|
||
date-fns).
|
||
|
||
Go now has good dependency management with the recent [83]modules tooling, but
|
||
it also has a culture of “use the standard library if you can”. Russ Cox wrote
|
||
an excellent essay about the downsides of not being careful with your
|
||
dependencies: [84]Our Software Dependency Problem. Go co-creator Rob Pike even
|
||
made this one of his [85]Go proverbs: “A little copying is better than a little
|
||
dependency.” You can probably guess by now, but I like this minimalist
|
||
approach: apart from reducing the number of points of failure, it makes
|
||
programs smaller.
|
||
|
||
Python, Ruby, Java, and C# seem to be somewhere in between: people use a fair
|
||
number of dependencies, but from what I’ve seen there’s more care taken and it
|
||
doesn’t get as out of hand as node_modules. Admittedly it is a little unfair,
|
||
as Python (and those other languages) have standard libraries that have more in
|
||
them than JavaScript’s.
|
||
|
||
The website [86]YouMightNotNeedjQuery.com shows how many of the tasks you think
|
||
you might need a library for are actually quite simple to do with plain
|
||
JavaScript. For example, in one of my projects I use a function like the
|
||
following to make an API request with plain old XMLHttpRequest:
|
||
|
||
function postJson(url, data, callback) {
|
||
var xhr = new XMLHttpRequest();
|
||
xhr.onreadystatechange = function () {
|
||
if (xhr.readyState === xhr.DONE) {
|
||
callback(xhr.status, JSON.parse(xhr.responseText));
|
||
}
|
||
};
|
||
xhr.open("POST", url, true);
|
||
xhr.setRequestHeader("Content-Type", "application/json");
|
||
xhr.send(JSON.stringify(data));
|
||
}
|
||
|
||
The moral of the story: think twice before adding dependencies. You’ll keep
|
||
your websites and programs smaller and more reliable, and you’ll thank Russ Cox
|
||
later.
|
||
|
||
Small analytics
|
||
|
||
Most website owners want some form of analytics to see how many visitors are
|
||
coming to their site, and from where. The go-to tool is Google Analytics: it’s
|
||
easy to set up and the UI is pretty comprehensive. But there’s a cost: it adds
|
||
a significant amount of weight to your page (19KB of JavaScript, 46KB
|
||
uncompressed), and it sends a lot of user data for Google to collect.
|
||
|
||
Once again, there’s been renewed interest in smaller, more privacy-friendly
|
||
analytics systems in recent times. Just this morning I read a provocative
|
||
article that was highly-voted on Hacker News called [87]“Google Analytics: Stop
|
||
feeding the beast”.
|
||
|
||
Last year I wrote two articles for LWN on the subject, so I won’t say too much
|
||
more here:
|
||
|
||
• [88]Lightweight alternatives to Google Analytics: replacing it with
|
||
lightweight open source and privacy-conscious alternatives, specifically
|
||
[89]GoatCounter and [90]Plausible.
|
||
• [91]More alternatives to Google Analytics: some heavier alternatives, and a
|
||
brief look at log-based analytics tools.
|
||
|
||
For this website I use GoatCounter, which is available as a low-cost hosted
|
||
service (free for non-commercial use) or as a self-hosted tool. I really like
|
||
what Martin is doing here, and how small and simple the tool is: no bells and
|
||
whistles, just the basic traffic numbers that most people want.
|
||
|
||
Small architectures (not microservices)
|
||
|
||
Small websites are great for users, but small architectures are great for
|
||
developers. A small, simple codebase is easy to maintain, and will have fewer
|
||
bugs than a large, sprawling system with lots of interaction points.
|
||
|
||
I contend that the “microservices everywhere” buzz is a big problem.
|
||
Microservices may be used successfully at Google and Amazon, but most companies
|
||
don’t need to build that way. They introduce complexity in the code, API
|
||
definitions, networking, deployment, server infrastructure, monitoring,
|
||
database transactions – just about every aspect of a system is made more
|
||
complex. Why is that?
|
||
|
||
• Code: you have lots of little repositories, possibly in different
|
||
languages, and each has to have some way to talk to the other services
|
||
(JSON over HTTP, gRPC, etc). With a monolithic system, it’s all in one
|
||
language (much better for a small team), calling other modules is just a
|
||
function call, and system-wide refactoring is comparatively easy
|
||
(especially in a statically typed language like Go or Java).
|
||
• API definitions: with many services talking to each other, suddenly you
|
||
need standardized interfaces for how they communicate. You spend a lot of
|
||
time setting up gRPC or JSON schema definitions. In a single codebase, a
|
||
function signature is the API definition.
|
||
• Networking: with microservices, a function call is a network call, and you
|
||
spend time setting up your network infrastructure, thinking about timeouts
|
||
and retries, and maybe even designing inter-service authentication. In
|
||
monolithic systems, you only worry about networking when talking to your
|
||
database, cloud provider, and users.
|
||
• Deployment: at a previous company I worked at, once we started building
|
||
with microservices, suddenly we needed fancy deployment tooling and a
|
||
dedicated infrastructure team to manage it all. You can get by with a lot
|
||
less if you’re only deploying a few services.
|
||
• Server infrastructure: you’ll probably need to set up new infrastructure –
|
||
lots of small virtual machines, or a Kubernetes-based system. Kubernetes in
|
||
itself is a complex distributed application (even [92]Google admits it’s
|
||
too complex), and it takes a lot of work – or a lot of money – to run
|
||
properly.
|
||
• Monitoring: to debug issues, you’ll need costly distributed-monitoring
|
||
software like Datadog to see what’s going on. When an outage occurs, you’ll
|
||
scramble to determine which service is responsible, which team to page, and
|
||
so on. Compare that with a simple stack trace or single-service issue.
|
||
• Database transactions: these are difficult to impossible in a microservices
|
||
architecture. You may be able to design your way out of them, but that’s
|
||
not easy either. With a monolith, just type BEGIN ... COMMIT, or however
|
||
your database library spells it.
|
||
|
||
It’s been said before, but microservices solve a people problem, not a
|
||
technical one. But beware of [93]Conway’s Law: your architecture will mimic
|
||
your company structure. Or the reverse – you’ll have to hire and reorg so that
|
||
your company structure matches the architecture that microservices require:
|
||
lots of engineers on lots of small teams, with each team managing a couple of
|
||
microservices.
|
||
|
||
That doesn’t mean microservices are always the wrong choice: they may be
|
||
necessary in huge engineering organizations. However, if you’re working at such
|
||
a company, you’ve probably already been using microservices for years. If
|
||
you’re not “Google size”, you should think twice before copying their
|
||
development practices.
|
||
|
||
What’s the alternative? The term “monolith” has a bad rap, but I agree with
|
||
David at Basecamp that [94]monoliths can be majestic. Basecamp is a large,
|
||
monolithic application, and they run it with just a dozen programmers. David is
|
||
quick to point out that “the Majestic Monolith doesn’t pretend to provide a
|
||
failsafe architectural road to glory”. You still have to think, design, and
|
||
write good code.
|
||
|
||
Thankfully, people are bouncing back from the cargo culting. Just do a search
|
||
for [95]“why not microservices” and you’ll find lots of good articles on the
|
||
subject. One of the recent ones I’ve read is from Tailscale: [96]Modules,
|
||
monoliths, and microservices.
|
||
|
||
So what’s my advice?
|
||
|
||
• Unless your company name is Google or Amazon, start with a monolith.
|
||
• Once it starts having problems, optimize or refactor the pain points.
|
||
• If it’s still having issues, buy a bigger server.
|
||
• If you have a specific technical reason to split it up, fix that problem.
|
||
• If there are still problems, split off only the component that needs
|
||
splitting off. You’ll have two services to deploy and monitor, but that’s
|
||
far simpler than going all-in on microservices.
|
||
|
||
Okay, so this became more of an anti-microservices rant than I was planning,
|
||
but so be it.
|
||
|
||
In terms of counter-examples, Stack Overflow once again comes to mind. They’re
|
||
one of the web’s busiest sites, but they have a relatively simple, two-tier
|
||
[97]architecture that they’ve scaled vertically – in other words, big servers
|
||
with lots of RAM, rather than hundreds of small servers. They have 9 web
|
||
servers and 4 very chunky SQL servers, with a few additional servers for their
|
||
tag engine, Redis, Elasticsearch, and HAProxy. This architecture helps them get
|
||
great performance and the ability to develop with a small team.
|
||
|
||
My own side business, [98]GiftyWeddings.com, only gets a small amount of
|
||
traffic, so it’s nothing like Stack Overflow, but it uses a Go HTTP server with
|
||
SQLite on one of the smallest EC2 instances available, [99]t2.micro. It costs
|
||
about $8 per month, and I only have one tiny piece of infrastructure to
|
||
maintain. I deploy using [100]Ansible – a tool that is another good example of
|
||
simple architecture and boils down to “just use ssh”.
|
||
|
||
Speaking of SQLite, there’s a growing number of developers who advocate using
|
||
SQLite to run their websites. SQLite’s [101]“when to use SQLite” page says “any
|
||
site that gets fewer than 100K hits/day should work fine with SQLite. The 100K
|
||
hits/day figure is a conservative estimate, not a hard upper bound. SQLite has
|
||
been demonstrated to work with 10 times that amount of traffic.” Here are some
|
||
other SQLite success stories:
|
||
|
||
• [102]Litestream is an open source tool that provides streaming replication
|
||
for SQLite. Read author Ben Johnson’s article, [103]Why I Built Litestream.
|
||
• Go developer David Crawshaw has an article about what he calls [104]“one
|
||
process programming” (with Go and SQLite), that can be summed up with his
|
||
phrase “don’t use N computers when 1 will do”. He also created a [105]Go
|
||
SQLite library that supports more SQLite-specific features than the other
|
||
drivers.
|
||
• Peewee ORM author Charles Leifer wrote an article [106]“Five reasons you
|
||
should use SQLite in 2016” that’s still very relevant in 2021. It ends with
|
||
“I hope you’ll give SQLite a try. Don’t believe the FUD about it not being
|
||
production-worthy, or not being suitable for use in web-applications.”
|
||
• Sam Eaton of [107]Crave Cookie runs a $200,000 per month side business
|
||
(wow!) using a single server and SQLite. Read his [108]Indie Hackers
|
||
interview.
|
||
|
||
Summing up
|
||
|
||
Companies will do what companies do, and continue to make flashy-looking,
|
||
bloated websites that “convert” well. Maybe you can have an influence at work,
|
||
and come home to your better half and say “honey, I shrunk the web”. Or maybe
|
||
you’ll just focus on the small web for your personal projects. (Disclaimer: I
|
||
mostly do the latter – as part of my day job, I work on [109]Juju, which is not
|
||
a small system by most measures.)
|
||
|
||
Either way, I believe the “small web” is a compelling term and a compelling
|
||
aesthetic. Not necessarily in the visual sense, but in the sense that you built
|
||
it yourself, you understand all of it, and you run it on a single server or
|
||
static file host.
|
||
|
||
There are thousands of excellent examples of small websites, and hundreds of
|
||
ways to create simple architectures – this essay touches on only a few of the
|
||
ones I’m passionate about. I’d love to hear your own ideas and stories! Comment
|
||
over at [110]Lobsters or [111]Hacker News or [112]programming Reddit.
|
||
|
||
I’d love it if you [113]sponsored me on GitHub – it will motivate me to work on
|
||
my open source projects and write more good content. Thanks!
|
||
|
||
|
||
References:
|
||
|
||
[1] https://benhoyt.com/
|
||
[2] https://benhoyt.com/
|
||
[3] https://benhoyt.com/cv/
|
||
[4] https://benhoyt.com/projects/
|
||
[5] https://benhoyt.com/writings/
|
||
[6] https://benhoyt.com/writings/non-tech/
|
||
[7] mailto:benhoyt@gmail.com
|
||
[8] https://benhoyt.com/
|
||
[9] mailto:benhoyt@gmail.com
|
||
[10] https://benhoyt.com/writings/the-small-web-is-beautiful/#small-software
|
||
[11] https://benhoyt.com/writings/the-small-web-is-beautiful/#small-websites
|
||
[12] https://benhoyt.com/writings/the-small-web-is-beautiful/#emphasize-server-side-not-javascript
|
||
[13] https://benhoyt.com/writings/the-small-web-is-beautiful/#static-sites-and-site-generators
|
||
[14] https://benhoyt.com/writings/the-small-web-is-beautiful/#fewer-dependencies
|
||
[15] https://benhoyt.com/writings/the-small-web-is-beautiful/#small-analytics
|
||
[16] https://benhoyt.com/writings/the-small-web-is-beautiful/#small-architectures-not-microservices
|
||
[17] https://basecamp.com/books
|
||
[18] https://neustadt.fr/essays/the-small-web/
|
||
[19] https://ar.al/2020/08/07/what-is-the-small-web/
|
||
[20] https://en.wikipedia.org/wiki/Forth_(programming_language)
|
||
[21] https://github.com/benhoyt/third
|
||
[22] https://en.wikipedia.org/wiki/Demoscene
|
||
[23] https://www.youtube.com/watch?v=jB0vBmiTr6o
|
||
[24] https://www.youtube.com/watch?v=RCh3Q08HMfs
|
||
[25] https://benhoyt.com/writings/the-small-web-is-beautiful/#fewer-dependencies
|
||
[26] https://cr.yp.to/bib/1995/wirth.pdf
|
||
[27] https://blog.brush.co.nz/2008/07/adobe-reader-9/
|
||
[28] https://1mb.club/
|
||
[29] https://news.ycombinator.com/item?id=25151773
|
||
[30] https://512kb.club/
|
||
[31] https://news.ycombinator.com/item?id=25450451
|
||
[32] https://250kb.club/
|
||
[33] https://news.ycombinator.com/item?id=25176663
|
||
[34] https://10kbclub.com/
|
||
[35] https://news.ycombinator.com/item?id=25556860
|
||
[36] https://news.ycombinator.com/news
|
||
[37] https://lobste.rs/
|
||
[38] https://sourcehut.org/
|
||
[39] https://forgeperf.org/
|
||
[40] https://sqlite.org/
|
||
[41] https://sqlite.org/testing.html
|
||
[42] https://lwn.net/
|
||
[43] https://lwn.net/Archives/GuestIndex/#Hoyt_Ben
|
||
[44] https://danluu.com/
|
||
[45] https://lucumr.pocoo.org/
|
||
[46] https://nullprogram.com/
|
||
[47] http://eradman.com/
|
||
[48] https://hugotunius.se/
|
||
[49] https://prog21.dadgum.com/
|
||
[50] https://jvns.ca/
|
||
[51] https://sjmulder.nl/en/textonly.html
|
||
[52] https://giftyweddings.com/
|
||
[53] https://news.ycombinator.com/item?id=26057078
|
||
[54] https://news.ycombinator.com/item?id=11210860
|
||
[55] https://indieweb.org/
|
||
[56] https://small-tech.org/
|
||
[57] https://news.ycombinator.com/item?id=24269071
|
||
[58] https://indieweb.org/Homebrew_Website_Club
|
||
[59] https://indieweb.org/IndieWebCamps
|
||
[60] https://benhoyt.com/writings/seo-for-software-engineers/
|
||
[61] https://stackoverflow.com/
|
||
[62] https://blog.codinghorror.com/performance-is-a-feature/
|
||
[63] https://news.ycombinator.com/
|
||
[64] https://news.ycombinator.com/hn.js
|
||
[65] https://news.ycombinator.com/item?id=23876281
|
||
[66] https://alistapart.com/article/understandingprogressiveenhancement/
|
||
[67] https://www.reddit.com/
|
||
[68] https://github.com/turbolinks/turbolinks
|
||
[69] https://turbo.hotwire.dev/
|
||
[70] https://hey.com/
|
||
[71] https://m.signalvnoise.com/html-over-the-wire/
|
||
[72] https://alistapart.com/article/the-future-of-web-software-is-html-over-websockets/
|
||
[73] https://benhoyt.com/writings/learning-elm/
|
||
[74] https://pages.github.com/
|
||
[75] https://jekyllrb.com/
|
||
[76] https://gohugo.io/
|
||
[77] https://staticsitegenerators.net/
|
||
[78] https://www.davidhaney.io/npm-left-pad-have-we-forgotten-how-to-program/
|
||
[79] https://github.com/juliangruber/isarray/blob/c9b0c5b4f44d366c9f51c7e85e70339bdeaa97b0/index.js#L3-L5
|
||
[80] https://momentjs.com/
|
||
[81] https://momentjs.com/docs/#/use-it/webpack/
|
||
[82] https://date-fns.org/
|
||
[83] https://golang.org/doc/modules/managing-dependencies
|
||
[84] https://research.swtch.com/deps
|
||
[85] https://go-proverbs.github.io/
|
||
[86] http://youmightnotneedjquery.com/
|
||
[87] https://casparwre.de/blog/stop-using-google-analytics/
|
||
[88] https://lwn.net/Articles/822568/
|
||
[89] https://www.goatcounter.com/
|
||
[90] https://plausible.io/
|
||
[91] https://lwn.net/Articles/824294/
|
||
[92] https://www.theregister.com/2021/02/25/google_kubernetes_autopilot/
|
||
[93] https://en.wikipedia.org/wiki/Conway%27s_law
|
||
[94] https://m.signalvnoise.com/the-majestic-monolith/
|
||
[95] https://duckduckgo.com/?t=canonical&q=why+not+microservices&ia=web
|
||
[96] https://tailscale.com/blog/modules-monoliths-and-microservices/
|
||
[97] https://stackexchange.com/performance
|
||
[98] https://giftyweddings.com/
|
||
[99] https://aws.amazon.com/ec2/instance-types/t2/
|
||
[100] https://www.ansible.com/
|
||
[101] https://sqlite.org/whentouse.html
|
||
[102] https://litestream.io/
|
||
[103] https://litestream.io/blog/why-i-built-litestream/
|
||
[104] https://crawshaw.io/blog/one-process-programming-notes
|
||
[105] https://github.com/crawshaw/sqlite
|
||
[106] https://charlesleifer.com/blog/five-reasons-you-should-use-sqlite-in-2016/
|
||
[107] https://cravecookie.com/
|
||
[108] https://www.indiehackers.com/podcast/166-sam-eaton-of-crave-cookie
|
||
[109] https://jaas.ai/
|
||
[110] https://lobste.rs/s/d6qwff/small_web_is_beautiful
|
||
[111] https://news.ycombinator.com/item?id=26305585
|
||
[112] https://www.reddit.com/r/programming/comments/lvfdq9/the_small_web_is_beautiful/
|
||
[113] https://github.com/sponsors/benhoyt/
|