Coding For Readability
April 6th, 2007Raymond Chen today reminds us that the readbility of code is important. But I’m not sure I agree with his headline/premise:
“Code is read much more often than it is written.”
In my opinion it’s more important for code to be skimmable than readable. This may be a lot of nitpicking over what is just supposed to be a catchy subject for Raymond’s blog, but I find it thought provoking. Let’s say you’ve got 100K of code. It’s OK if 90K of that code is completely unreadable, as long as it never needs to be modified again. That’s a big if, but my point is that the 10K that is actively developed can be well separated from the 90K of unreadable garbage, and you’re in good shape. Your code is skimmable.
In other words, don’t waste your time making already unreadable code “readable.” Just keep it in a dirty subroutine (and subfolder, probably!) where it belongs, and keep your high level code meaningful. I would guess that the vast majority of code in any shipping product has not been “read” in years. The products continue to evolve because they are skimmable. The change-prone portions have naturally eroded away from the giant clumps of unreadable junk.
Which isn’t to say that new code shouldn’t be as readable as possible. Interestingly enough, the article that prompted Raymond’s latest advice was an earlier one advising against BOOL parameters. He makes a good point, in recognizing that BOOL parameters in C or C++ do not often convey the parameter’s true meaning. Here is an area where Objective-C has a huge advantage with its inline-labeled parameters. Consider Raymond’s complaint:
“Even worse is that CreateEvent has two BOOL parameters. Like anybody reading the code later can remember which comes first.”
The Windows API he alludes to has a prototype like this:
HANDLE WINAPI
CreateEvent(LPSECURITY_ATTRIBUTES lpEventAttributes,
BOOL bManualReset,
BOOL bInitialState,
LPCTSTR lpName);
So you end up with a call that looks like this:
HANDLE myHandle = CreateEvent(myAttrs, TRUE, FALSE, "Ouch");
Indeed, Raymond was right. What do the TRUE and FALSE mean? The Objective-C equivalent of this CreateEvent method call would look more like:
HANDLE myHandle = [self createEventWithAttributes:myAttrs
withManualResetting:YES
signallingInitialState:NO
eventName:@"Ahh..."];
Damn it feels good to be a Cocoa programmer.
Update: It occurred to me shortly after writing this that when I do write C code, I often overcome this problem by /* inline-commenting */ the parameters. This technique was also described by somebody in the comments on Raymond’s blog.
Update 2: I didn’t think this post through too well before posting it, and now I feel like I’m suffering a bit of the fallout that comes from that. It’s easy to take from my post above that I have a nonchalant attitude about code readability. I meant it more as a riff on Raymond’s headline, and as an opportunity to add my belief that as important as readability is, skimmability is even more important.
Eric Albert wrote a thoughtful reply, to which I was motivated to also reply in his comments. I think my thoughts there might be also serve the permanent record of this entry here:
For the record, I am also in (nearly) complete agreement with Raymond. I mainly disagreed with his premise that code is read more often than it’s written. I don’t think that’s true.
And my opinions about this also come from being a code generalist. In particular, I think of the bugs I fixed in the Mac OS 7-9 days, when some of the ugliest, unreadable code imaginable was involved in the fixing. Often it was the skimmability of the outer layers that made it possible to pinpoint a bug, even if the final fix required cracking open some C file that was autotranslated from Pascal that was auto-translated from 68K Assembly.
In short: a giant code base is referenced much more like the yellow pages than like a novel. In the phone book, it’s nice when all of the entries are readable and well designed, but it’s much more important to be able ot skim to the section you’re most interested in right now.
April 6th, 2007 at 8:32 am
“inline-labeled parameters”.
Don’t invoke the wrath of bbum
April 6th, 2007 at 8:46 am
Heh – it was in fact thanks to Jon’s prepublishing comments that I changed my wording from “named parameters” to “inline-labeled parameters.” The distinction Jon is alluding to is that Objective-C’s parameters are not named, because they’re not uniquely labeled or re-orderable.
This does lead to the possibility of methods with names that don’t aid documentation such as:
– (void) doSomething:withThing:withThing:withThing:;
Of course, you can write unreadable code in any language if you try hard enough :)
April 6th, 2007 at 8:50 am
My favourite is:
@interface Stupid:NSObject
– ::::;
@end
Good luck guessing what the method does. :-)
April 6th, 2007 at 8:52 am
Jens: Heh … I confess that Black Ink has a few methods in it still with ::: for the trailing parameters, an artifact of porting from Java where parameters beyond the first had to remain unnamed.
April 6th, 2007 at 8:57 am
Jens, that actually wont compile, how about:
@interface Stupid:NSObject
– _:_:_;
@end
Which does? Morse code method names?
April 6th, 2007 at 9:55 am
“Damn it feels good to be a Cocoa programmer.”
/me throws up his obj-c gang sign.
April 6th, 2007 at 10:07 am
I’d much prefer 100% readability as you never know which parts of your code will need attention again in the future.
I am also tempted to think that if 90% of your code are ‘unreadable garbage’ that code may not be particularly good to begin with and it being unreadable will come to hurt you when you are forced to fix some problems in it. Of course all this is even more important when you are working on a collaborative project rather than code that is owned and exclusively used by yourself. While your own ‘unreadable garbage’ may still be somewhat meaningful to yourself, it’s fairly likely that it may cause a lot of struggle for others.
April 6th, 2007 at 11:17 am
I don’t agree with what you say.
Code must be 100% readable because
1) Others could end up in maintain that code (you should know something about this topic :))
2) In a year, when you find the Nth bug you might not be able to re-understand the mess that the year before you were comfortable with.
3) With modern refactoring techniques there is no excuse for not having readable code.
April 6th, 2007 at 11:20 am
I don’t disagree that code should be 100% readable. I mostly questioned the premise that code is read more than it’s written. I don’t think I buy that.
And there are lots of situations I can imagine where fixing the readability of existing unreadable code should not be the highest priority.
April 6th, 2007 at 11:34 am
I think you may be right when saying that code is not read more than it is written. However – in my limited experience anyway – this is partly due to the fact that a lot of existing code is so hard to read that you just shrug and move on rather than putting the effort of figuring out what other people may have meant with their code into it.
It is also a question of the situation you are dealing with. When you are working on your own project, it may be worth ‘saving’ the readability for last (although that wouldn’t be my style, I guess). But what about an open source project where other people may look over or even ‘scrutinise’ your code as you work on it? Things should be readable there. And often aren’t.
April 6th, 2007 at 11:57 am
“I often overcome this problem by /* inline-commenting */ the parameters.”
well…this “c-part” of your cocoa-application may very well belong to the 90% of code you never touch again. and if you really happen to look at this code again you probably lookup the documentation for these functions again, or you may as well rewrite the code because you know better now and implement things in a simpler whay, that may even be easier to understand ;-)
April 6th, 2007 at 12:02 pm
Amen to Cocoa gratitude. When I see a function name like EnableWindow(bool) whose job is not to enable a window, but to set the enabledness of a window, I get a bad feeling.
April 6th, 2007 at 12:17 pm
Another simple way to make C functions like your example more readable is to pass constants instead of simply true or false. If done correctly these carry some of the meaning of what you would see in Objective-C plus the boolean value itself.
But I agree with the general point of your post. It is generally not a good use of time to make sure every line of code is readable. Instead, refactor when you encounter a particularly messy part that you need to modify, and make sure that at least readable method names hide the most unreadable implementation guts.
April 6th, 2007 at 12:21 pm
Code may not be read very often, but when it is, it takes an inordinant amount of developer time to thoroughly (re)assess all the implications of changing it. Falling short in this scrutiny is what leads to unknown undesired sideeffects which take even more time to track down . . . usually after the product ships.
April 6th, 2007 at 6:27 pm
I’ve seen suggestions to always use Enums instead of bools for better readability.
Then you could do something like:
HANDLE myHandle = CreateEvent(myAttrs, ManualReset, NoInitialState, "Ouch");
April 7th, 2007 at 8:12 pm
I’ve always thought the theory of readable, appropriately-commented code was compelling.
Recently, my boss said that our company has signed agreements with Tata and Infosys to outsource our work to India. I’m glad that I have not really kept up with the theory of making my source readable.
So, from now until the time I get fired or quit, I’m going to sharply increase my use of goto’s, replace my scrupulously #define-d constants with mysterious “magic numbers” and start using Latin for variable and function names. F*cK them!
April 7th, 2007 at 8:31 pm
macFanDave: I can appreciate your frustration, but I think the venom against developers from other countries is uncalled for. I hope you keep your job, but any further comments here along the lines of “Eff Them” will be deleted.
We should look at globalization of the world as a positive, not as a negative.
April 8th, 2007 at 9:09 am
Daniel,
I apologize for the misunderstanding, but my “eff them” was directed at my greedy, treacherous corporate overlords, not at fellow developers overseas.
Frankly, when I get to the point where I can outsource myself, it will be time to go anyways. The code base I work on is far from that point. I work for a manufacturer that requires customization on a per-piece basis (our product sells for $20,00 to > $100,000 a pop so customer demands for bells and whistles are justifiably honored.) The problem is that product engineering is unable or unwilling to give us their methodology unequivocally. It is unclear whether it is stupidity, laziness, or a turf battle that prevents them from letting us automate some of their daily tedium, but it provides us with endless opportunities to guess how they do their work and to respond to their fickle demands. They are hardly a group that has defined its problem well enough to engage outside contractors (local or global).
For example, we had a New England firm bid on a project for about 7-10 times an average engineer’s salary and wanted 15 months after receiving the complete spec. Well, another guy and I did it in-house in 9 months, and through weekly meetings with engineering, the spec constantly changed. The point is that our customer is so fickle, their efforts to engage outside contractors are doomed to failure, no matter where they are located.
Globalization where capital and goods can flow freely, but labor cannot is disasterous for all but the elite. Engaging in international trade must be done soberly and not under the rubric of deceptive slogans like “free trade.”
April 8th, 2007 at 9:12 am
Thanks for clarifying your points. I agree that globalization is a tricky subject and has a lot of implications that should be dealt with by people smarter than myself.
April 9th, 2007 at 5:38 am
Daniel,
There are not very many people who are smarter than you ;-). You probably mean “people who have studied international trade more thoroughly than you have.”