A programmer’s worst enemy is getting stuck. Getting stuck on a problem hurts your productivity. Worse than that, it hurts your joy, your confidence, and your soul. Therefore learning how to avoid getting stuck, how to recognize when you’re stuck, and how to get unstuck is a key skill in the quest of becoming a great programmer.
One of the things that helps me both to avoid getting stuck and to get out of being stuck is understanding the different kinds of stuck.
Just Plain Not Stuck. In order to understand how you get stuck, it’s important to first see what it looks like when you’re not stuck. You’re not stuck when you’re programming something that you understand—or think you understand—reasonably well.
Let’s say somebody asks you to build a lightweight GUI system for a video game. It’ll be used to show the main menu, with it’s “Continue” and “Options” and ever-favorite “Credits” button. The GUI will also be used for the health bar and the inventory screen and the quick-activation in-game tool belt. Fun game-y sort of stuff.
So now you put on your programmer hat and you think, “Okay, maybe a general Window class—wait no, ‘Window’ sounds too formal and old-school. I’ll call it ‘Widget’—basically it’s a drawable rectangular thing. Then we’ll have a button class that derives from that. I’ll need input and click detection. States for the different button states. Hot-swapping between images in different states.” And off your brain goes! Designing and imagining, considering options, dreaming up how it all should be. You’re going to make the world’s greatest GUI framework.
You’re Just Plain Not Stuck. If you have a smidgeon of design skill, some familiarity with how GUIs work (you do, don’t you?), and some inkling of how rectangles and images and mouse clicks work, you’re good to go. Nothing can stop you. You’re programming.
This is programming at its finest. Facing a challenging problem—but not too difficult—with fairly clear concepts and room for creativity. This is how we love to program.
You are in control. No bureaucratic processes to bog you down. No waiting for long downloads or repeated system reboots. Just you and your editor and “class Widget… class Button extends Widget….”
Just Plain Not Stuck. This is where we want to be. Alas, we cannot always stay here. (People who always do stay here are probably not “Real Programmers.”) We must face the harsh realities of other people’s tools, bugs, bizarre APIs.
Stuck in the Muck. Which brings us to the first kind of stuck. Stuck in the muck happens when you’re facing a task that isn’t particularly hard—it’s just hard to figure out how you’re supposed to do it.
I switched to Mac a few years ago and have been slowly dredging up my long-buried knowledge of Unix. So here I am, sitting at the command line, trying to figure out how to list all the files in a folder and sort them by date.
Well look, I know this is easy for you. You’re a Unix-head and you’ve done this a thousand times. And sure, even I know how to type ls. But what is the switch that will let me tell ls how to sort by date?
So I type man ls. Immediately I am poked in the eye with a butt-ugly page showing me a ton of arcana on ls. Now I tediously, painstakingly read through the monospace text looking for something about “date.” (Yes, I know there are prettier man page readers. I haven’t bothered to set one up. And anyway I’m making a point here.) It’s not on the first page, so I tediously scroll my way down using circa-1974 scrolling technology, still using eyeball-search to find the word “date.”
Ah-ha! Here it is, buried in the third page. I want the -t switch. Brilliant. So I quit my man reader and try out ls -lt. Ah. Shoot. I wanted them in reverse order.
So now I run man ls again and do another tedious eyeball-search looking for… Oh, bother—this is a pain. How about another round of Robot Unicorn Attack?
Now this is a trivial example. Pitiful, really. But it’s a small instance of a larger phenomenon that frequently plagues programmers. You’re trying to get a task done. And you like that task—maybe a super-fly task like writing a particle system. But along the way you encounter a hitch—some tool (like ls) that doesn’t work the way you want, or some API call that keeps returning an error. And so you end up slogging, trolling through the muck. Documentation. Old usenet posts. Maybe, if you’re lucky, a Stack Overflow discussion. On particularly bad days, Google searches that just keep going nowhere, and yet you just keep re-searching, not believing that the whole universe could be this ignorant, hoping you’ll eventually find something.
You’re stuck. But you’re not stuck because the problem you’re facing is difficult. You’re stuck because the answer is obscure. Getting through the problem means lots of reading, lots of skimming, siphoning through a lot of irrelevant junk. You’re stuck in the muck.
You can’t avoid getting stuck this way. Well, okay—some APIs tend to be particularly badly designed, with functions and parameters so obscure that endlessly reading documentation is the only way to crack the code. I’ve always thought Microsoft’s APIs—Win32 especially—were particularly finicky and arbitrary. Or take sound libraries. I like OpenAL, but the functions are badly named and the return values senseless. Fmod, by contrast, isn’t free, but the API is much nicer.
So avoid the nastiest APIs and frameworks and choose better ones if you can. But otherwise, there’s no way to completely avoid getting stuck in the muck. Therefore the key skill to dealing with stuck in the muck is how to get out.
How to get out of being stuck in the muck is a matter of a whole other post, but here’s the basic rundown.
- Pay attention to when you read and when you skim. Learn to skim what needs to be skimmed and read what needs to be read.
- Learn to search. With Google, yes, but also within your IDE. I am astounded at how many programmers will troll through their own code tediously, page by page, rather than simply using “Find in Files” or grep.
- Avoid eyeball-search whenever you can. (Shame on me for using a man reader for which I do not know how to search.)
- Use Stack Overflow early and often. It’s the best thing to have happened to programmers in years.
And here’s one more tip. Set a time limit. If you’ve searched for an answer for more than thirty minutes, maybe it’s time to go about the task a different way. That’s general good advice for how to get unstuck. Don’t just keep pursuing the same strategy for ever. Give a particular course of action the good ol’ college try, but if it doesn’t pay off in a reasonable amount of time, try something different.
Conceptually Stuck. Oooh, this one’s harder. A programmer is conceptually stuck when the reason for his or her lack of progress is not mere lack of facts, but lack of concepts. You’re conceptually stuck when you not only don’t know the answer—you don’t really understand the question.
A common example of this sort of problem in C++ centers around pointers. Many of my beginning students in game programming at the Guildhall come from languages like Java and C#. In those languages, pointers are hidden behind references, and garbage collection deals automatically with problems like memory leaks and dangling pointers. I will sometimes see code like this.
string reverse( string s )
string* copy = new string;
// ... code to reverse-copy s into copy.
…which fills me with horror on so many levels. The most gruesome part of this code is that simple little expression
new string—so innocent in Java or C#, so very wicked in C++. But how, “wicked,” you ask?
So let’s say that you write this code into a game you’re working on. And your lead programmer comes to you and says, “We’re seeing a memory leak in the latest build. We don’t know what’s causing it, but it looks like the problem came in at one of your revisions. Could you look into it?” So you start digging.
Now if you’re still working from a Java or C# perspective, you may not be well versed on what a memory leak is. But let’s say you are. How do you go about finding a memory leak? What should you be looking for? What tools would you use to help you search?
And let’s say you discover that the memory leak is happening somewhere in this function. Why is it happening here? Which line causes the leak? How would you fix it?
As a programmer, if you’re attacking a problem of this severity without understanding the underlying systems (in this case, memory allocation), you are lost. You will spend hours, possibly days, searching for a problem and a solution that a programmer who simply knows what he is doing can find and solve in minutes. That is a nasty, miserable way to get stuck. And a programmer who stays stuck like this for several days each week is going to hate his or her job before long. It’s no fun feeling like your own code is playing a joke on you, stapling “Kick Me!” to your back.
I’ve known junior C++ programmers who spent hours trying to resolve “duplicate symbol” errors from the linker because they didn’t know what
#pragma once was for. Sure, this is arcana to a PHP programmer, but C and C++ programmers have to know how the compiler and linker both work—how to avoid, for example, including headers more than once in a translation unit.
The key is that in any area of work, there are certain underlying concepts that you can’t live without. You can get by without them for a while, perhaps, but ultimately you have to master them. Without that mastery, you will encounter obstacles that turn into mystifying nightmares. That’s when you know you’re conceptually stuck.
The tragedy and horror of conceptual stuckness is that you generally gave no idea why you’re stuck or even that you’re stuck. If you don’t have the concepts needed to solve the problem, you may also not have the concepts needed to recognize that there is a problem. There is a particular kind of blindness that goes with being conceptually stuck.
Psychologists call this the four stages of competence. At the lowest level, you don’t know something and you don’t even realize you don’t know it. At a little higher level, you don’t know something but at least you realize you don’t know. Being conceptually stuck means being at one of those levels. The only way out is to move up to the highest level: knowing and knowing that you know.
Study is the way to avoid becoming conceptually stuck. This is one area of programming where practice and mere “experience” on its own won’t help. You have to actually learn—read, talk, listen, think. You can practice using std::vectors for five years and never really understand how they allocate memory or initialize elements. Without that deeper understanding, you can do some good with vectors, but you can also do a lot of harm… resizing when you should
reserve(), pushing front when you should
push_back(), passing by value when you should pass by constant reference.
Let’s say you’re conceptually stuck—how do you get unstuck? The answer is just the same. Study. I recommend a simple three-step process.
- Step away from the code.
- Breathe deep.
- Take up a book and read.
Just Plain Stuck. The worst kind of stuck is what happens when there truly is no way forward—when there is no answer to the question. Like they say in Maine, “You can’t get there from here.”
This does not happen in programming much. In my role as a game producer and project manager, I sometimes have programmers argue about a task they don’t like or don’t feel confident about. “It can’t be done,” they say. “Converting the engine to use OpenGL from DirectX is simply impossible.”
“Come on now,” I answer. “What if you had a year to do it.”
“Okay, yes, we could maybe do it in a year.”
“Well then, it’s not impossible then, is it,” I say, and then I smile in a really irritating way.
Truthfully, there isn’t much when it comes to programming that is truly impossible. Bits are very light and it’s easy to push them around—what’s impossible about setting bits? But there are lots of programming tasks that take far more work than they’re worth. When something is clearly far harder than it’s worth, then you’re really stuck.
I mentioned an example of this in my last post. I’ve got these crash reports and I need to attach them to debug symbols. In order to do that, I need the symbol files—.dSYM files, they’re called. But I don’t know if I’ve still got the .dSYM files for the executable that the crash report is based on. And if I don’t—well then I’m Just Plain Stuck, because the crash reports won’t be much good to me then.
Another example would be a lost password. For some authentication systems, if you lose the password then you’re Just Plain Stuck. You won’t move forward without that password and there’s nothing you can do about it. You have to start over with a new account, maybe lose the data in the old account. That’s a severe example of Just Plain Stuck.
Just Plain Stuck is as bad as it gets. But it doesn’t get this bad very often.
In fact, I’d say that the threat of getting Just Plain Stuck is a bigger overall threat to programmers than actual instances of getting Just Plain Stuck. That is, when we dread a task, often it’s not because we’re actually stuck but because we’re pretty sure we’re moving toward getting stuck. We don’t want to get stuck, so we do something else—a different task, or another round of Crush the Castle. And of course the irony is that by avoiding the task in order to avoid getting stuck, we actually bring about the getting stuck immediately. We stop making progress. We procrastinate. And to procrastinate is to be stuck.
I think a major reason that programmers will often prefer writing their own code rather than using an external library is because of this dread—this fear of getting stuck. And I’m not sure it’s as irrational as it sounds. When I’m just writing code, I’m Just Plain Not Stuck. I feel powerful, competent, and I’m having fun programming. I can get a ton of stuff done in a few hours of flowing work. When I’m using someone else’s library, I have to study, to read, to understand their concepts and their API and their silly parameter arguments. I know that eventually I’m going to find a bug I don’t understand or a function call that keeps returning an error for no apparent reason. I’m stuck, or moving toward stuck. And I get almost nothing done in a few hours of start-and-stop, frustrating work.
So given the option between being Just Plain Not Stuck and facing the constant threat of getting stuck, who wouldn’t choose the Not-Stuck option? Who wouldn’t reinvent the wheel? You can complain about “Not Invented Here” syndrome all you like, but programmers like to program, and stuck is our biggest enemy. Assuming there is no overwhelming reason to use an external library, we’ll take the Not-Stuck option every time.