I’ve been ditching a lot of code lately. The first thing was my side-project Canto’s old codebase*. The second was this blog, which is now obviously a WordPress blog instead of a quirky but fun-loving git based CMS I wrote before. All together, I’ve shed thousands of lines of code and it feels great. But as I toss this code to the wayside, I can’t help but wonder “How did things get this way? Where did I go wrong?”
One thing that I’ve learned over the course of my programming travails is that design is more important than implementation. As I maintained and extended and improved Canto over the two or three years since I first started it, I learned a lot about showing foresight. A lot about how getting a feature into a codebase right is a better long-term strategy than getting a feature into a codebase quick.
Programming is a tough task. It requires a lot of concentration and thought and, as if that wasn’t bad enough, it’s generally done under a lot of pressure. Either from deadlines from a boss, or just expectations of your users (or your perception of either). A lot of choices I’ve made in the last couple of years have been wrong because they’ve been twisted by having the perception an audience. If someone sends you an email and they’re in distress because of a bug you feel as if they’re waiting for your response, constantly refreshing their mail client or feeling frustration with your software the whole time the flaw goes unpatched. You feel as though there are a thousand other users that have run into the same bug and just never reported it only to move on to greener pastures. You see the 10 day (or more!) turnaround time on your packages in repositories. The fact that Ubuntu is now actively serving up a broken version to its users and there’s nothing you can do but fix it for the next iteration (Salacious Salamander or whatever) six months later. Suddenly it’s as if everyone using your software is secretly unhappy with it.
It’s hard not to face these troubles and feel an urgency beyond reality. Feel the need to find it, fix it, and push it to the repo and make a release before anybody else reports the same problem. But, unless you’re dealing with a critical bug and your software is immensely popular it’s probably not as urgent as you imagine. Most likely, the user reported the bug and moved on with their lives. They either uninstalled your software, will use something else in the meantime, or will patiently wait for a fix. If you’re lucky, maybe they included a patch. The point is, what the user does is what the user does, it’s up to you to take your time and really analyze a problem before you fix it. There are plenty of potential users out there and for any user you lose over a single bug there’s another who will try your software after it’s patched. That’s why it’s important to find the right solution instead of the quick solution because the right solution will keep you from getting into this situation again (or make it easier to fix correctly when you do) and the quick solution increases the probability that you’re going to feel that sort of pressure, and lose another user over essentially the same bug.
Coding is all about trying to maximize the time you spend writing features and feeling rewarded, and minimize the time you spend bug fixing and feeling like your users are searching you out with machetes. Anything you do to sway that balance in your favor should be done without hesitation. But what can you do? I might not be the best person to ask, but these are some improvements I’ve been trying over the last few weeks and so far so good. I call my new philosophy “Calm The Fuck Down”
- Start over. Either on the project, subsystem, or feature level. Even with recognition of the fact that the current implementation has become unmanageable, it’s always hard to look at functioning code and say “This is crap! Tear it out!” but sometimes that’s the only thing to say. Coders tend to look at their own code and not see its utility, or its elegance, but the weight of all of the obstacles they’ve overcome, or the bugs they’ve ironed out. To be passionate about good code, you have to be dispassionate about your own code. As you gain experience you see the error of your ways and have to re-evaluate practically every decision you’ve made in the light of new information and the easiest way to do this is to start over. It’s not always the right thing to do, but when you suddenly realize that your code has turned into a chain of hacks then you have no other path forward. Some developers believe they can just do a quick stub-out of code, or a quick and dirty narrow implementation now and return later. Maybe you can. I can’t. My thought is that if you can’t take the time to do it right, it’s time to hold off and give it a bit more thought.
- Put everything on paper first. This is something that I find helps alot, particularly if you’ve really got a good handle on the language you’re using, because it helps you layout your data structures beforehand and anticipate your needs before you even open your editor. Sometimes it doesn’t work out (I actually just rebased out of existence a commit that I had planned out on paper but had fallen victim to a number of unexpected twists), but most of the time an hour of planning can save you a full day of coding. If you get into the habit of putting everything on paper first, your first step in responding to a feature request or a bug report is grabbing a piece of paper and a pen, instead of impulsively taking a hatchet to your codebase.
- Don’t let the phantom specter of imagined users fleeing over bugs or missing features rush your design decisions. I’ve fought this battle for so long that it’s become meaningless. There’s always another feature, always another bug. If you rush to fix a bug, you’re probably simultaneously laying the groundwork for the next one. Getting a fix or a feature out means nothing if it bites you in the ass down the line. So unless people’s boxes are being enslaved into a malicious porn spam botnet because of a security flaw, it can wait.
As for all of that code I’ve scrapped over the last few months, I chalk it up to one thing: practice. If the wise men of yore are to be trusted, that apparently makes perfect…
Reddit tl;dr : Regardless of perceived pressure, calm the fuck down and take your goddam time.
*Tangentially, Canto 0.8.x is much stronger and in alpha for harder-core IRC lurkers.