farthergate.com/posts/2025-06-10-an-ode-to-simplicity.md
Aleks Rutins a4f9dadd8b
All checks were successful
/ deploy (push) Successful in 4m7s
Switch to Kramdown, write a blog post
2025-06-10 22:27:08 -04:00

5.6 KiB

title banner published_on
An ode to simplicity /blog-banners/cheetahmontage.png 2025-06-10

If there's one lesson that I take from developing — and, more importantly, later abandoning — Cheetah, it's this: nothing can kill a good project, or even a middling-to-mediocre project, like scope creep.

The first big mistake I made was to do everything myself. Now, this was an incredible learning experience, of course: I learned how to write functioning Rust code, for one (functioning, not clean; please mind your footing around the Rc<RefCell<HashMap<String, Rc<RefCell<ElementRegistrar>>>>>), but by everything, I mean everything. Starting with the template engine. And it wouldn't just be a normal, text-based template engine: this template engine (in one file, for those who don't value their sanity) worked on the DOM.

The engine would have been complicated enough already with just that, but the cherry on top was a declarative-shadow-DOM-based hydrating component system that automatically extracted scripts from the page. And, of course, everything had to run as fast as humanly possible 🚀 (after all, this is Rust). Thus: pointers! Pointers everywhere! Except: this is Rust, so we wrap our pointers in seven layers of boxes, because we don't understand how they work and are more than a little scared of them.

Don't even ask about the Nix-based DSL for generating the HTML-based DSL for generating the site, or the Nix- and Caddy-based container builder, or any number of other quarter-finished micro-initiatives that all fed into the leviathan that that project was.

Suffice to say, it didn't work very well. Forcing everything to be in its own shadow DOM — as expected — broke styling. Sure, the generator itself was blazingly fast 🚀, but blazingly fast 🚀 isn't worth much when the recommended project template pulls the Rust-based project from Nix without a binary cache. Building the site took a nanosecond, but the full CI workflow ended up taking several minutes each time.

The final nail in the coffin, though, was dependency hell. Cheetah had more dependencies than any self-respecting programmer could chuck a rubber duck at.1 The most important of these was kuchiki, an HTML traversing library, which, after a couple of years, became unmaintained. I only noticed this when I tried to package an RPM — Fedora only packages the latest version of Rust crates, and the latest versions of kuchiki's dependencies were incompatible. There was more, too, but I won't put you through it. In short, cheetah became unmaintainable. I had built a massive, hulking project, and being able to maintain it depended on everything not breaking all at once. A couple of years out, once versions started to misalign, everything broke. All at once.


Sometimes, discretion is the better part of valor. So, I rewrote it. It took a bit to settle, but I eventually settled on Ruby, and created Phlexite.

In all honesty, "static site generator" are three rather strong words to describe Phlexite. It's a glorified path generation library with a nice DSL. It happens to also be smart enough to call functions to make pages. It's meant to be used with Phlex, but it's not restricted to it — in fact, it has no dependencies at all. It's simple enough that I haven't needed to update it in several months. This site is running with the latest (at the time of writing) version of Phlex (a major version ahead of where Phlex was when I last updated Phlexite), and it works without a hitch. If Cheetah was overcomplicated, Phlexite is oversimplified. And, after using it for a few months, oversimplification is winning.

Writing Rust feels, at times, like a constant battle for my sanity and soul. It builds character,2 sure, but it's not always enjoyable. Ruby is fun. In Ruby, the answer to "Can I do this?" is almost always "Yes, easily". I can write code without worrying about performance, and it'll end up fast enough. Sure, Phlexite doesn't build sites as fast as Cheetah, but you don't have to wait for the optimizing compiler to build it — and thus, CI ends up taking 20 seconds, rather than five minutes.

This site is built with Phlexite. It has Tailwind-based styling, a sensible build script, a tiny little dev script based on Watchman, draft post support — all things that the Cheetah version didn't have, because I was too busy fighting the tooling. When I want to add a new feature, I just... add it. It doesn't generally take that long. Instead of fighting tooling on my blog, I can get past that to actually write.3

Parallels elsewhere: more recently, I've been using vanilla GNOME with VS Code and Zed on all of my devices, and I've been incredibly productive. WM configuration is cool, and bspwm and COSMIC are blazingly fast 🚀. But what use is cool and blazingly fast 🚀 if I can't get anything done?

Tech should serve our productivity, not the other way around. That's why high-level, dynamically-typed languages were made in the first place — and why they're still just as relevant, no matter how interesting the latest statically-typed systems programming language may be.



  1. The great irony here, of course, is that I accrued all of these dependencies in the interest of doing everything myself. ↩︎

  2. https://calvinandhobbes.fandom.com/wiki/Building_character ↩︎

  3. My past self would have trouble believing that this is what a blog is for, but I'm pretty sure that this is what a blog is, actually for. ↩︎