Symlach

I'm feeling rusty

“We have seen that computer programming is an art, because it applies accumulated knowledge to the world, because it requires skill and ingenuity, and especially because it produces objects of beauty. A programmer who subconsciously views himself as an artist will enjoy what he does and will do it better.” ― Donald E. Knuth

Most people who enjoy learning by doing accumulate a project graveyard. Mine is large. As I mentioned in my previous post, it’s the place where my personal projects typically end up, and I’d love to see more of other people’s rough work or hear what they learned by trying something out. There’s something really cool about building something just for the love of it, or for what it can teach you along the way.

Digging back through my collection, I found a terminal user interface (TUI) application I’d built in November 2022 and forgotten about since. At the time I’d been working on a video streaming project for work that was pretty frontend heavy, and I felt like my instincts for building backend systems were getting rusty. I’d also been playing Wordle most mornings, and I wondered if I could build “Rustle”, a clone for the terminal, written in Rust. The thought of it sitting on a production server as an easter egg, waiting for an engineer to find it, amused me.

I’d built a few CLIs in Python and Go, but I’d never written a TUI application, and I had limited experience with Rust having just finished reading Programming Rust. I wanted to see how far I could get.

The game logic was straightforward, which freed up most of my brain to focus on learning the Rust language and the packages needed to build the TUI.

One issue I did run into was the grid used for guesses. The original Wordle game gives you six rows, to make six guesses, but my letters were drawn in ASCII art and each one needed a certain amount of height to render cleanly inside its box. At six rows the boxes had to shrink, and the letters started overlapping their borders. I tried a few ways around it before settling on five rows instead. It worked well, and giving players one fewer guess made the game a little more challenging, which is never a bad thing.

Here’s the end result:

A short demo of the Rustle terminal application I built.

I was happy with the outcome. It even encouraged my wife to start using the terminal more. Win.

I wish I’d taken better notes on what I learned building it, but here are a few things that stuck with me almost four years later.

As someone new to the language, Rust felt frustrating to write. But once things compiled, they more often than not worked first time. I see that as a good thing. Flagging issues at the point they occur makes them far easier to understand and fix than finding them a week later.

Rust’s error messages were a big part of that. I could usually fix a problem from the error message alone. I found this refreshing having used other languages with cryptic error messages, and it spared me the constant back-and-forth between code and docs.

People often complain about learning Rust’s ownership system. It took some adjustment, and I’m sure my code is far from perfect, but I found the official Rust guide did a good job teaching the fundamentals. Without the pressure of a deadline, I found learning the ownership system fun, working with the compiler as it guided me through my mistakes, when I couldn’t rely on the error message alone I could turn to the documentation to clarify anything the error didn’t. Lifetimes gave me a headache, but it’s been too long for me to remember the details. I got things working, though a purist would probably lose sleep reading my code.

Throughout my career I’ve mostly written software in TypeScript and Go. Go sometimes gets a hard time for being verbose, especially around error handling. I found Rust similar but for different reasons. I really liked how it handled errors, but concepts like asynchronous programming were a much steeper learning curve. I tried making the game-end notification asynchronous so it would clear itself after a few seconds, but I ran into a few issues and decided to keep the game fully synchronous instead. It made no real difference to the user experience, the notification cleared as soon as you started a new game anyway. Async complexity like this is to be expected for a language that makes the programmer manage things other languages handle for you. I can see how people who get to write Rust for extended periods would grow to love it. It brings a lot of benefits for the right use case.

Then there’s speed, which comes up a lot with Rust. I didn’t benchmark the application, so I can’t give an objective answer. For a Rust newbie it was sometimes painfully slow to write, but that was counteracted by things working as expected once they compiled. I can see why teams chasing speed of delivery might steer clear, but for projects balancing strict performance requirements with developer experience, I can imagine Rust at least being worth considering.

After showing the project to a couple of friends, they wanted to play it on their Windows machines. This turned out to be simpler than I’d expected. Rust compiles to a single binary, so there was nothing for them to install. I think I used rustup on my Linux machine with a Windows target for cross-compilation, though I have a vague memory of hitting an issue and using cross. I can’t remember exactly. What I do remember is that whatever I did, the binary worked first time when I sent it to them to try. If this had been more than a hobby project, I’d probably have set up GitHub Actions to build for each platform.

I dabbled with Rust on and off through 2023 and bought Zero To Production In Rust intending to build my own web application. That never happened, though I did enjoy completing the project laid out in the book. I’d like to try Rust again someday, maybe to build something like a cache or a load balancer. For now I’m focused on learning to build a platform on Kubernetes, which I imagine will keep me busy for the next few months.