Dispatch 5 (and various misc. updates)
This commit is contained in:
88
content/journal/dispatch-5-july-2023/index.md
Normal file
88
content/journal/dispatch-5-july-2023/index.md
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
---
|
||||||
|
title: "Dispatch #5 (July 2023)"
|
||||||
|
date: 2023-07-02T16:55:57-04:00
|
||||||
|
draft: false
|
||||||
|
tags:
|
||||||
|
- dispatch
|
||||||
|
references:
|
||||||
|
- title: "My thoughts on Helix after 6 months - Tim Hårek"
|
||||||
|
url: https://timharek.no/blog/my-thoughts-on-helix-after-6-months/
|
||||||
|
date: 2023-07-02T12:53:51Z
|
||||||
|
file: timharek-no-ah7ilz.txt
|
||||||
|
- title: "What App is That?"
|
||||||
|
url: https://maggieappleton.com/apps
|
||||||
|
date: 2023-07-02T12:53:51Z
|
||||||
|
file: maggieappleton-com-7am49k.txt
|
||||||
|
- title: "Modern software quality, or why I think using language models for programming is a bad idea"
|
||||||
|
url: https://softwarecrisis.dev/letters/ai-and-software-quality/
|
||||||
|
date: 2023-07-03T00:54:57Z
|
||||||
|
file: softwarecrisis-dev-7c7z9g.txt
|
||||||
|
- title: "The small web is beautiful"
|
||||||
|
url: https://benhoyt.com/writings/the-small-web-is-beautiful/
|
||||||
|
date: 2023-07-03T00:52:08Z
|
||||||
|
file: benhoyt-com-vfdv1s.txt
|
||||||
|
- title: "Why You Own an iPad and Still Can’t Draw"
|
||||||
|
url: https://maggieappleton.com/still-cant-draw
|
||||||
|
date: 2023-07-03T01:05:26Z
|
||||||
|
file: maggieappleton-com-fube9k.txt
|
||||||
|
---
|
||||||
|
|
||||||
|
June was dominated by work and travel. Weekdays were filled up with a client project we were working hard to wrap, weekends by plans with friends and both of our families: [Running of the Bulls][1], canoe camping near Saxapahaw, our yearly trip to Beaufort with Claire's college friends, and then a cruise in the Caribbean with Claire's family followed immediately by a trip up to DC to see mine.
|
||||||
|
|
||||||
|
[1]: https://bullcityrunning.com/our-races/running-of-the-bulls-8k/
|
||||||
|
|
||||||
|
<!--more-->
|
||||||
|
|
||||||
|
<div class="image-set">
|
||||||
|
{{<thumbnail IMG_4041 "200x150" />}}
|
||||||
|
{{<thumbnail 11B423F8-5D03-4155-B548-185E04A04595_1_105_c "200x150" />}}
|
||||||
|
{{<thumbnail IMG_9457 "200x150" />}}
|
||||||
|
{{<thumbnail C65C4973-3266-4155-9786-F7B379BD8DD9_1_105_c "200x150" />}}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
Most everything else fell by the wayside, but that's OK -- these were all awesome experiences, and I'm excited for a (relatively) quiet July.
|
||||||
|
|
||||||
|
After getting the trailer hitch installed last month, we picked up a [bike rack][2] and a [seat for Nev][3] and brought the bikes with us to Beaufort. This was **awesome** -- Beaufort's an idyllic coastal town in just about every way but one: parking sucks. Being able to zip up and down the main street on our bikes (and parking them right at our destination) was such a joy, and Nev seems to enjoy the rack-mounted seat a lot more than the trailer we've been using.
|
||||||
|
|
||||||
|
I'm still enjoying using Obsidian to collect link and make notes, though mostly in the "capture" phase[^1], collecting information and starting to put some structure around it. When something comes up and I think, man, I read something good about that at some point in the past, I'm using that as a cue to create a dedicated note, with the hope that the _next_ time it comes up, I'll have a useful thing to reference.
|
||||||
|
|
||||||
|
I also read some good articles about [Helix][4] and [Procreate][5], and I'm hoping to give those some attention this month.
|
||||||
|
|
||||||
|
[2]: https://1up-usa.com/product/2-super-duty-double
|
||||||
|
[3]: https://www.thule.com/en-us/child-bike-seats/rear-mounted-child-bike-seats/thule-yepp-nexxt-maxi-_-12080211
|
||||||
|
[4]: https://timharek.no/blog/my-thoughts-on-helix-after-6-months/
|
||||||
|
[5]: https://maggieappleton.com/apps
|
||||||
|
|
||||||
|
This month:
|
||||||
|
|
||||||
|
* Adventure: dust off the road bike, fill the tires, grease the chain, throw it on the rack, and get out for a long ride
|
||||||
|
* Project: publish an article on [testing][14] on my company's website
|
||||||
|
* Skill: learn [Helix][13] movements, see if it'd be a good Vim replacement (I still love Vim, and I'm pretty good at it, but my config's dated and I'm wary of how much effort it'll take to modernize)
|
||||||
|
|
||||||
|
[13]: https://helix-editor.com/
|
||||||
|
[14]: /notes/good-tests
|
||||||
|
|
||||||
|
Reading:
|
||||||
|
|
||||||
|
* Fiction: [_The Golden Enclaves_][6], Naomi Novik
|
||||||
|
* Non-fiction:
|
||||||
|
* [_Rapt_][7], Winifred Gallagher
|
||||||
|
* [_Visual Thinking_][8], Williemien Brand
|
||||||
|
* [_The Manual: A Philosopher's Guide to Life_][9], Epictetus
|
||||||
|
|
||||||
|
[7]: https://bookshop.org/p/books/rapt-attention-and-the-focused-life-winifred-gallagher/7485226?ean=9780143116905
|
||||||
|
[6]: https://bookshop.org/p/books/the-golden-enclaves-naomi-novik/17789027?ean=9780593158357
|
||||||
|
[8]: https://bookshop.org/p/books/visual-thinking-empowering-people-and-organisations-through-visual-collaboration-williemien-brand/12408256?ean=9789063694531
|
||||||
|
[9]: https://bookshop.org/p/books/the-manual-a-philosopher-s-guide-to-life-epictetus/15150488?ean=9781545461112
|
||||||
|
|
||||||
|
Links:
|
||||||
|
|
||||||
|
* [Modern software quality, or why I think using language models for programming is a bad idea][10] -- I refer people to this article a lot in discussions around <abbr title="large language models">LLMs</abbr> and software development
|
||||||
|
* [The small web is beautiful][11]
|
||||||
|
* [Why You Own an iPad and Still Can't Draw][12]
|
||||||
|
|
||||||
|
[10]: https://softwarecrisis.dev/letters/ai-and-software-quality/
|
||||||
|
[11]: https://benhoyt.com/writings/the-small-web-is-beautiful/
|
||||||
|
[12]: https://maggieappleton.com/still-cant-draw
|
||||||
|
|
||||||
|
[^1]: Tiago Forte's _Building a Second Brain_ outlines a four-step process: Capture, Organize, Distill, Express.
|
||||||
@@ -15,6 +15,10 @@ references:
|
|||||||
url: https://cerebralab.com/Imaginary_Problems_Are_the_Root_of_Bad_Software
|
url: https://cerebralab.com/Imaginary_Problems_Are_the_Root_of_Bad_Software
|
||||||
date: 2023-06-20T16:28:39Z
|
date: 2023-06-20T16:28:39Z
|
||||||
file: cerebralab-com-qy5zqs.txt
|
file: cerebralab-com-qy5zqs.txt
|
||||||
|
- title: "When to Build Millennia Sewers"
|
||||||
|
url: https://taylor.town/millennium-sewer
|
||||||
|
date: 2023-07-03T00:32:43Z
|
||||||
|
file: taylor-town-5siv9a.txt
|
||||||
---
|
---
|
||||||
|
|
||||||
### Thoughts on priorities in software development
|
### Thoughts on priorities in software development
|
||||||
@@ -28,7 +32,9 @@ references:
|
|||||||
* [The Grug Brained Developer][1]
|
* [The Grug Brained Developer][1]
|
||||||
* [Even Amazon can't make sense of serverless or microservices][2]
|
* [Even Amazon can't make sense of serverless or microservices][2]
|
||||||
* [Imaginary Problems Are the Root of Bad Software][3]
|
* [Imaginary Problems Are the Root of Bad Software][3]
|
||||||
|
* [When to Build Millennia Sewers][4]
|
||||||
|
|
||||||
[1]: https://grugbrain.dev/
|
[1]: https://grugbrain.dev/
|
||||||
[2]: https://world.hey.com/dhh/even-amazon-can-t-make-sense-of-serverless-or-microservices-59625580
|
[2]: https://world.hey.com/dhh/even-amazon-can-t-make-sense-of-serverless-or-microservices-59625580
|
||||||
[3]: https://cerebralab.com/Imaginary_Problems_Are_the_Root_of_Bad_Software
|
[3]: https://cerebralab.com/Imaginary_Problems_Are_the_Root_of_Bad_Software
|
||||||
|
[4]: https://taylor.town/millennium-sewer
|
||||||
|
|||||||
@@ -47,6 +47,7 @@ I find [Go][1] really compelling, even though it's not super applicable to my jo
|
|||||||
* [SyncThing][5]
|
* [SyncThing][5]
|
||||||
* [Restic][6]
|
* [Restic][6]
|
||||||
* [Gotenberg][7]
|
* [Gotenberg][7]
|
||||||
|
* [Shiori][8]
|
||||||
|
|
||||||
[2]: https://gohugo.io/
|
[2]: https://gohugo.io/
|
||||||
[3]: https://caddyserver.com/
|
[3]: https://caddyserver.com/
|
||||||
@@ -54,29 +55,30 @@ I find [Go][1] really compelling, even though it's not super applicable to my jo
|
|||||||
[5]: https://syncthing.net/
|
[5]: https://syncthing.net/
|
||||||
[6]: https://restic.net/
|
[6]: https://restic.net/
|
||||||
[7]: https://gotenberg.dev/
|
[7]: https://gotenberg.dev/
|
||||||
|
[8]: https://github.com/go-shiori/shiori
|
||||||
|
|
||||||
### Project Ideas
|
### Project Ideas
|
||||||
|
|
||||||
* Bookmarking app (Pinboard replacement)
|
* Bookmarking app (Pinboard replacement)
|
||||||
* Note-taking / journaling app
|
* Note-taking / journaling app
|
||||||
* [StevieBlocks][8]
|
* [StevieBlocks][9]
|
||||||
|
|
||||||
{{<thumbnail project1 "400x" />}}
|
{{<thumbnail project1 "400x" />}}
|
||||||
|
|
||||||
[8]: https://gist.github.com/dce/f975cb21b50a2cf998bf7230cbf89d85
|
[9]: https://gist.github.com/dce/f975cb21b50a2cf998bf7230cbf89d85
|
||||||
|
|
||||||
### Resources
|
### Resources
|
||||||
|
|
||||||
* [Standard Go Project Layout][9]
|
* [Standard Go Project Layout][10]
|
||||||
* [The files & folders of Go projects][10]
|
* [The files & folders of Go projects][11]
|
||||||
* [Why David Yach Loves Go][11]
|
* [Why David Yach Loves Go][12]
|
||||||
* [One process programming notes (with Go and SQLite)][12]
|
* [One process programming notes (with Go and SQLite)][13]
|
||||||
* [Go Project Layout][13]
|
* [Go Project Layout][14]
|
||||||
* [Gopher Wrangling. Effective error handling in Go][14]
|
* [Gopher Wrangling. Effective error handling in Go][15]
|
||||||
|
|
||||||
[9]: https://github.com/golang-standards/project-layout
|
[10]: https://github.com/golang-standards/project-layout
|
||||||
[10]: https://changelog.com/gotime/278
|
[11]: https://changelog.com/gotime/278
|
||||||
[11]: https://cloud.google.com/blog/products/application-modernization/why-david-yach-loves-go
|
[12]: https://cloud.google.com/blog/products/application-modernization/why-david-yach-loves-go
|
||||||
[12]: https://crawshaw.io/blog/one-process-programming-notes
|
[13]: https://crawshaw.io/blog/one-process-programming-notes
|
||||||
[13]: https://medium.com/golang-learn/go-project-layout-e5213cdcfaa2
|
[14]: https://medium.com/golang-learn/go-project-layout-e5213cdcfaa2
|
||||||
[14]: https://stephenn.com/2023/06/gopher-wrangling.-effective-error-handling-in-go/
|
[15]: https://stephenn.com/2023/06/gopher-wrangling.-effective-error-handling-in-go/
|
||||||
|
|||||||
@@ -2,6 +2,11 @@
|
|||||||
title: "Good Tests"
|
title: "Good Tests"
|
||||||
date: 2023-05-12T23:40:19-04:00
|
date: 2023-05-12T23:40:19-04:00
|
||||||
draft: false
|
draft: false
|
||||||
|
references:
|
||||||
|
- title: "A year of Rails - macwright.com"
|
||||||
|
url: https://macwright.com/2021/02/18/a-year-of-rails.html
|
||||||
|
date: 2023-07-03T02:52:03Z
|
||||||
|
file: macwright-com-o4dndf.txt
|
||||||
---
|
---
|
||||||
|
|
||||||
_(Notes for a Viget article I'm putting together)_
|
_(Notes for a Viget article I'm putting together)_
|
||||||
|
|||||||
728
static/archive/benhoyt-com-vfdv1s.txt
Normal file
728
static/archive/benhoyt-com-vfdv1s.txt
Normal file
@@ -0,0 +1,728 @@
|
|||||||
|
[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/
|
||||||
344
static/archive/macwright-com-o4dndf.txt
Normal file
344
static/archive/macwright-com-o4dndf.txt
Normal file
@@ -0,0 +1,344 @@
|
|||||||
|
#[1]macwright.com [2]macwright.com
|
||||||
|
|
||||||
|
Tom MacWright
|
||||||
|
|
||||||
|
tom@macwright.com
|
||||||
|
|
||||||
|
Tom MacWright
|
||||||
|
|
||||||
|
* [3]Writingâ‡
|
||||||
|
* [4]Reading
|
||||||
|
* [5]Photos
|
||||||
|
* [6]Projects
|
||||||
|
* [7]Drawings
|
||||||
|
* [8]About
|
||||||
|
|
||||||
|
A year of Rails
|
||||||
|
|
||||||
|
Railroad
|
||||||
|
|
||||||
|
I spent most of 2020 working with [9]Ruby on Rails. I moved a project
|
||||||
|
from [10]Next.js + [11]Rust to… Rails, baby! Back to the future. My
|
||||||
|
earlier post on [12]Second-guessing the modern web was inspired by this
|
||||||
|
experience, that for the product we were building, a ‘modern’ stack was
|
||||||
|
not working as well as a traditional one.
|
||||||
|
|
||||||
|
We didn’t do competitive analysis against Laravel, Django, or Phoenix.
|
||||||
|
They’re similar, not radically better or worse. There are multiple
|
||||||
|
acceptable solutions to a problem, and this was more a matter of
|
||||||
|
choosing the right kind of solution than pursuing some kind of perfect
|
||||||
|
choice and burning hours and motivation doing the window-shopping.
|
||||||
|
|
||||||
|
What helped Rails win was that the team had a little more experience in
|
||||||
|
Ruby (with the exception of myself), and we found plenty of resources
|
||||||
|
for developing and deploying the stack. Rails fit perfectly into the
|
||||||
|
ideology of [13]Choosing boring technology. Another part of the product
|
||||||
|
would be the hard, innovative part, so it made no sense to grapple with
|
||||||
|
bleeding-edge web frameworks.
|
||||||
|
|
||||||
|
This was a really fun experience. There’s a lot to love about Rails.
|
||||||
|
Other communities could learn a bit from the Ruby & Rails culture and
|
||||||
|
wisdom. I won’t implement everything in Rails, but it’ll be part of the
|
||||||
|
toolbox.
|
||||||
|
|
||||||
|
Before this, I hadn’t touched the stuff. And I bet a lot of people are
|
||||||
|
like that - they came of age in the world of React and Go, and haven’t
|
||||||
|
tried anything even remotely similar to Rails. For their benefit, and
|
||||||
|
to debrief from 2020, here are some notes on the experience. Plus,
|
||||||
|
[14]Rails-like projects in JavaScript are ramping up quickly, and it’s
|
||||||
|
fun to know the origins.
|
||||||
|
|
||||||
|
The good
|
||||||
|
|
||||||
|
Debugging Rails apps is amazing
|
||||||
|
|
||||||
|
A while ago, I [15]wrote on Twitter
|
||||||
|
|
||||||
|
the real reason why javascript developers don’t use breakpoints and
|
||||||
|
use console.log is that breakpoints don’t work
|
||||||
|
|
||||||
|
After years of working in JavaScript, I’m used to bad debugging
|
||||||
|
experiences. The Chrome debugger’s [16]automatic pause on caught
|
||||||
|
exceptions is amazing, sometimes. But throwing a debugger statement in
|
||||||
|
some React code is dodgy as hell. Sometimes it works, mostly it
|
||||||
|
doesn’t. You have to deal with code that might not have the right
|
||||||
|
[17]sourcemap to translate from bundled & minified code to original
|
||||||
|
source. Subtle abstractions like React hooks and advanced transpiler
|
||||||
|
stuff like [18]Regenerator mean that your code’s stacktrace probably
|
||||||
|
looks nothing like what you expect, with lots of internal garbage.
|
||||||
|
Sure, you can learn better techniques for diagnosing and debugging
|
||||||
|
errors, but it’s not just you - the debugging story in JavaScript is
|
||||||
|
pretty bad. This applies even to Node.js, where one of the debugging
|
||||||
|
stories is to connect Chrome’s debugger to a Node.js instance: a
|
||||||
|
finicky solution that doesn’t consistently work.
|
||||||
|
|
||||||
|
In Rails, there is [19]byebug. You write byebug in your source code,
|
||||||
|
and you get an interactive REPL right there. It works in views,
|
||||||
|
controllers, database migrations, everywhere. It almost always works.
|
||||||
|
Variables are named what you expect. The whole system is paused at that
|
||||||
|
moment, and you can actually interact with it, using all of the Rails
|
||||||
|
utilities and your installed gems.
|
||||||
|
|
||||||
|
If a page crashes unexpectedly, you get a similar REPL experience, in
|
||||||
|
your browser, automatically. With an automatically cleaned-up
|
||||||
|
stacktrace that excludes Rails’s own frames. Like the byebug interface,
|
||||||
|
this REPL actually works and is consistently helpful in finding root
|
||||||
|
causes. Rarely will you need to use puts to print something to the
|
||||||
|
console because this debugging system is so good.
|
||||||
|
|
||||||
|
The magic mostly works
|
||||||
|
|
||||||
|
Our Rails app didn’t have any require statements. You mention a
|
||||||
|
module’s name, and it’s automatically included, using [20]Zeitwerk, a
|
||||||
|
tool that comes standard with Rails.
|
||||||
|
|
||||||
|
This kind of system was terrifying to me before. What if you
|
||||||
|
accidentally import something just by mentioning it? What if two things
|
||||||
|
have the same name and you import the wrong one? How do you really know
|
||||||
|
what’s happening? Sure, you’re happy now, with all of that annoying
|
||||||
|
importing and exporting taken care of, but the sky might fall.
|
||||||
|
|
||||||
|
Or maybe it just… doesn’t. Maybe impure, vaguely risky techniques are
|
||||||
|
just a net positive over time, and making everything fully explicit
|
||||||
|
isn’t really necessary? Now when I’m using other systems, I wonder -
|
||||||
|
what if I could just mention one of my React components and it would
|
||||||
|
just… be there? Sure, the system would have to complain if there were
|
||||||
|
two components with the same name, and it would have to make
|
||||||
|
assumptions about directory structure, but overall, wouldn’t this be
|
||||||
|
nice?
|
||||||
|
|
||||||
|
This applies to a lot of other parts of the system too. Rails is famous
|
||||||
|
for doing pluralization - you name a model Post and you automatically
|
||||||
|
get an interface called posts. But what, you ask, of words with uneven
|
||||||
|
pluralization rules? Rails actually [21]does the right thing, almost
|
||||||
|
always. And when it fails, you can override it. It actually just saves
|
||||||
|
time, reliably.
|
||||||
|
|
||||||
|
Testing works
|
||||||
|
|
||||||
|
I’ve tried to test front-end applications. I’ve set up [22]nightwatch,
|
||||||
|
[23]jest, [24]enzyme, [25]cypress, and probably 5-10 other frameworks.
|
||||||
|
Front-end testing is universally terrible. Projects like Cypress are
|
||||||
|
throwing untold hours into making it less terrible, taking on massive
|
||||||
|
amounts of complexity to abstract away from fickle browser behavior and
|
||||||
|
complex interactions.
|
||||||
|
|
||||||
|
But it still sucks. Frontend testing has no good attributes: it’s
|
||||||
|
unreliable, hard to automate, hard to debug when it fails, and often
|
||||||
|
doesn’t even assert for important behaviors, so it doesn’t actually
|
||||||
|
identify regressions. Running frontend tests in CI is resource-heavy,
|
||||||
|
requiring you to set up headless X windows environments on servers or
|
||||||
|
use specialized CI services that produce screencasts of test runs.
|
||||||
|
|
||||||
|
Testing fully-server-rendered applications, on the other hand, is
|
||||||
|
amazing. A vanilla testing setup with Rails & [26]RSpec can give you
|
||||||
|
fast, stable, concise, and actually-useful test coverage. You can
|
||||||
|
actually assert for behavior and navigate through an application like a
|
||||||
|
user would. These tests are solving a simpler problem - making requests
|
||||||
|
and parsing responses, without the need for a full browser or headless
|
||||||
|
browser, without multiple kinds of state to track.
|
||||||
|
|
||||||
|
Not only do the tests work better, the testing culture is a completely
|
||||||
|
different universe. There are entire books written about how to write
|
||||||
|
RSpec tests that catch bugs, allow software evolution, and aren’t
|
||||||
|
filled with boilerplate.
|
||||||
|
|
||||||
|
Gems are so powerful
|
||||||
|
|
||||||
|
Powerful and dangerous.
|
||||||
|
|
||||||
|
I’m used to modules as they work in other systems - Python, Node, Elm,
|
||||||
|
and so on. They provide objects, functions, and variables that you can
|
||||||
|
import and combine into your code explicitly. Usually they sit on some
|
||||||
|
specific level of abstraction - it’s a utility for connecting to
|
||||||
|
servers or a React component you can use.
|
||||||
|
|
||||||
|
Gems can do so much more. You install something like [27]Devise into
|
||||||
|
your system and it adds views, routes, methods, utilities, you name it.
|
||||||
|
It’s not like “loading some functionsâ€<C3A2>, it’s more like composing a
|
||||||
|
whole different app into your app, implicitly.
|
||||||
|
|
||||||
|
This is obviously terrifying. It means that you can’t look at your
|
||||||
|
directories of views and your file of routes.rb and know what exists at
|
||||||
|
a glance. There are other layers, lurking in the ephemeral space of
|
||||||
|
third-party code. They interact in serious but uncertain ways.
|
||||||
|
|
||||||
|
But it’s also pretty incredible - the idea that something like
|
||||||
|
[28]passport, Node’s middleware, could instead be a full-fledged
|
||||||
|
authentication system. It means that you have to write a lot less code,
|
||||||
|
and it also means that the people who use that code have a lot more
|
||||||
|
code in common. That gems can work on a higher level of abstraction,
|
||||||
|
making it possible to cobble together software faster, to write less
|
||||||
|
‘glue code.’
|
||||||
|
|
||||||
|
There’s so much good writing about Rails
|
||||||
|
|
||||||
|
Even if you don’t write Ruby, you should pay attention to [29]Sandi
|
||||||
|
Metz. She’s incredibly wise and has so many incredible ideas to share.
|
||||||
|
|
||||||
|
And then there’s [30]arkency, [31]ThoughtBot, and so many other
|
||||||
|
thoughtful writers with years of experience in Rails. Sometimes it’s a
|
||||||
|
little shocking to google for some obscure problem and see a decade of
|
||||||
|
discussion about it.
|
||||||
|
|
||||||
|
The best practices are also formalized into tools like [32]Code Climate
|
||||||
|
and [33]reek. I’ve never seen so many actually-useful suggestions come
|
||||||
|
out of automated systems as I did in the world of Ruby and Rails.
|
||||||
|
|
||||||
|
Ruby
|
||||||
|
|
||||||
|
Ruby is a pretty pleasant language to work in. Sure, it has a lot of
|
||||||
|
syntax and a sprawling standard library, but you don’t have to use all
|
||||||
|
of that if you don’t want to. It took me a while to adjust to the
|
||||||
|
object-oriented way of doing things - in particular, the idea that you
|
||||||
|
can’t just have a free-range function floating out there, unassociated
|
||||||
|
with a class or module, like you can in JavaScript. And you can’t just
|
||||||
|
create an arbitrary one-off object - you either need to define a class
|
||||||
|
to create an object, or use a Hash to store data.
|
||||||
|
|
||||||
|
But Ruby’s standard library isn’t that huge. I’ve seen JavaScript’s
|
||||||
|
‘standard library’ grow a lot too, and frankly it’s nice to have
|
||||||
|
methods like [34]String.prototype.padStart instead of having every
|
||||||
|
little thing in userspace. The only part that felt actively weird was
|
||||||
|
[35]activesupport - a gem that extends Ruby’s core objects, but is part
|
||||||
|
of Rails. It felt weird to have string methods that would only work if
|
||||||
|
your environment was Rails.
|
||||||
|
|
||||||
|
The [36]Dash app for documentation rocketed from my pile of unused
|
||||||
|
tools to an absolute must-have. In the world of Ruby and Rails, with
|
||||||
|
most gems having pretty good, semi-standard documentation, you can
|
||||||
|
search for, and get answers, super fast. The Ruby language
|
||||||
|
documentation and the Rails documentation is absolutely great. The
|
||||||
|
JavaScript equivalent - [37]MDN - pales in comparison.
|
||||||
|
|
||||||
|
The bad
|
||||||
|
|
||||||
|
The asset pipeline
|
||||||
|
|
||||||
|
Remember SASS and the YUI Compressor? These are, unfortunately,
|
||||||
|
defaults in the [38]asset pipeline. There’s [39]Webpacker too, which
|
||||||
|
has a parallel approach to CSS and images as the asset pipeline. It has
|
||||||
|
[40]opinionated integrations with stuff like React. Ah, and I should
|
||||||
|
mention that Rails’s [41]JavaScript utilities are written in…
|
||||||
|
CoffeeScript.
|
||||||
|
|
||||||
|
I get it - it’s hard to keep up with the latest trends in frontend. But
|
||||||
|
this is one area where Rails’s strong backwards compatibility feels
|
||||||
|
iffy. I wish that Rails was more opinionated about the frontend, and
|
||||||
|
that it had better opinions.
|
||||||
|
|
||||||
|
Best practice churn
|
||||||
|
|
||||||
|
In Smalltalk, everything happens somewhere else. - [42]Adele
|
||||||
|
Goldberg
|
||||||
|
|
||||||
|
Ruby, as today’s Smalltalk, has the same issue. The community venerates
|
||||||
|
small - that methods should be short, files should be small, complexity
|
||||||
|
should be controlled. This begs the question of where it all goes -
|
||||||
|
certainly not in controllers, which should be skinny, and not in views,
|
||||||
|
which should have very little logic at all, and maybe [43]not in models
|
||||||
|
either. Maybe in [44]Service Objects, or policies, or decorators?
|
||||||
|
|
||||||
|
I found myself falling victim to this. I’d try to win CodeClimate’s
|
||||||
|
approval by moving code around, perfecting the art of making everything
|
||||||
|
small or at most medium-sized, extracting concerns until most files
|
||||||
|
looked okay. This was time well-spent on learning, but I have to admit
|
||||||
|
that it doesn’t actually matter for an early-stage startup’s product.
|
||||||
|
|
||||||
|
In stark contrast to the folks who say that Rails is for prototypes,
|
||||||
|
there’s a lot of attention paid to long-lived engineering efforts -
|
||||||
|
adopting patterns that let many team work on the same ‘monolith’,
|
||||||
|
identifying [45]shotgun surgery - a term I first heard from Sandi Metz.
|
||||||
|
|
||||||
|
ActiveRecord is great, except when it isn’t
|
||||||
|
|
||||||
|
One of the hardest bugs we encountered happened with ActiveRecord. We
|
||||||
|
were creating a set of changes to apply to a model, using their
|
||||||
|
in-memory instances to do some stuff, and then finally applying them.
|
||||||
|
This broke because one of the ActiveRecord methods automatically
|
||||||
|
‘committed’ those changes, quietly.
|
||||||
|
|
||||||
|
ActiveRecord is kind of like this - a lot of the times it’s pleasantly
|
||||||
|
implicit, letting you just assign a value and automatically saving that
|
||||||
|
to the database. But then it’ll do something implicitly that you don’t
|
||||||
|
want to happen, and figuring out why this happened and how to stop it
|
||||||
|
from happening is a real challenge.
|
||||||
|
|
||||||
|
Most of the time, to be clear - it’s a really great system. It provides
|
||||||
|
lots of ways to generate efficient-enough queries, knowing full well
|
||||||
|
that SQL performance is often the bottleneck of web applications. Most
|
||||||
|
of the time it’s really nice that it automatically casts and
|
||||||
|
deserializes query results. But when it goes bad, the diagnosis and the
|
||||||
|
cure can be pretty ugly.
|
||||||
|
|
||||||
|
The other issue with ActiveRecord is that it has efficient methods and
|
||||||
|
inefficient methods right next to each other, because it automatically
|
||||||
|
turns your ‘query builder’ into an array when you call array-like
|
||||||
|
methods. So, for example:
|
||||||
|
Dogs.all.max_by(&:height)
|
||||||
|
|
||||||
|
Is wildly inefficient. It might fetch and deserialized a million
|
||||||
|
records just to sort them and give you the first. On the other hand,
|
||||||
|
Dogs.order(height: :desc).first
|
||||||
|
|
||||||
|
Is fast - it sorts in the database and fetches a single record. Rails
|
||||||
|
is both offering smart and easy ways to write optimized code, but also
|
||||||
|
making it really easy to write inefficient code.
|
||||||
|
__________________________________________________________________
|
||||||
|
|
||||||
|
A Rails-like framework is a really good thing to have in your toolbox,
|
||||||
|
and there’s a lot to learn from the Ruby community. My hope is that we
|
||||||
|
see these sorts of abstractions in new languages and frameworks, and
|
||||||
|
see more of the Ruby community’s culture filter into the programming
|
||||||
|
world.
|
||||||
|
|
||||||
|
February 18, 2021 [46]@tmcw
|
||||||
|
|
||||||
|
References
|
||||||
|
|
||||||
|
1. https://macwright.com/rss.xml
|
||||||
|
2. https://macwright.com/atom.xml
|
||||||
|
3. file:///
|
||||||
|
4. file:///reading/
|
||||||
|
5. file:///photos/
|
||||||
|
6. file:///projects/
|
||||||
|
7. file:///drawings/
|
||||||
|
8. file:///about/
|
||||||
|
9. https://rubyonrails.org/
|
||||||
|
10. https://nextjs.org/
|
||||||
|
11. https://www.rust-lang.org/
|
||||||
|
12. https://macwright.com/2020/05/10/spa-fatigue.html
|
||||||
|
13. http://boringtechnology.club/
|
||||||
|
14. https://macwright.com/2020/10/28/if-not-spas.html
|
||||||
|
15. https://twitter.com/tmcw/status/1321133460501585922
|
||||||
|
16. https://developers.google.com/web/updates/2015/05/automatically-pause-on-any-exception
|
||||||
|
17. https://www.html5rocks.com/en/tutorials/developertools/sourcemaps/
|
||||||
|
18. https://github.com/facebook/regenerator
|
||||||
|
19. https://github.com/deivid-rodriguez/byebug
|
||||||
|
20. https://github.com/fxn/zeitwerk
|
||||||
|
21. https://weblog.rubyonrails.org/2005/8/25/10-reasons-rails-does-pluralization/
|
||||||
|
22. https://nightwatchjs.org/
|
||||||
|
23. https://jestjs.io/
|
||||||
|
24. https://enzymejs.github.io/enzyme/
|
||||||
|
25. https://www.cypress.io/
|
||||||
|
26. https://rspec.info/
|
||||||
|
27. https://github.com/heartcombo/devise
|
||||||
|
28. http://www.passportjs.org/
|
||||||
|
29. https://sandimetz.com/
|
||||||
|
30. https://blog.arkency.com/
|
||||||
|
31. https://thoughtbot.com/blog/
|
||||||
|
32. https://codeclimate.com/
|
||||||
|
33. https://github.com/troessner/reek
|
||||||
|
34. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/padStart
|
||||||
|
35. https://rubygems.org/gems/activesupport/versions/6.1.1
|
||||||
|
36. https://kapeli.com/dash
|
||||||
|
37. https://developer.mozilla.org/en-US/
|
||||||
|
38. https://guides.rubyonrails.org/asset_pipeline.html
|
||||||
|
39. https://edgeguides.rubyonrails.org/webpacker.html
|
||||||
|
40. https://github.com/rails/webpacker#integrations
|
||||||
|
41. https://github.com/rails/rails/tree/main/actionview/app/assets/javascripts
|
||||||
|
42. https://en.wikipedia.org/wiki/Adele_Goldberg_(computer_scientist)
|
||||||
|
43. https://thoughtbot.com/blog/skinny-controllers-skinny-models
|
||||||
|
44. https://codeclimate.com/blog/7-ways-to-decompose-fat-activerecord-models/
|
||||||
|
45. https://en.wikipedia.org/wiki/Shotgun_surgery
|
||||||
|
46. https://twitter.com/intent/follow?screen_name=tmcw&user_id=1458271
|
||||||
150
static/archive/maggieappleton-com-7am49k.txt
Normal file
150
static/archive/maggieappleton-com-7am49k.txt
Normal file
@@ -0,0 +1,150 @@
|
|||||||
|
#[1]Main RSS Feed
|
||||||
|
|
||||||
|
[2]Home
|
||||||
|
The Garden (BUTTON)
|
||||||
|
[3]Now
|
||||||
|
[4]About
|
||||||
|
(BUTTON)
|
||||||
|
|
||||||
|
notes
|
||||||
|
|
||||||
|
evergreen
|
||||||
|
|
||||||
|
What App is That?
|
||||||
|
|
||||||
|
A guide to the apps and tools I use to create illustrations
|
||||||
|
* [5]How to Illustrate
|
||||||
|
|
||||||
|
Planted about 3 years agoLast tended about 2 years ago
|
||||||
|
|
||||||
|
(BUTTON) Back To Top
|
||||||
|
|
||||||
|
"What app is that?"
|
||||||
|
|
||||||
|
[6]
|
||||||
|
|
||||||
|
I'm a Promiscuous Polytooler
|
||||||
|
|
||||||
|
I use wide variety of different tools and apps for different kinds of
|
||||||
|
visual creations. I'm not wedded to any one tool in particular – they
|
||||||
|
all have their strengths and weaknesses. I'll use whatever fits the
|
||||||
|
task at hand and move work between them liberally.
|
||||||
|
|
||||||
|
Here's all the apps and hardware that might be involved in a particular
|
||||||
|
creation...
|
||||||
|
|
||||||
|
None of these are affiliate links - I'm just pointing you to official
|
||||||
|
sites for more context
|
||||||
|
[7]
|
||||||
|
|
||||||
|
Workflows
|
||||||
|
|
||||||
|
And here's a couple of my common workflows for different styles of
|
||||||
|
illustrations and visuals...
|
||||||
|
|
||||||
|
1. Illustrated notes
|
||||||
|
|
||||||
|
Anything I make that has a painterly and loose hand-drawn feel was made
|
||||||
|
in Procreate on the iPad or Photoshop on the Wacom Cintiq. Or probably
|
||||||
|
a combination – it's easy to move files back and forth between the two
|
||||||
|
and the tools they offer are very similar.
|
||||||
|
|
||||||
|
Illustrations like these...
|
||||||
|
|
||||||
|
Both of these applications allow you to draw in “raster” graphics,
|
||||||
|
meaning you paint pixels onto a canvas. They require a decent level of
|
||||||
|
hand-skills to make sure your lines aren't wobbly, although both
|
||||||
|
applications have smoothing features to help with that.
|
||||||
|
|
||||||
|
When I'm in Procreate I use a small selection of brushes I've gathered
|
||||||
|
over the years. It's hard for me to remember where they're all from,
|
||||||
|
and I've customised the majority of them to suit my personal prefs.
|
||||||
|
Most of them were originally from Max Ulichney's brushes. I have the
|
||||||
|
essentials set ($2), the painters set ($8), and the comics set ($15),
|
||||||
|
and can vouch they're all great.
|
||||||
|
|
||||||
|
I move these pieces to Photoshop if I want to work on a larger screen,
|
||||||
|
or have accidentally enlarged the canvas to a 14000px wide sprawling
|
||||||
|
set of sketches that Procreate can't open without crashing.
|
||||||
|
|
||||||
|
2. Polished vector illustrations
|
||||||
|
|
||||||
|
Illustrations that look more “polished” are made primarily in Adobe
|
||||||
|
Illustrator, with a touch of Photoshop at the end for lighting effects
|
||||||
|
and texture.
|
||||||
|
|
||||||
|
Pieces like these...
|
||||||
|
|
||||||
|
These illustrations are all vector-based, meaning we use mathematical
|
||||||
|
curves to define their shapes, rather than painted pixels. Vectors are
|
||||||
|
great for create hard, crisp edges and working with perfect geometric
|
||||||
|
forms.
|
||||||
|
|
||||||
|
While I love vectors for laying down the foundation shapes of these,
|
||||||
|
I'll move them over the Photoshop once they're 90% done to adjust the
|
||||||
|
colors, add more subtlety to the lighting and shadows, and chuck a bit
|
||||||
|
of texture on the top so they feel more tangible.
|
||||||
|
|
||||||
|
Want to share? (BUTTON) Tell Twitter About It
|
||||||
|
|
||||||
|
3 Backlinks
|
||||||
|
|
||||||
|
Why You Own an iPad and Still Can't Draw
|
||||||
|
|
||||||
|
The failure of drawing materials without mediums and meat
|
||||||
|
|
||||||
|
Frequently Asked Questions
|
||||||
|
|
||||||
|
Questions I am often asked to answer
|
||||||
|
|
||||||
|
The Best Illustration Books and Courses
|
||||||
|
|
||||||
|
My favourite resources for learning to draw and developing your visual
|
||||||
|
thinking skills
|
||||||
|
|
||||||
|
Mentions around the web
|
||||||
|
|
||||||
|
Tomiwa 😃
|
||||||
|
Maggie Appleton - indieweb.social/@maggie
|
||||||
|
2 Likes and Retweets
|
||||||
|
|
||||||
|
Want to stay up to date?
|
||||||
|
|
||||||
|
(BUTTON) Subscribe via RSS Feed
|
||||||
|
© 2023 Maggie Appleton
|
||||||
|
* [8]The Garden
|
||||||
|
* [9]Essays
|
||||||
|
* [10]About
|
||||||
|
* [11]Notes
|
||||||
|
* [12]Now
|
||||||
|
* [13]Patterns
|
||||||
|
* [14]Library
|
||||||
|
* [15]Projects
|
||||||
|
* [16]Colophon
|
||||||
|
|
||||||
|
References
|
||||||
|
|
||||||
|
Visible links:
|
||||||
|
1. file:///rss.xml
|
||||||
|
2. file:///
|
||||||
|
3. file:///now
|
||||||
|
4. file:///about
|
||||||
|
5. file:///topics/how-to-illustrate
|
||||||
|
6. file:///var/folders/q9/qlz2w5251kzdfgn0np7z2s4c0000gn/T/L71674-9587TMP.html#im-a-promiscuous-polytooler
|
||||||
|
7. file:///var/folders/q9/qlz2w5251kzdfgn0np7z2s4c0000gn/T/L71674-9587TMP.html#workflows
|
||||||
|
8. file:///garden
|
||||||
|
9. file:///essays
|
||||||
|
10. file:///about
|
||||||
|
11. file:///notes
|
||||||
|
12. file:///now
|
||||||
|
13. file:///patterns
|
||||||
|
14. file:///library
|
||||||
|
15. file:///projects
|
||||||
|
16. file:///colophon
|
||||||
|
|
||||||
|
Hidden links:
|
||||||
|
18. https://github.com/MaggieAppleton
|
||||||
|
19. https://uk.linkedin.com/in/maggieappleton
|
||||||
|
20. https://dribbble.com/mappleton
|
||||||
|
21. https://twitter.com/Mappletons
|
||||||
|
22. https://indieweb.social/@maggie
|
||||||
135
static/archive/maggieappleton-com-fube9k.txt
Normal file
135
static/archive/maggieappleton-com-fube9k.txt
Normal file
@@ -0,0 +1,135 @@
|
|||||||
|
#[1]Main RSS Feed
|
||||||
|
|
||||||
|
[2]Home
|
||||||
|
The Garden (BUTTON)
|
||||||
|
[3]Now
|
||||||
|
[4]About
|
||||||
|
(BUTTON)
|
||||||
|
|
||||||
|
Essays
|
||||||
|
|
||||||
|
budding
|
||||||
|
|
||||||
|
Why You Own an iPad and Still Can't Draw
|
||||||
|
|
||||||
|
The failure of drawing materials without mediums and meat
|
||||||
|
* [5]How to Illustrate
|
||||||
|
|
||||||
|
Planted almost 3 years agoLast tended almost 3 years ago
|
||||||
|
|
||||||
|
(BUTTON) Back To Top
|
||||||
|
|
||||||
|
Assumed Audience
|
||||||
|
|
||||||
|
Anyone who thinks they can't draw, but would like to learn
|
||||||
|
|
||||||
|
They message me a lot.
|
||||||
|
|
||||||
|
Which iPad should I buy? What app do you use? What brush is that?
|
||||||
|
What size should my canvas be?
|
||||||
|
|
||||||
|
These questions aren't wrong. In fact they're perfectly reasonable.
|
||||||
|
|
||||||
|
I'm vocal about the fact many of my illustrations are made on in an app
|
||||||
|
called . I have a full post about my drawing equipment and workflows
|
||||||
|
over at
|
||||||
|
[6]What App is That?
|
||||||
|
|
||||||
|
How are you supposed to draw if you don't also have these fancy tools?
|
||||||
|
|
||||||
|
This is the tricky bit.
|
||||||
|
|
||||||
|
If you go out and buy yourself these same things, you'll have all the
|
||||||
|
right materials to draw. But that's only the dressing on the drawing
|
||||||
|
dish.
|
||||||
|
[7]
|
||||||
|
|
||||||
|
What you have is Material without the Medium or the Meat
|
||||||
|
|
||||||
|
What on earth do I mean by material, medium, and meat?
|
||||||
|
__________________________________________________________________
|
||||||
|
|
||||||
|
[8]
|
||||||
|
|
||||||
|
Moving past materials
|
||||||
|
|
||||||
|
Worrying about the materials should take up - at most - 10% of your
|
||||||
|
attention and concern. Focus 70% of your attention on learning the
|
||||||
|
medium while you're just starting out.
|
||||||
|
|
||||||
|
You can keep 20% of your focus on the Meat. But I wouldn't worry too
|
||||||
|
much about communicating original, profound ideas at first. Doing so in
|
||||||
|
addition to learning a whole new language is going to be overwhelming.
|
||||||
|
|
||||||
|
In the same way it's a bad idea to learn Spanish while simultaneously
|
||||||
|
trying to write a philosophy dissertation in it.
|
||||||
|
|
||||||
|
Once you get more comfortable “speaking" in visual language, you'll be
|
||||||
|
able to shift a much higher percentage of your attention onto the Meat.
|
||||||
|
You'll get to focus on The Thing You Want to Say, and know enough
|
||||||
|
visual language to say it well.
|
||||||
|
|
||||||
|
That's the ideal I'm currently striving for. To reach a point where the
|
||||||
|
Material is irrelevant, the Medium is a baked into my subconscious, and
|
||||||
|
I'm all about the Meat.
|
||||||
|
|
||||||
|
That's the goal. Don't let the shiny iPad reflection blind you.
|
||||||
|
|
||||||
|
Get past picking the Material. Focus on the Medium. Aim for the Meat.
|
||||||
|
|
||||||
|
Want to share? (BUTTON) Tell Twitter About It
|
||||||
|
|
||||||
|
1 Backlinks
|
||||||
|
|
||||||
|
The Best Illustration Books and Courses
|
||||||
|
|
||||||
|
My favourite resources for learning to draw and developing your visual
|
||||||
|
thinking skills
|
||||||
|
|
||||||
|
Mentions around the web
|
||||||
|
|
||||||
|
Tomiwa 😃
|
||||||
|
Maggie Appleton - indieweb.social/@maggie
|
||||||
|
2 Likes and Retweets
|
||||||
|
|
||||||
|
Want to stay up to date?
|
||||||
|
|
||||||
|
(BUTTON) Subscribe via RSS Feed
|
||||||
|
© 2023 Maggie Appleton
|
||||||
|
* [9]The Garden
|
||||||
|
* [10]Essays
|
||||||
|
* [11]About
|
||||||
|
* [12]Notes
|
||||||
|
* [13]Now
|
||||||
|
* [14]Patterns
|
||||||
|
* [15]Library
|
||||||
|
* [16]Projects
|
||||||
|
* [17]Colophon
|
||||||
|
|
||||||
|
References
|
||||||
|
|
||||||
|
Visible links:
|
||||||
|
1. file:///rss.xml
|
||||||
|
2. file:///
|
||||||
|
3. file:///now
|
||||||
|
4. file:///about
|
||||||
|
5. file:///topics/how-to-illustrate
|
||||||
|
6. file:///apps
|
||||||
|
7. file:///var/folders/q9/qlz2w5251kzdfgn0np7z2s4c0000gn/T/L84552-9249TMP.html#what-you-have-is-material-without-the-medium-or-the-meat
|
||||||
|
8. file:///var/folders/q9/qlz2w5251kzdfgn0np7z2s4c0000gn/T/L84552-9249TMP.html#moving-past-materials
|
||||||
|
9. file:///garden
|
||||||
|
10. file:///essays
|
||||||
|
11. file:///about
|
||||||
|
12. file:///notes
|
||||||
|
13. file:///now
|
||||||
|
14. file:///patterns
|
||||||
|
15. file:///library
|
||||||
|
16. file:///projects
|
||||||
|
17. file:///colophon
|
||||||
|
|
||||||
|
Hidden links:
|
||||||
|
19. https://github.com/MaggieAppleton
|
||||||
|
20. https://uk.linkedin.com/in/maggieappleton
|
||||||
|
21. https://dribbble.com/mappleton
|
||||||
|
22. https://twitter.com/Mappletons
|
||||||
|
23. https://indieweb.social/@maggie
|
||||||
1069
static/archive/softwarecrisis-dev-7c7z9g.txt
Normal file
1069
static/archive/softwarecrisis-dev-7c7z9g.txt
Normal file
File diff suppressed because it is too large
Load Diff
191
static/archive/taylor-town-5siv9a.txt
Normal file
191
static/archive/taylor-town-5siv9a.txt
Normal file
@@ -0,0 +1,191 @@
|
|||||||
|
[1]taylor.town
|
||||||
|
|
||||||
|
[2]about [3]now [4]hire [5]rss [6]spam
|
||||||
|
|
||||||
|
cloaca maxima
|
||||||
|
|
||||||
|
When to Build Millennia Sewers
|
||||||
|
|
||||||
|
In the mid-1800s, [7]every building in central Chicago was raised 10ft
|
||||||
|
(30m). Yes, they literally used [8]jackscrews to lift entire city
|
||||||
|
blocks up one-by-one.
|
||||||
|
|
||||||
|
Chicago had to [9]hotfix production because they built the city on the
|
||||||
|
shoreline of Lake Michigan, where filth accumulated without natural
|
||||||
|
drainage. They lifted the entire city after it was built so they could
|
||||||
|
add sewers and prevent flooding.
|
||||||
|
|
||||||
|
For comparison, Rome’s [10]Cloaca Maxima (“Greatest Sewer”) is still
|
||||||
|
in-use after 2,400 years.
|
||||||
|
|
||||||
|
So why didn’t Chicago just build it right the first time?
|
||||||
|
* [11]Irreversible Decisions
|
||||||
|
* [12]Unintended vs. Unforeseen
|
||||||
|
* [13]Always Scale Down
|
||||||
|
* [14]Labor & Materials
|
||||||
|
* [15]Awful Architecture
|
||||||
|
|
||||||
|
Irreversible Decisions
|
||||||
|
|
||||||
|
Some decisions are consequential and irreversible or nearly
|
||||||
|
irreversible – one-way doors – and these decisions must be made
|
||||||
|
methodically, carefully, slowly, with great deliberation and
|
||||||
|
consultation. If you walk through and don’t like what you see on the
|
||||||
|
other side, you can’t get back to where you were before. We can call
|
||||||
|
these Type 1 decisions. But most decisions aren’t like that – they
|
||||||
|
are changeable, reversible – they’re two-way doors. If you’ve made a
|
||||||
|
suboptimal Type 2 decision, you don’t have to live with the
|
||||||
|
consequences for that long. You can reopen the door and go back
|
||||||
|
through. Type 2 decisions can and should be made quickly by high
|
||||||
|
judgment individuals or small groups.
|
||||||
|
|
||||||
|
As organizations get larger, there seems to be a tendency to use the
|
||||||
|
heavy-weight Type 1 decision-making process on most decisions,
|
||||||
|
including many Type 2 decisions. The end result of this is slowness,
|
||||||
|
unthoughtful risk aversion, failure to experiment sufficiently, and
|
||||||
|
consequently diminished invention. We’ll have to figure out how to
|
||||||
|
fight that tendency.
|
||||||
|
|
||||||
|
– [16]Jeff Bezos
|
||||||
|
|
||||||
|
The Cloaca Maxima didn’t magically start out as the Greatest Sewer. It
|
||||||
|
began as an open-air canal, then was modified and renovated and
|
||||||
|
connected to the aqueducts.
|
||||||
|
|
||||||
|
The Romans probably made mistakes, but they didn’t make any wrong
|
||||||
|
irreversible decisions. To build something that lasts, make sure the
|
||||||
|
architecture is correct where it counts.
|
||||||
|
|
||||||
|
The Chicago sewage disaster was technically reversible, but extremely
|
||||||
|
expensive and painful.
|
||||||
|
|
||||||
|
Put “wiggle-room” in your architecture. Plan for repairs. Add
|
||||||
|
backdoors, engine-hoods, seams, and spaces. Emergency plans are
|
||||||
|
generally cheap to include in early phases of design.
|
||||||
|
|
||||||
|
Unintented vs. Unforeseen
|
||||||
|
|
||||||
|
[17]Exxon executives knew that CO₂ emissions would harm Earth.
|
||||||
|
|
||||||
|
Exxon willfully ignored its own research. Climate change was unintended
|
||||||
|
but not unforeseen.
|
||||||
|
|
||||||
|
Prophets are silenced when apocalypses seem bad for business.
|
||||||
|
|
||||||
|
But remember – all apocalypses are opportunities for entrepeneurship.
|
||||||
|
Exxon could’ve made billions by diversifying themselves with renewable
|
||||||
|
energy. They acted against their own self-interest by ignoring their
|
||||||
|
facts.
|
||||||
|
|
||||||
|
To prevent long-term disaster, solve the hard problem of aligning
|
||||||
|
incentives. Build systems so that all constituents predict and prevent
|
||||||
|
impending doom.
|
||||||
|
|
||||||
|
Transparency thwarts [18]own goals. It’s difficult to do stupid things
|
||||||
|
when you do stupid things publicly.
|
||||||
|
|
||||||
|
Always Scale Down
|
||||||
|
|
||||||
|
There’s really two ways to design things. You can either sort of
|
||||||
|
start with small things and scale them up or you could start with
|
||||||
|
big things and scale them down…
|
||||||
|
|
||||||
|
So suppose you want to build a system for like 10,000 people to use
|
||||||
|
simultaneously. One way of doing it would be to start with the
|
||||||
|
system, design it for 10 people and test it like that and scale it
|
||||||
|
up 10,000. The other way would be to design it for like 100,000,000
|
||||||
|
people – I mean do the design for that – and then scale it down to
|
||||||
|
tens of thousands. You might not get the same architecture. You
|
||||||
|
might get a completely different architecture. In fact, you would
|
||||||
|
get a different architecture.
|
||||||
|
|
||||||
|
And I think it’s a really bad idea to start at a design for 10 or
|
||||||
|
100 things and scale it up. It’s better to start with an
|
||||||
|
architecture that you know will work for a few trillion things and
|
||||||
|
scale it down. It will actually be less efficient when you’ve got
|
||||||
|
your 10,000 things than when you scaled up, but you’ll know that
|
||||||
|
you’ll be able to scale it up later. So it’s good.
|
||||||
|
|
||||||
|
So rather than ask, “how do we get to five nines?”, let’s make it
|
||||||
|
more interesting! Let’s start at 9,999 nines reliability and scale
|
||||||
|
it down.
|
||||||
|
|
||||||
|
– Joe Armstrong from [19]Systems that run forever and self-heal and
|
||||||
|
scale
|
||||||
|
|
||||||
|
If you can afford it, throw a few extra zeroes on your designs.
|
||||||
|
|
||||||
|
Labor & Materials
|
||||||
|
|
||||||
|
Carefully compare lifetime, labor, and materials.
|
||||||
|
|
||||||
|
lifetime repair labor materials
|
||||||
|
asphalt 20 years moderate $ $
|
||||||
|
concrete 30 years difficult $ $$
|
||||||
|
stone 100+ years easy $$$$ $$$
|
||||||
|
|
||||||
|
Pay particular attention to labor – 9 women can’t make a baby in 1
|
||||||
|
month.
|
||||||
|
|
||||||
|
Exercise for the reader: Which is cheaper, a Nespresso machine or a
|
||||||
|
[20]percolator?
|
||||||
|
|
||||||
|
Awful Architecture
|
||||||
|
|
||||||
|
Sometimes there are no tradeoffs.
|
||||||
|
|
||||||
|
Some decisions are awful in every dimension.
|
||||||
|
|
||||||
|
[21]Dvorak keyboards reduce finger fatigue using the same materials as
|
||||||
|
QWERTY keyboards.
|
||||||
|
|
||||||
|
[22]Juicero famously launched a high-tech product that was inferior to
|
||||||
|
traditional juicers [23]in every comparable way:
|
||||||
|
|
||||||
|
After taking apart the device, venture capitalist Ben Einstein
|
||||||
|
considered the press to be “an incredibly complicated piece of
|
||||||
|
engineering”, but that the complexity was unnecessary and likely
|
||||||
|
arose from a lack of cost constraints during the design process. A
|
||||||
|
simpler and cheaper implementation, suggested Einstein, would likely
|
||||||
|
have produced much the same quality of juice at a price several
|
||||||
|
hundred dollars cheaper.
|
||||||
|
|
||||||
|
If you want to create lasting sewers, study sewer architecture and its
|
||||||
|
impacts. What do good sewers have in common? What do bad sewers look
|
||||||
|
like? What tradeoffs exist with sewage systems? Are there any
|
||||||
|
promising-yet-untested sewer designs? Why do sewers go into disrepair?
|
||||||
|
What societal factors prevent sewers from being made in the first
|
||||||
|
place? Who truly controls the sewers?
|
||||||
|
|
||||||
|
Great architects think ahead, but don’t let ambitions run amok. They
|
||||||
|
anticipate irreversible changes and second-order effects. They consider
|
||||||
|
all the costs – labor and materials and maintenance and environmental
|
||||||
|
impact. They always stay ahead-of-schedule and within their budget. And
|
||||||
|
despite the overwhelming constraints, great architects build millennia
|
||||||
|
sewers whenever and wherever they can.
|
||||||
|
|
||||||
|
References
|
||||||
|
|
||||||
|
1. file:///
|
||||||
|
2. file:///about
|
||||||
|
3. file:///now
|
||||||
|
4. file:///hire-me
|
||||||
|
5. file:///feed.xml
|
||||||
|
6. https://newsletter.taylor.town/
|
||||||
|
7. https://en.wikipedia.org/wiki/Raising_of_Chicago
|
||||||
|
8. https://en.wikipedia.org/wiki/Jack_(device)#House_jack
|
||||||
|
9. https://www.reddit.com/r/ProgrammerHumor/comments/blhec6/fixing_bugs_in_production/
|
||||||
|
10. https://en.wikipedia.org/wiki/Cloaca_Maxima
|
||||||
|
11. file:///var/folders/q9/qlz2w5251kzdfgn0np7z2s4c0000gn/T/L81887-9224TMP.html#irreversible
|
||||||
|
12. file:///var/folders/q9/qlz2w5251kzdfgn0np7z2s4c0000gn/T/L81887-9224TMP.html#unintended
|
||||||
|
13. file:///var/folders/q9/qlz2w5251kzdfgn0np7z2s4c0000gn/T/L81887-9224TMP.html#scale-down
|
||||||
|
14. file:///var/folders/q9/qlz2w5251kzdfgn0np7z2s4c0000gn/T/L81887-9224TMP.html#labor-materials
|
||||||
|
15. file:///var/folders/q9/qlz2w5251kzdfgn0np7z2s4c0000gn/T/L81887-9224TMP.html#awful
|
||||||
|
16. https://www.sec.gov/Archives/edgar/data/1018724/000119312516530910/d168744dex991.htm
|
||||||
|
17. https://en.wikipedia.org/wiki/ExxonMobil_climate_change_denial
|
||||||
|
18. https://en.wikipedia.org/wiki/Own_goal
|
||||||
|
19. https://www.youtube-nocookie.com/embed/cNICGEwmXLU?start=433
|
||||||
|
20. https://en.wikipedia.org/wiki/Coffee_percolator
|
||||||
|
21. https://en.wikipedia.org/wiki/Dvorak_keyboard_layout
|
||||||
|
22. https://en.wikipedia.org/wiki/Juicero
|
||||||
|
23. https://en.wikipedia.org/wiki/Juicero#Criticism
|
||||||
142
static/archive/timharek-no-ah7ilz.txt
Normal file
142
static/archive/timharek-no-ah7ilz.txt
Normal file
@@ -0,0 +1,142 @@
|
|||||||
|
[1]Skip to content
|
||||||
|
* [2]Blog
|
||||||
|
* [3]Connect
|
||||||
|
* [4]About
|
||||||
|
|
||||||
|
* [5]Index
|
||||||
|
* [6]Blog
|
||||||
|
* My thoughts on Helix after 6 months
|
||||||
|
|
||||||
|
My thoughts on Helix after 6 months
|
||||||
|
|
||||||
|
Published June 19, 2023 — 3 minute read
|
||||||
|
Photo of Tim Hårek Andreassen Tim Hårek Andreassen
|
||||||
|
|
||||||
|
Back in [7]January I decided to try out Helix as my primary editor and
|
||||||
|
today I have almost been using it for 6 months and these are my
|
||||||
|
thoughts.
|
||||||
|
|
||||||
|
[8]# What I like
|
||||||
|
|
||||||
|
[9]# Keystrokes
|
||||||
|
|
||||||
|
Helix lives in the opposite land when it comes to keystrokes in
|
||||||
|
comparison to Vim, and it was only difficult for the first couple of
|
||||||
|
days. I’ve become fond of the way to navigate around.
|
||||||
|
|
||||||
|
[10]# Minor modes
|
||||||
|
|
||||||
|
I really like that there are more modes, called [11]“Minor modes”, and
|
||||||
|
the reason why I like them are that whenever I initate a mode there is
|
||||||
|
a subtle pop-up in the lower-right corner with the available actions
|
||||||
|
with the activated mode. This is super helpful when you are first
|
||||||
|
learning Helix and when you are doing something you don’t do on a
|
||||||
|
regular basis. It lowers the chance of having to switch context in
|
||||||
|
order to do something. For instance, I know that m activates “Match
|
||||||
|
mode”, but sometimes I may forget how to select around specific
|
||||||
|
selector like (), but with Helix I will have a little helper that tells
|
||||||
|
me that the next key is a and then the next helper will help me select
|
||||||
|
just ().
|
||||||
|
|
||||||
|
[12]# Moving around
|
||||||
|
|
||||||
|
I’ve become really fond of the idea that every move-action is also a
|
||||||
|
selection/highlight, I find that I miss that feature whenever I edit
|
||||||
|
server-configs via SSH or somewhere else when I’m not in Helix. It
|
||||||
|
feels natural after a while because you get used to moving around
|
||||||
|
text/code with w and e.
|
||||||
|
|
||||||
|
[13]# Configuration
|
||||||
|
|
||||||
|
No more Vimscript and Lua, just plaintext TOML! The documentation for
|
||||||
|
how to configure the editor is great and most of the defaults are also
|
||||||
|
great! My editor-config is just 23 lines in contrast to my
|
||||||
|
Neovim-config which is 209 lines long.
|
||||||
|
|
||||||
|
[14]# Language server protocol (LSP) support
|
||||||
|
|
||||||
|
I had some experience with this from Neovim, but it felt cumbersome
|
||||||
|
having to configure everything. With Helix I can simply run hx --health
|
||||||
|
markdown and see what LSP is required for Markdown.
|
||||||
|
$ hx --health markdown
|
||||||
|
Configured language server: marksman
|
||||||
|
Binary for language server: /opt/homebrew/bin/marksman
|
||||||
|
Configured debug adapter: None
|
||||||
|
Highlight queries: ✓
|
||||||
|
Textobject queries: ✘
|
||||||
|
Indent queries: ✘
|
||||||
|
|
||||||
|
I even managed to get it working with Deno thanks to its documentation
|
||||||
|
on how to use custom LSPs for specific languages.
|
||||||
|
|
||||||
|
[15]# What I don’t like
|
||||||
|
|
||||||
|
There really isn’t anything in particualr that I don’t like about
|
||||||
|
Helix. I really miss having it installed on servers by default, but I
|
||||||
|
completely understand that that is a big ask 😅 It’s not too difficult
|
||||||
|
to swap between Vim-bindings and Helix-bindings for short sessions.
|
||||||
|
|
||||||
|
[16]# Conclusion
|
||||||
|
|
||||||
|
Helix is fun and easy! I highly recommend Helix if you:
|
||||||
|
* want to try a new editor,
|
||||||
|
* tired of configuring {Neo}vim with Vimscript/Lua,
|
||||||
|
* or been thinking about trying out Vim, but been hesitant because of
|
||||||
|
the modes.
|
||||||
|
|
||||||
|
I will continue to use Helix for the forseeable future, I’m looking
|
||||||
|
forward to what future updates will bring!
|
||||||
|
|
||||||
|
Remember to check out Helix’s tutor, hx --tutor for quick introduction
|
||||||
|
to its keystrokes and interactions.
|
||||||
|
|
||||||
|
Tagged with [17]100 days to
|
||||||
|
offload[18]helix[19]software[20]thoughts[21]tools
|
||||||
|
540 words
|
||||||
|
[22]Reply via e-mail
|
||||||
|
|
||||||
|
Also mentioned in
|
||||||
|
|
||||||
|
* [23]June 2023
|
||||||
|
|
||||||
|
Last deploy: 2023-07-02 11:14 UTC
|
||||||
|
|
||||||
|
* [24]Stats
|
||||||
|
* [25]Privacy
|
||||||
|
* [26]Sitemap
|
||||||
|
* [27]RSS
|
||||||
|
|
||||||
|
References
|
||||||
|
|
||||||
|
Visible links:
|
||||||
|
1. file:///var/folders/q9/qlz2w5251kzdfgn0np7z2s4c0000gn/T/L71669-427TMP.html#main
|
||||||
|
2. https://timharek.no/blog/
|
||||||
|
3. https://timharek.no/connect/
|
||||||
|
4. https://timharek.no/about/
|
||||||
|
5. https://timharek.no/
|
||||||
|
6. https://timharek.no/blog/
|
||||||
|
7. https://timharek.no/blog/trying-helix/
|
||||||
|
8. file:///var/folders/q9/qlz2w5251kzdfgn0np7z2s4c0000gn/T/L71669-427TMP.html#what-i-like
|
||||||
|
9. file:///var/folders/q9/qlz2w5251kzdfgn0np7z2s4c0000gn/T/L71669-427TMP.html#keystrokes
|
||||||
|
10. file:///var/folders/q9/qlz2w5251kzdfgn0np7z2s4c0000gn/T/L71669-427TMP.html#minor-modes
|
||||||
|
11. https://docs.helix-editor.com/keymap.html#normal-mode
|
||||||
|
12. file:///var/folders/q9/qlz2w5251kzdfgn0np7z2s4c0000gn/T/L71669-427TMP.html#moving-around
|
||||||
|
13. file:///var/folders/q9/qlz2w5251kzdfgn0np7z2s4c0000gn/T/L71669-427TMP.html#configuration
|
||||||
|
14. file:///var/folders/q9/qlz2w5251kzdfgn0np7z2s4c0000gn/T/L71669-427TMP.html#language-server-protocol-lsp-support
|
||||||
|
15. file:///var/folders/q9/qlz2w5251kzdfgn0np7z2s4c0000gn/T/L71669-427TMP.html#what-i-don-t-like
|
||||||
|
16. file:///var/folders/q9/qlz2w5251kzdfgn0np7z2s4c0000gn/T/L71669-427TMP.html#conclusion
|
||||||
|
17. https://timharek.no/tags/100-days-to-offload/
|
||||||
|
18. https://timharek.no/tags/helix/
|
||||||
|
19. https://timharek.no/tags/software/
|
||||||
|
20. https://timharek.no/tags/thoughts/
|
||||||
|
21. https://timharek.no/tags/tools/
|
||||||
|
22. mailto:tim@harek.no?subject=RE: My thoughts on Helix after 6 months
|
||||||
|
23. https://timharek.no/blog/2023-june-recently/
|
||||||
|
24. https://timharek.no/stats/
|
||||||
|
25. https://timharek.no/privacy/
|
||||||
|
26. https://timharek.no/sitemap/
|
||||||
|
27. https://timharek.no/rss.xml
|
||||||
|
|
||||||
|
Hidden links:
|
||||||
|
29. https://timharek.no/
|
||||||
|
30. https://timharek.no/blog/my-thoughts-on-helix-after-6-months/
|
||||||
@@ -49,6 +49,12 @@ ul {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ol {
|
||||||
|
margin-left: 3ch;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
blockquote {
|
blockquote {
|
||||||
border-left: 1ch solid #ddd;
|
border-left: 1ch solid #ddd;
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
@@ -70,6 +76,7 @@ footer {
|
|||||||
|
|
||||||
sup {
|
sup {
|
||||||
line-height: 0;
|
line-height: 0;
|
||||||
|
font-size: 0.8em;
|
||||||
}
|
}
|
||||||
|
|
||||||
figure {
|
figure {
|
||||||
@@ -90,7 +97,7 @@ figure {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.references {
|
.references, .footnotes {
|
||||||
font-size: 0.8em;
|
font-size: 0.8em;
|
||||||
|
|
||||||
h3 {
|
h3 {
|
||||||
|
|||||||
Reference in New Issue
Block a user