brandur.org

Atoms

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.

Hetzner is launching a new Object Storage storage on November 1st, aimed squarely at competing with S3 (and is S3 API compatible). Their pricing page is quite verbose, so here’s a summary by my interpretation:

Storage Transfer out Operations
AWS
  • $0.023/GB (tier up to 50 TB) = $23/TB/mo
  • First 100 GB: Free
  • After 100 GB: $0.09/GB (tier up to 10 TB) = $90/TB (!!!)
  • $0.005 per 1k PUT, COPY, POST, LIST requests
  • $0.0004 per 1k GET, SELECT requests
Hetzner
  • First TB: €5/mo = $5.44/TB/mo
  • After 1 TB: €0.0067/TB-hour = 31 * €0.0067 = €4.9848 =~ $5.42/TB/mo
  • First 1 TB: Free
  • After 1 TB: €1/TB = $1.09/TB
  • Free

Observations:

  • The price difference in storage is night and day, with Hetzner’s service less than 14 of the price of Amazon.
  • It’s even more stark for transfer out. At $90/TB, Amazon basically owns your data once it’s in their data center. Hetzner’s price is 1/90th AWS’ with a 10x more generous free tier.
  • No per-operation cost is huge. While reviewing my own S3 costs earlier this year, I was surprised to find that 85% of my bill was per-operation cost.
  • Hetzner storage price above assumes a 31 day month. It’s a bit cheaper for shorter months.
  • Hetzner storage prices are measured in TB, but fractional, and charged in increments of 100 MB.
  • Hetzner prices don’t include VAT. Hetzner’s VAT logic is incredibly complex, but you aren’t charged VAT in the USA unless you’re in Arizona, Colorado, New Mexico, Texas, or Utah.
  • On the other hand, Hetzner has a single eu-central region, so US-based customers will have to deal with speed-of-light latency.

On the face of it, pretty exciting. An optimistic premise of major cloud providers like AWS is that as they reduced their own operation costs through economies of scale, some of those savings would be passed down to us, but we’ve seen over the years that this rarely happens, even as the cost of hardware storage has steadily decreased.

I have to think that Hetzer’s prices are closer to what S3 would cost, were it to be launched today.


I’m demoing a new version manager. I’ve been on asdf for a few years. I often use IRB (Ruby’s interactive interpreter) for basic calculations since Ruby makes such a good scripting language. When doing so today, for about the 1,000th time, I got this:

$ irb
No version is set for command irb
Consider adding one of the following versions in your config file at
ruby 3.2.1

This sort of lazy error bothers me:

  • In the vast majority of situations, but especially when I’m just trying to Ruby to subtract one number from another, the exact version of Ruby I’m calling into doesn’t matter. I’d accept anything in the range of 2.0 to 3.3. If I have 3.2.1 installed, maybe just use that?
  • There’s nothing actionable. I’m not told what config file it’s talking about, or how to otherwise resolve the problem.

I was told the other week that Mise does a better job of default behavior and descriptive error messages, so I’m giving it a shot.

So far, so good. Easy installation and configuration in my ~/.zshrc. I asked it to install Ruby, and it just did it. No additional plugin needed to be installed, and no specific version was required:

$ mise install ruby
mise ruby@3.3.5 ✓ installed

When entering a directory with .tool-versions, it told me immediately that a tool was missing:

$ cd owl
mise missing: ruby@3.3.4

A simple mise install walked me through installing all dependencies, including some unusual ones like Crystal, and doing so interactively so I could skip any that I didn’t want:

$ mise install
mise ⚠️ crystal is a community-developed plugin – https://github.com/asdf-community/asdf-crystal
Would you like to install crystal? Yes
mise ⚠️ postgres is a community-developed plugin – https://github.com/smashedtoatoms/asdf-postgres
Would you like to install postgres? No
mise ruby@3.3.4 ✓ installed
mise crystal@1.6.2 ✓ installed                                                                                                                                            mise run with --yes to install plugin automatically
mise asdf plugin postgres is not installed
mise Run with --verbose or MISE_VERBOSE=1 for more information

Published fragment Rails World 2024, with a few reflections on this year’s event.


Published sequence 088, royal lion hunt.

I visited the British Museum in London during my stay there last year. The museum has a wealth of ancient artifacts, including some of the most famous ones in history like the Rosetta Stone, but despite having my camera with me, I took few photos while I was there. All I could think of was the tens of thousands of times each of these objects was photographed every day, contributing to an enormous body of billions of photos, 99.9999% would never be glanced again.

This is one of the few artifacts I photographed because I liked it so much. It’s artwork on stone depicting Assyrian royals taking part in a lion hunt, circa 645 BC, right around the period where the civilization would collapse.

At the time I knew almost nothing about Assyria, but a friend sent over the excellent episode “Empire of Iron” from Paul Cooper’s Fall of Civilizations podcast (also you YouTube). It starts describing how the Greek general Xenophon came across the ruins of two colossal cities as he was returning from a battle in 401 BC. We know now that these were the Assyrian cities Kalhu and Nineveh, but by then (about 200 years post-collapse) locals knew nothing about them, despite their far greater scope and sophistication than anything they could build at the time. It would’ve been like living amongst ancient ruins built by giants.



Published fragment TIL: Variables in custom VSCode snippets, on using built-in variables in VSCode snippets to make publishing to this site incrementally faster.


APacIa

Of mild interest, Stripe has announced a new API release process. Two named API versions a year will be released, named after plants (e.g. “acacia”), and presumably following an A-Z scheme similar to Ubuntu naming.

Previously, API changes roughly followed this procedure:

  • Non-breaking changes went out after they’d been reviewed and whenever they became available.
  • A new API version (named with only its date of release) was cut for breaking changes. If multiple breaking changes happily coincided around the same time, they’d be coordinated for simultaneous release.

By my reading, the new scheme seems to be largely the same, except that non-breaking changes would be held for a monthly release on the current version, and breaking changes would be held for up to six months

I suppose the benefit of the new approach is that it gives users a more predictable cadence for breaking changes. Optimistically, maybe it gets them in the habit of updating their API version twice a year. Even more optimistically, maybe it starts to pave the path for a format deprecation lifecycle so that ancient API versions could eventually be retired.


Published fragment A few secure, random bytes without pgcrypto, on avoiding the pgcrypto extension and its OpenSSL dependency by generating cryptographically secure randomness through gen_random_uuid().


Published Real World Performance Gains With Postgres 17 B-tree Bulk Scans, in which we benchmark one of our API endpoints and get a 30% throughput improvement, with 20% drop in response time.

As long as you make heavy use of eager loading (which every serious application does to remove N+1s), Postgres 17 looks to be one of these releases where all you have to do is upgrade, and reap a major performance gain for free.



Published fragment Direnv’s source_env, and how to manage project configuration, on how I accidentally stumbled across the source_env directive and dramatically improved my configuration methodology overnight.


I pushed a new version of redis-cell today, a project that I still somewhat maintain, but only touch once a year or so.

While looking into another issue that someone had filed, I got the bright idea to update the project’s dependencies. That was a mistake, and I ended up sinking hours into fixing calls to the time crate. It wasn’t just that a few breaking changes had been introduced – no, the entire API had changed, and every use of any function or type from the create had to be fixed. There was no upgrade guide.

I really want to like Rust, but something like this happens every time I go back to the language. This wasn’t some novel third party dependency that broke. It was time, one of the most core facilities of any programming language, and although the changes that broke me are older now, a cursory look at the project’s changelog shows that it’s regularly deprecating/changing API on recent versions.

Zero cost abstractions are cool, but you know what I like better? Stability.


After coming off the absolute blight on human consciousness that was The Acolyte, I found myself wanting to go back and watch the original Star Wars trilogy.

I was a teen when its “Special Edition” revisions were released, and I remembered that George Lucas had gone on record at the time saying that these were now the definitive versions of the movies. But that was decades ago, and I’d just assumed that the smallest modicum of rationality had won out since then, and HD versions of the theatrical releases had gone out. I mean – the menagerie of Jar Jar-esque CGI critters on Tatooine and Han walking over Jabba’s tail – it’s all so clownish that no one could possibly have stuck to that line. Right?

Wrong. I watched a few minutes of the latest Blu-ray release and it was painful. It’s all in there. Even in the 90s the CGI looked awful. Now, it’s a punchline.

Scrounging the web, I came across Project 4K77 (‘77 is when A new Hope came out), also hosting Project 4K80 and 4K83 for Empire and Jedi, where fans have scanned 35 mm film frame by frame to 4K resolution, and painstakingly cleaned up the whole collection to approach modern standards.

I watched a copy, and it was exactly what I was looking for. Not only is all the Special Edition garbage gone, but it looks considerably better than Lucasfilm’s Blu-ray restoration. It’s grainy, but left that way on purpose to stay true to the original theatrical release.

I’m at the point now that I’m pretending no Star Wars past the original trilogy exists. Who could possibly have guessed not only how badly the prequels would turn out, but that the sequel trilogy would be even worse, and TV follow ups down in the gutter with it.

Oh, and mercifully, Han shoots first.


Published fragment Elden Ring, on how I broke my promise never to give FromSoftware money again, and it was okay.


Golang Weekly notes that Go has jumped to the 7th position on the TIOBE index, which measures programming language popularity.

The rankings are still hard to believe (does anyone actually believe there’s more C++ development happening than JS/TS?), but even so, a positive sign!