Leopard-Free Programming
I had a pleasurable bit of progress today while working on a feature for Hiss, my HTML adventure game system. This is one of my favorite things: turning a messy and not-quite-correct solution into a minimal and obviously correct solution.
To accomplish this required thinking and writing clearly:
-
A set of rules defining what to display on the screen.
-
The least complex set of steps that could fit the rules.
My tools were: a couch and a paper notebook. You can see the rules and steps I ended up writing in the Hiss Devlog (scroll down to Day 61, Feb 3).
But to summarize:
Before: My display code was handling all sorts of weird edge cases. Tackling each of these cases separately as I encountered them had resulted in a terrible mess with a global variable and logic spread all over the place.
After: By implementing my simple logical steps, the global variable had disappeared entirely and the logic was confined to a single small function. Nice.
As is often the case, the most effective (as in, least total time taken) way for me to accomplish this was a combination of trial-and-error at the keyboard to play with the problem followed by quiet contemplation away from the keyboard.
I’d love to skip the initial keyboard part entirely. But I don’t don’t seem to possess the ability to simulate the whole thing in my head and come up with the solution ex nihilo. I need to chase some leopards around first.
Leopards?
Ah, so now we come to my new favorite programming term. A pair of recent toots on Mastodon drew my attention to this 2013 journal entry by Jack Rusher:
Leopards in the Source Code (jackrusher.com)
Jack:
"…quite often developers follow an approach where they modify the code until all tests pass and then back slowly away from the keyboard before anything breaks…"
He then quotes Franz Kafka’s incredibly short parable titled Leopards in the Temple:
"Leopards break into the temple and drink to the dregs what is in the sacrificial pitchers; this is repeated over and over again; finally it can be calculated in advance, and it becomes a part of the ceremony."
I have certainly seen this pattern many times: we add special leopard-handling code to our programs and it accretes until the leopard stuff is as big as the original problem being solved.
After a couple years, the source is so leopard-shaped that no one can even remember what the original intention was!
By contrast, it takes a very clear understanding of the problem to find a route that avoids leopards entirely. There often is such a solution, but it takes time and concentration.
Aside: This is time that could instead be spent on adding new features. So it naturally follows (and it has certainly been my experience) that leopard-free solutions are more likely to be pursued in personal projects than in commerical production code.
Typically, the leopard-free version has an "obvious" quality to it that seems so simple that you can hardly believe you’d ever imagined anything else. But make no mistake: the simple version comes from a hard-won clarity of thought!
Rapid prototyping is fun! Beating on the keyboard until stuff works is a great way to explore a program as it is being molded into shape.
But there is a deeper satisfaction to be had in revisiting fragile code that "just barely works" and chipping away at the leopard-handling cruft until you’ve discovered the elegant solution that solves the real problem.
(I was originally going to add this note to my build-it-twice card, but upon re-reading it, I realized that one is more about re-building or refactoring an entire application. It’s certainly a very similar idea, but at a higher-level of abstraction.)
"Back" to programming.