2007-06-17

tactics, tactics, tactics

One of the challenges for professional programmers trying to advance professionally is simply deciding what to study. We each have a limited amount of time to invest in improving our skills. Should we spend those hours reading about architecture? Computing theory? Lambda calculus? Discrete mathematics? Complexity theory? Compilers? Should we get involved in local user groups, or toy around with new programming languages? Join the IEEE Computer Society? It's easy to find folks who will advocate any of those, and they're probably all correct, in the sense that any of those things help. But we can't study everything, so what is the best place to focus our limited time?

Well, I think I have an answer. But first, a detour into chess.

I came to chess as an adult. I'd played it most of my life, but had never studied or played seriously. Just pushed the pieces around, against other players who were also just pushing the pieces around. One day in my late twenties, I decided I would learn to play chess for real. So I went to the library and tried to pick out a book. Even though the SF Main Library had a huge number of chess books, it was surprisingly easy to pick a few: I just started with the ones with broad titles ("chess" and "dummies" come to mind). And I got better, really fast. Suddenly, I could beat the pants off anyone who was just pushing the pieces around.

I was the chess-playing equivalent of a junior programmer, let's say a recently graduated CS student. Unlike people who've never programmed, the junior programmer can usually convince the computer to do what he or she wants it to do. A huge accomplishment! And then the junior programmer does something foolish, like say, gets a job programming computers.

Back to chess, the foolish thing I did was join a chess club, where I was by far the worst player. Now I had the dilemma: what to study next? Like most people in my situation, I chose absolutely wrong. I picked up a book on the Ruy Lopez opening system. After reading it, I was a substantially better Ruy Lopez player. Which was great when I could persuade my opponents to stick to the opening lines I'd studied, which I generously estimate accounted for 0.1% of the games I played. Next I picked another opening, the Grob, and read up on it, and tried to get my opponents to let me play a Grob or a Ruy Lopez. Now 0.2% of my games were improved. And then -- since I'm not crazy in the sense of doing the same thing again and again expecting different results -- I stopped studying specific openings.

By analogy, the employed junior programmer reads a book on yacc and a tutorial on the GNU multiprecision math library. Two things happen: first, that tiny percentage of their time spent working with these specific tools improves, and second, they start to put a lot of effort into convincing co-workers to stick with yacc and libgmp for all tasks. Have they really improved? Yes, but not in a way that is apparent in most of their endeavors.

Fast-forward over the part where I read a big stack of chess books: endgame theory, entire books on specific units, books about the history of chess, books about the psychology of the game, the official USCF rules. Each one improved my games only marginally, if at all, and most ended up as bathroom literature in our house, which really irritates my wife. My rating had barely improved in the few years since I read "Chess for Dummies", and I was still the worst player in the club. I knew that I was looking for a way to improve my game in general, but re-reading the general books wasn't a help, and the advice from people who've mastered chess is really inconsistent. (Frankly, people who write about chess are mostly aging child prodigies, who don't really believe it is possible to learn the game as an adult). Then, by some random stroke of luck, I stumbled on a very thin, very simple book in the book store: "Rapid Chess Improvement", by Michael de la Maza. It's a small book, but I can distill it even further: study tactics. To be fair, the book actually outlines a specific study program, which is great, but the important lesson is just those two words: study tactics.

I don't think this book has been written for computer programmers yet. But let me quickly translate: study coding.

Tactics, in chess, are present in every single game, just as coding is present in all software projects. Tactics are what makes or breaks most games of chess, just as coding is what makes or breaks most software projects. Gambling on a chess game? Put your money on the tactical whiz who has never studied openings over the master of the English opening -- even in an English game! In the same way: hire people who can read, write and talk about code over those with sloppy code and really deep knowledge of J2EE.

Before I move on, I'd like to proudly announce that, after spending 100% of my chess-studying time on tactics for the last year -- maybe 20 hours total -- I'm no longer the worst player in my chess club. I still lose more games than I win, but as long as I've slept and eaten recently, I don't lose because of head-slapping tactical errors. Better still, I am recognized in the club as someone who will punish my opponents' tactical mistakes brutally. Can you guess what I'm studying these days? More tactics.

OK, if you're still with me, you're probably wondering "how does one study coding?"

Chess players study tactics by means of puzzles. A typical tactical puzzle has a picture of a chessboard with a few pieces, and a single sentence problem description: "white to play and win," or something similar. Tactical puzzles are not generally taken directly from actual games. Instead, they are simplified or idealized from real games -- pieces which aren't relevant to the problem are removed, for example, and the real game elements of time pressure and personality and so on are completely removed.

Can this study method be translated into programming? Yes. I believe the equivalent is reviewing code on paper. Not necessarily literally on paper, but in isolation from the compiler, the schedule, the politics and everything else that comes with a professional software project. Just the code. Unlike chess, the problem description is always the same: "how can this code be improved." Ignore the big picture, the product, and high-level software objectives such as performance, portability or reusability. Just think literally: how can the *CODE* be improved, from the perspective of a human reader.

And just like the chess player solving a tactical puzzle, arm yourself! In chess, there are names for all of the common tactical patterns. Fork, pin, skewer. Discovered check, driving off, piling on. The list goes on a bit, but it's finite. In the same way, there is a jargon for describing code quality in much more concrete terms than the all-too-common (and uselessly vague) "bad smell". There are the basics: use meaningful names, keep it simple stupid (KISS), don't repeat yourself (DRY), be consistent, and so on. Then there are more complex quality issues like cohesion, coupling, information hiding, referential integrity and separation of concerns. Challenge yourself to use the correct terminology, both in describing problems and in suggesting improvements.

Note that I'm talking about something you do with the spare time that you've set aside for professional development, not at work. And I certainly don't mean to imply that we should all be applying this kind of scrutiny to every piece of code we produce professionally. At my chess club, we start each game with 25 minutes on the clock. I'd never get past move 10 before losing on time if I applied the kind of focus to each move that I apply when solving a tactical problem, in the same way that software would never be completed if programmers always tried to make it "perfect". The objective of the study, in both cases, is learning to recognize patterns, not learning to apply a specific method.

So daily, weekly, or monthly, pick a manageable chunk of code -- good or bad, yours or someone else's -- print it out (again, not necessarily literally), take it home, and study it in detail, with the objective of improving it. Studying code in this way will not make you way better, immediately, at your current job. Instead, it will make you a little bit better, slowly, at every programming task you undertake.