Multimedia particles in the style of a tweet, also serving as a changelog to consolidate changes elsewhere in the site. Cross-posted to an atom feed. Frequently off topic.

Published fragment Prepared statements for psql operations, on using prepared statements with operational queries to make it easy to replace parameters and save time.

PREPARE add_flag_to_team(text, uuid) AS INSERT INTO flag_team (
    (SELECT id FROM flag WHERE name = $1),

EXECUTE add_flag_to_team('<flag_name>', '<team_id>');

As I was untangling my Amazon/AWS credentials last night, I did something that I don’t do often, and looked at the details of my AWS bill.

The total cost of hosting this site for January: $3.08. That doesn’t seem like a bad deal, but digging in a little, it turned out I was overpaying.

Of $3.08, $3.07 was for S3 (I was mildly surprised to see that all my CloudFront use fits in the free tier). And of that, $2.15 was for PUT, COPY, POST, or LIST requests on this site’s bucket. The GETs used to actually serve the site are cheaper, and added up to only $0.39.

The S3 lists and mutations are generated from the build process, which from a GitHub Action syncs the built product with S3. The majority of builds are automated on cron – some parts of the site like reading or twitter ingested data from the Goodreads and Twitter APIs, so I’d had the site building every three hours to pick up changes.

But over the last year, both those APIs have experienced unceremonious deaths, reducing the dynamic content on this site to zero. All relevant changes are now pushed through Git, leaving the cron schedule a vestige of better times.

I reduced the cron frequency from three hours to three days (still a good idea to check periodically that the build still works), which should have the effect of bringing that $2.15 down by an order of magnitude.

Saving $2 this way was certainly not worth the time (that’s about 1/3rd of a single San Francisco coffee these days), but hey, it’s fun.

A Go 1.21 feature that I’d previously missed: toolchains. A toolchain consists of a bundled compiler, assembler, and set of standard Go tooling. An installed go command has a bundled toolchain, but is capable of fetching other ones as necessary.

Today, to upgrade my project to Go 1.22, all I had to do was change one line in go.mod:

$ git diff
diff --git a/go.mod b/go.mod
index 49a960839..f1b3ff857 100644
--- a/go.mod
+++ b/go.mod
@@ -11,7 +11,7 @@


-go 1.21
+go 1.22.0

The next Go command I ran detected the absence of Go 1.22, and downloaded it, producing the most streamlined upgrade path of all time.

$ go version
go version go1.22.0 darwin/arm64

Published fragment Thoughts on ONCE + Campire, on ONCE’s $299 self-hosted Basecamp. Is a web app for chat fine nowadays?

A tweet:

typing is the secret to using the computer. if you’re not typing, you should be clicking on stuff. if you’re scrolling, then it’s already over… you’re not doing shit

A little brash on the surface, but a font of wisdom below. If you’re on a computer scrolling, nothing useful is happening. Best to stop using said computer and go do something better.

Published fragment Hard media, on the disapperance of physical media and the overabundance of its digital counterpart.

Running 2023

2023 was an odd fitness year for me, simultaneously being one of victory and of defeat. I did some of my best running distance ever, finishing just over 1,700 km, but still ended the year heavy. A clear indicator that nutrition is at least as important as exercise.

I started a daily running streak going into France, and hit 163 consecutive days before it ended with my trip to the John Muir Trail. This was a great habit – wanting to keep the streak going, I’d be out there every day rain or shine, even when I hated it. There was a moment where I arrived in Berlin late in the evening, exhausted from three days of long distance travel, but still, like every other day, dragged myself to the door, put on my running shoes, and ran around in the dark until I hit my 5 km minimum. Running is such a great way to see Europe. By the end of my stay in any place – Paris, London, Bath, York, Berlin – I’d have multiple routes figured out and strong opinions on which were the best. Europe’s a crowded place, so I’d wake up as early as I could, often starting before the sun was out. Getting my run done early also improved the chances that it’d get done at all.

Takeaways for 2024: Habit streaks work, early is better than late, and without nutrition, fitness is only half of the whole.

Published sequence 072, Prairie ridgeline.

SQLite’s Wal2 mode was new to me. Added for high throughput systems to resolve a problem where if a wal file was being continuously written to with new changes, SQLite’s checkpointer could never fully finish its work, and therefore the wal file could grow unbounded.

Wal2 fixes the problem by juggling two wal files which its writer and checkpointer alternate between:

In wal2 mode, the system uses two wal files instead of one. The files are named “[database]-wal” and “[database]-wal2”, where “[database]” is of course the name of the database file. When data is written to the database, the writer begins by appending the new data to the first wal file. Once the first wal file has grown large enough, writers switch to appending data to the second wal file. At this point the first wal file can be checkpointed (after which it can be overwritten). Then, once the second wal file has grown large enough and the first wal file has been checkpointed, writers switch back to the first wal file. And so on.

Published fragment Discovering histograms, kicking off metric rollups, on a blog post explaining aggregating aggregates doesn’t work, and using histograms to do the job instead. It’s a modest effort, but it’s something to kick off writing for 2024.

Goodhart’s law:

When a measure becomes a target, it ceases to be a good measure.

The Christmas tree this year. Mom and Dad have been using a real tree for four decades, but with the help of an attractive sale from Costco, this is finally the year they switched to artificial. There’s nothing quite like the smell of an honest-to-God tree on Christmas morning, but these days the fake ones are gorgeous, and win hands down practicality wise with no cleanup and built-in lights.

Follow up from yesterday: dumped Goodreads immediately after realizing out that it was not only returning missing information for newly read books, but was tainting my existing archives as records of previously read books started returning corrupted records as well.

My book list is now a flat file in TOML instead. More robust, but it’s a shame how one by one, every third party API this site used to ingest for aggregation has disappeared – Goodreads was the last one standing, and it’s gone.

Archive ⭢