Archive for March 2010
As programmers, we love writing code. Opening a fresh, clean editor, bringing up a blank form in Visual Studio, the world crisp and uncluttered and ready to receive your vision. It’s easy to understand why starting a new project is fun.
However, mostly we don’t like reading code. Dropped into the middle of some densely-packed jungle of a project, filled with obfuscated filenames and cryptic little comments like:
if (section == 0) /* can’t validate section this way */
and having to fight your way through to fix a bug or add a featurette without breaking anything else. It’s a lot like going to certain modern art exhibitions; you end up feeling as if those responsible are deliberately obscuring things just to piss you off. Actually, in the programming world this is sometimes the case. It’s easy to understand why people will go to extraordinary lengths to avoid reading and understanding complicated, real-world code.
This is unfortunate, because reading code – even bad code – is the key to writing good code.
When I was learning to program someone told me that I should try to read as much code as possible. Budding genius that I was, I thought this was advice for stupid people who needed to learn from their betters. I thought the only reason to read code was to pick up tricks from it.
How wrong I was. The real reason to read code has nothing to do with learning from the programmer who wrote it.
Recently I discovered that learning a foreign language teaches you two things: how to communicate in that language and how to communicate in your own language to non-native speakers. You learn that simple grammatical structures and shorter sentences are easier to understand. You get a feeling for when someone’s following you and which words in the sentence are most important to pronounce clearly.
It’s the same with reading and writing code. Reading code teaches you how to read code and it teaches you how to write code that’s easy to read. Both of these are desperately important.
Actually reading code is something most of us subconsciously avoid. I’ve lost track of the number of times I’ve been through this little dance:
- Decide to fix a bug or add a feature to a piece of code someone else has written
- Take a brief look at said code
- Frown in distaste because the original programmer – curse his blackened soul – put the opening brace on the end of the if statement instead of on a new line, as God intended*
- Spend the next 90 seconds not being able to work out why it was put together the way it was, or what’s calling what and why
- Tell myself: “Boy, this code is a real mess! Even I can’t understand it! The best thing to do is clearly to make a clean start and write it myself – it can’t be that hard and I can always refer back if I run into problems!”
- Spend the next few hours, days or (on one memorable occasion) weeks reimplementing a slightly buggier, less complete version of the original code. I now have something that isn’t noticably better by any metric, but I feel I understand it and that lifts a weight from my heart
- “Phew”, I say, wiping my brow with the back of my hand, “it’s a good job I rewrote that!”
It’s only after years and years of repeating this pattern that it has begun to dawn on me that each time I do this I’m really just wasting precious, precious time on something that doesn’t improve the product at all. What’s worse, I’m only doing it because I can’t face the thought of reading somebody else’s code. If I spent one fraction of the time reading and understanding it then I’d learn a lot more about the problem it’s trying to solve and would be in a great place to tweak or refactor it to suit my needs.
The desire to start afresh comes from the fear of reading code, and it’s always, always a waste of time because – guess what? When you’re done, there’s just as much code to be read next time you come back to it. The right thing to do is to read it, grok it and gently massage it into a more suitable shape. Or hack it apart brutally and repurpose it. It doesn’t matter! Once you understand it, you can do what you want with it. Code doesn’t rust and it doesn’t go off. Just read it, change it and use it. Every time I do this now, it makes me happy.
Just being able to read complex code quickly and effortlessly is a wonderful aim in itself, but the real benefits come from the effect it has on your own code. When you first learn to program, you’re really learning to write code that communicates your intentions to the compiler. Initially this seems like hard work, but actually a compiler jumps through a lot of hoops to work out what your convoluted code is supposed to mean.
To become a better developer, however, you need to learn to write code that simultaneously communicates your intentions to the compiler and to other programmers, who would rather do anything than work out what you were trying to achieve.
Even when working on your own you benefit hugely by writing code that clearly communicates its intentions, because most interesting programs end up being larger than you can hold in your head at any one time and end up being worked on for more than one session.
If you think your intentions are clear, but you’re not in the habit of reading code, you’re probably wrong and they’re only clear to you (and only today). It’s when you summon up your courage and dive into the deep end of someone else’s code and try to work out what’s going on without any reference points that you start to notice what makes this easy and what makes it hard. Would a brief comment here have saved you looking things up in that other set of nested classes?
When you come back to write more code yourself, you recognise which parts might be confusing, where a helpful comment or carefully-chosen function name would clear up any potential ambiguities. You recognise that a future maintainer who comes in to change this function will need to know that it’s affected by this other class over here.
In short, you learn to see your code with the eyes of a reader, and in doing so you become better at writing it. You can work on it faster and your team can work on it faster. Everybody wins. I worked professionally for years – years – without ever really reading anyone else’s code. Once I started, I began to see the whole field in a new light. I wish I’d started reading code years ago, I really do.
… that there are those among us who have never heard Code Monkey – if you think I’m talking to you, then may I humbly suggest taking steps to rectify the situation at once 😉
Every now and again I see glimpses of myself in ‘younger’ programmers as they struggle with the same concepts I did, fall into the same mental traps and generally make similar mistakes. Writing the 4 wrong ways post made me wonder how common these phases really are and whether we could categorize them.
You too? Well wonder no longer, for I have completed this herculean task! I’ve found myself in each of these traps at least once – some of them several times – and have seen them in others too. Are there more out there?
The Enthusiastic Newbie
The newbie is full of passion and excitement for her one and only language, which is undoubtedly VB, PHP or actionscript. Having finally got to grips with the syntax of said language she feels she’s completely mastered it in all its forms. The newbie writes astonishingly quickly, but everything ends up in one big file full of global variables. This is a very productive stage, if little worm games and random utilities / replacement shells are what you want produced.
Distinguishing code features: Each program is exactly one file, containing a hundred global variables, none of which has more than four letters in the name.
Mistaken belief: Programming’s pretty easy, really.
Most endearing quality: Her little shiver of excitement every time she opens her IDE and gazes at a blank project, full of potential.
Reads: Firefly fanfics.
Most likely to say: “Come and look at this cool flash game I just finished!”
The Budding Genius
Having programmed for a few years and learnt a second language, the budding genius is firmly convinced that he is the Messiah of the programming world. He reinforces this world view with his conviction that anything he doesn’t understand (i.e. almost everything) is pointless, old-fashioned and a waste of time.
Distinguishing code features: Uses his own vector class implementation. Always starts class names with his own initial.
Mistaken belief: The programming world has more to learn from him than he does from it.
Most endearing quality: How easy it is to make him defensive and huffy by mentioning anything outside his cabbage patch of experience.
Reads: His own blog.
Most likely to say: “Huh, yeah well everyone knows functional languages are no use for *real* programming *anyhow*”
The Abstraction Freak
After a while all new programmers being to realize they start each new flash game by copying 90% of the old one. Suddenly it occurs to them that they could write one ‘super’ game engine to make writing a new game as simple as finding the sprites and writing a config file containing the rules! Flushed with this success, the wannabe abstraction freak begins to believe all programs should be generalized, generalized, generalized… unfortunately, holding on to this belief too long turns them into the Abstraction Freak.
Distinguishing code features: Adds five new classes every time he implements a new feature, all of which are named after design patterns and give no clue whatsoever as to the feature they’re supposed to implement. Any actual business logic is hidden in an xml-based config file somewhere else in the repository.
Mistaken belief: Writing a program to interpret a set of config files containing an awkwardly-phrased, buggy description of the program he wants to write is better than writing the program he wants to write.
Most endearing quality: The expression of painful concentration on his face while battling his analysis paralysis before starting to reimplement the login feature for the fourth time that month.
Reads: Design Patterns, cover to cover, during his lunch break every day.
Most likely to say: “So I think we should start the new time scheduling project by writing a generic application framework…”
Any programmer exposed to the bitter realities of working in a soulless commercial software company, shuffling bits on a hard disk for the same salary every month eventually develops a certain protective shell. Neither speed nor genius are rewarded, so often a professional developer begin to develop a very careful, measured style that ensures he’s never caught out by either bugs or management, which he considers to be pretty much the same thing.
Distinguishing code features: The first ten lines of any function, even an accessor, are all assert statements. All the error conditions for each function are dutifully checked and handled and comments are liberally scattered throughout.
Mistaken belief: Doing things ‘properly’ is the same as getting things done, but better.
Most endearing quality: His aura of measured, unflappable calm that makes it clear that even the direst emergency won’t make him work any faster, leaving one with the impression he might be better suited to a career in the bonsai industry.
Reads: joelonsoftware.com (yes, even though Joel’s stopped posting)
Most likely to say: “Well, I won’t be able to say until doing a proper estimate next week, but it’s going to be at least *sucks air in through pursed lips* at least four man-months to add a print preview, plus testing and documentation of course.”
After a decade or so of bouncing from one stereotype to the next, our newbie is all grown up, yet she feels like a hollow shell of the enthusiast she once was. One morning, she wakes up and realizes that the unwieldy crust of unit tests, assertions, error-checking and class-design that have built up around her programming style are just crutches, crutches that are dragging her down and that she no longer needs! She casts them off and begins writing the simplest, barest code she can think of to do what she needs! Free the features! Free the code! Freedom!
Distinguishing code features: Only writes in dynamically-typed languages with a strong functional component. At first glance her code looks remarkably similar to the newbie’s, except there’s less of it and the variable names make sense.
Mistaken belief: That her enlightenment makes her a guru without the quotation marks.
Most endearing quality: Her little shiver of excitement every time she sees an interesting problem she could solve with ‘just half a dozen lines’ of code.
Most likely to say: “You know, polymorphic inheritance is really just a poor-man’s substitute for first-class functions and dynamic typing…”
So there you have it, my career as a programmer laid bare. I’m curious; does everyone go through these phases?
If I’ve missed any great ones, add your own in the comments and I’ll either update the article or collect them for a Part II…
Note: Yield Thought has moved to http://yieldthought.com – check there for the latest posts!