729 lines
38 KiB
Plaintext
729 lines
38 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. file:///
|
||
2. file:///
|
||
3. file:///cv/
|
||
4. file:///projects/
|
||
5. file:///writings/
|
||
6. file:///writings/non-tech/
|
||
7. mailto:benhoyt@gmail.com
|
||
8. https://benhoyt.com/
|
||
9. mailto:benhoyt@gmail.com
|
||
10. file:///var/folders/q9/qlz2w5251kzdfgn0np7z2s4c0000gn/T/L83225-8351TMP.html#small-software
|
||
11. file:///var/folders/q9/qlz2w5251kzdfgn0np7z2s4c0000gn/T/L83225-8351TMP.html#small-websites
|
||
12. file:///var/folders/q9/qlz2w5251kzdfgn0np7z2s4c0000gn/T/L83225-8351TMP.html#emphasize-server-side-not-javascript
|
||
13. file:///var/folders/q9/qlz2w5251kzdfgn0np7z2s4c0000gn/T/L83225-8351TMP.html#static-sites-and-site-generators
|
||
14. file:///var/folders/q9/qlz2w5251kzdfgn0np7z2s4c0000gn/T/L83225-8351TMP.html#fewer-dependencies
|
||
15. file:///var/folders/q9/qlz2w5251kzdfgn0np7z2s4c0000gn/T/L83225-8351TMP.html#small-analytics
|
||
16. file:///var/folders/q9/qlz2w5251kzdfgn0np7z2s4c0000gn/T/L83225-8351TMP.html#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. file:///var/folders/q9/qlz2w5251kzdfgn0np7z2s4c0000gn/T/L83225-8351TMP.html#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's_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/
|