I recently imposed on myself the constraint of coding without comments. Why?
- Comments rust faster than code, even when you’re careful
- Well written code can be read, and comments are annoying footnotes
- Comments make for lazy coding
Now, setting the bar at no comments at all seems a bit fanatic, but any value greater than zero is an invitation to using comments when better approaches are available, and like any addiction, I bet you can’t stop at one.
The Traditional View
In Programming C# 4, we write,
“…so even if your code is sufficiently clear that it’s easy to see what it does, it may not be at all clear why it does certain things….
We then go on to give an example,
Frobnicator.SetTarget(""); Frobnicator.SetTarget("Norfolk");
and then suggest that a comment will clarify the purpose of the code,
// Frobnicator 2.41 has a bug where it crashes occasionally if // we try to set the target to "Norfolk". Setting it to an empty // string first seems to work around the problem. Frobnicator.SetTarget(""); Frobnicator.SetTarget("Norfolk");
You can, however, eliminate these comments by being willing to put that information into the method name,
private void SetTargetToEmptyStringToWorkAroundBugInFrobnicator() { Frobnicator.SetTarget(""); } SetTargetToEmptyStringToWorkAroundBugInFrobnicator(); Frobnicator.SetTarget("Norfolk");
What I prefer here is that the code and comments cannot get out of sync, and if the bug goes away, I just remove the obviously redundant code. Since I started this approach I’ve not found the need for comments (nor the need for such absurdly long method names).
NB: I’m not advocating (yet), just experimenting.
Beware of the temptation to refactor,
When I first wrote this, I was tempted to factor out the common code:
private void SetStringToEmptyToFixBugThenSetStringYouWant( string newString) { Frobnicator.SetTarget(""); Frobnicator.SetTarget(newString); } SetStringToEmptyToFixBugThenSetStringYouWant("Norfolk");
While this has appeal, the problem is that when the bug is fixed, I’d have to change every call to this method everywhere, rather than just eliminating the call to the fix. Ugly.
Of course, I could add comments to explain why the code no longer makes sense:
The last thing you want is to end up with code like this!
// no longer need to set the empty string private void SetStringToEmptyToFixBugThenSetStringYouWant( string newString) { // Frobnicator.SetTarget(""); Frobnicator.SetTarget(newString); } SetStringToEmptyToFixBugThenSetStringYouWant("Norfolk");
Yikes!
Pretty nice post. I just stumbled upon your blog and wished to say that I have really enjoyed browsing your blog posts.
After all I will be subscribing to your rss feed and I hope you write again very soon!
@Marko Acosta by the way, I know I made a mistake in the example of my comment, it was just to clarify when the comments get ridiculous, it was a a no sense function with a no sense procedure… (no body would do that example that way)
I think the author is missing the real point, if he is doing a single user simple application (like in the 90’s) with few lines of code(that he will mantain) then he has all the right to say that comments are useless… but in the actual world software is not mantained by a single developer but by a team of developers who think, reasoning and work very differently from each other, when the code grows (and always does) and needs more and more levels of abstractions it’s impossible to be guided on that mess only with “right name conventions”. If you ever worked on SOA systems using a lot of calls from different applications with different languages you know what I mean….
Naming conventions are usefull, but good comments are a must! of course you will miss to update a few comments in the progress but the most of the time they describe “why you did something that way” and not why you named it so obvious…
Althought I agree there are persons who actually get ridiculous with comments like:
/*
* PHP Ridiculous snippet that would get and age and name of a
* person object….
*/
public function get_age_and_name($person){
// Get the age of a person
$data[‘age’] = $person->get_age();
// Get the name of the person
$data[‘name] = $this->get_name();
// Return the values
return $data;
}
I admit it… it’s ridiculous…
No, it doesn’t have the same problem as a comment, and that is the key point. When the bug is fixed, you no longer have to call the method, true, but then you just delete the method and everything keeps working. Or, you call the method but you don’t need to, which is okay because it does no harm, and does not mislead, it is just unnecessary (which would be the case with a comment and still calling the method). The problem arises when you fix the code but not the comment, but that is impossible if the code is self-commenting. Could I come up with a better name? sure, how about WorkAroundSetStringForBug1413(string s);
What would be a good way to document that you used algorithm A, as prefered to B? Would you have to implement B and then not use it? Here are 2 examples:
int ImplementationA(unsigned int n) {
int count = 0 ;
while (n) {
count++ ;
n &= (n – 1) ;
}
return count ;
}
#define MASK_01010101 (((unsigned int)(-1))/3)
#define MASK_00110011 (((unsigned int)(-1))/5)
#define MASK_00001111 (((unsigned int)(-1))/17)
int ImplementationB(unsigned int n) {
n = (n & MASK_01010101) + ((n >> 1) & MASK_01010101) ;
n = (n & MASK_00110011) + ((n >> 2) & MASK_00110011) ;
n = (n & MASK_00001111) + ((n >> 4) & MASK_00001111) ;
return n % 255 ;
}
int BitCount(int n) { return ImplementationA(n); }
Does it help that there is no comment? Are you not affrad one of the implementations might have trouble with 0 or a negative number? Wouldn’t you want to know the programmer at least thought of tha possibility?
20 years ago, we were writing in C, one of my programmers would never use an int i in a for loop, because it wasn’t selfdocumenting. Needless to say, his variable iCounterFrom1ToNumberOfElements counted from 0 to the number of elements minus 1.
I think the code states that I used A, and my reasons are not something i’d typically document in a code file. But if you want to, by all means, use a comment; this isn’t meant to be a religious rite 🙂
Alternative answer:
public void GetFooUsigAlgorithmABecauseAlgorithmBSucks() {}
@Mike Brown
Mike, i can’t see that your code does what you intend it to do. As far as it stands now, it does nothing yet. This ‘full moon’part i expect to be hard if you can’t write: // see Knuth, vol1, page 123
I can’t get over the statement that commenting is lazy, crappy and will get out of sync with the code.
First it is more work to comment.
Second it is ridiculous to say its crappy, I think it is worse to write out long phrases as the method name.
Finally if your a disciplined engineer you keep up the comments, it isn’t really that hard.
My 2 cents
It is lazy not in that it is fewer keystrokes, but in that i t is less thought about naming your methods and your code. Let’s take it to reducto ad absurdum
// get the user’s age
int x = GetX();
// decide if drinking is legal
if ( x < zz ) { foo(); // reject drink } else { bar(); // serve drink, pardon pun } Yes, the comments clarify the code, yes the code is clear (now) as to what it does, but it is crappy code. int personsAge = GetAge(); if ( personsAge < GetLegalDrinkingAge() { DenyDrink(); } { ServeDrink(); } Look ma, no comments, and the method names are of reasonable length.
I found that good comments reveals the purpose of the code that helps other programmers to verify the code for its suitability in meeting the specified criteria.
And I find that good method names do the same but don’t rust nearly as fast. 🙂
public DateTime GetEasterForYear(int year)
{
var firstVernalFullMoon = GetFirstFullMoonForSpring(int year);
var firstSunday = GetFirstSundayAfterDate(firstVernalFullMoon);
return firstSunday;
}
I don’t need to spell out the other functions do I? It’s very easy to express intent in code. It’s also easy to spot a bug in the implementation because I’m breaking down each function to a single task. We’re not living in an age of 256k of ram anymore. We should err on the side of maintainability over performance because when performance becomes an issue, you probably should look at other solutions than inlining a few functions here and there.
Nicely done and a good illustration of ripping a straw man to shreds.
I *WANT* my code and comment to be out of sync when someone changes the code without doing a proper job. I need this signal. The assumption that you don’t need redundancy because perfect code can be written is false: Code that does not do what the programmer intended is quite common, and when you remove the intentions it can become a real pain. The SetStringToEmptyToFixBugThenSetStringYouWant example is only to underline how rediculous it is.
What about:
x &= (x-1) ; // clear lower bit, better make my intentions clear!
var S = new HashSet(); // why did i prefer a hashset over a list, did i think a all?
or just ANY optimizing algorithme
Challange: Write a clear routine that calculates eastersunday for a given year without comments. It must not only work correct, the reader must be ably to verify that what is does is exactly what you wanted it to do. (without testing it)
I won’t take your challenge. I take it as given that sooner or later I’ll run into a situation where a comment is easier, faster and less confusing than the convolutions necessary to do it in code.
I simply set the bar very high. Rather than zero, let me back off to asymptotically approaching zero.
And actually, for the record, i don’t think the example is rediculous.
Hi Jesse,
I agree with you. Comments get more and more useless over time, while code changes and comments don’t.
However, when you embed the comments into your properties & methods signatures then you need to maintain those as well. It would be wrong to change the content of a method and not change its name… so the discrepency between what-code-does and what-reading-the-code-tells-me remains.
Ben
Agreed, but note that the method is dedicated to doing just one thing, so if you change what it does, you need a different method, and yes a recompile. That latter is probably the real downside; but the truth is that a dedicated work around method is more theory than practice.
In any case frequent refactoring is a key ingredient in agile development so it isn’t a big deal.
I disagree. When looking at code, i like to scan the comments to quickly know what some block of code is doing instead of reading the code itself.
@Jesse Liberty
The comparison to the Taliban sounds like an “Ad Hitlerum” attack to me. I doubt I’ve EVER seen someone’s suggestion of coding practices compared to the Taliban.
With that said, I agree it very well may be an emotional trigger. After all we’ve been made to feel guilty every time we don’t add comments, now to say that comments are a crutch and instead we should focus on self-documenting code flies in the face of everything we’ve been taught.
I’ve written on this before in relation to the DDD concept of Intention Revealing Interfaces. But I did wimp out and say combine meaningful function names with comments. I think honestly though that following the domain driven path should naturally lead to a lesser need for comments.
Hey Jesse,
Great article, but I’m afraid that my supportive remarks were getting a little long and as they inevitably do, it turned into a blog post of its own. You can read the full thing here: http://blog.robertgreyling.com/2010/08/i-dont-want-your-stinkin-code-comments.html
Keep us posted on the experiment, I’d be keen to hear how your ideas progress…
All the best,
Rob
@The LudditeDeveloper
I’m sorry but to call it write only code is to misunderstand either what i’m advocating or how that term is used. Write only code is code that cannot be read, and that is exactly what I’m NOT talking about.
I lived through all those stages, and the problem we were trying to solve is the same problem we’re still trying to solve, how to make code that is easily read and easily understood by other programmers. I am NOT suggesting that you simply not comment (aha!) I am suggesting that you not comment because you don’t ever need to if you write code that is self-commenting. Oh. Right. Big difference that. And it is…
… look at the example i give in the article and please tell me why that code is harder for your graduate student to understand than a comment, and trade that off against what happens later when the logic changes and the comment does not.
All of this folderol about write-only and unreadable code is a straw-man argument. I’m certainly not arguing for obscure code, or “if it was hard to wirte, it should be hard to read.” I’m arguing that comments are a crappy, lazy, and way too easy way to document your code; that the right way, the only way that is guaranteed not to get out of sync with the code, is IN THE CODE.
In the seventies we had structured programming and the ban on the goto statement.
In the eighties we moved to ‘modular programming’ with ‘self-documenting code’, which at the time, meant the code contained sufficient documentation rendering any external documentation superfluous. The term ‘lazy programmer’ was applied to those who did NOT comment their code.
In the nineties we moved from index sequential file access to the relational database.
Today we have object oriented programming and a return to self-documenting code.
In the real world with implementation methodologies still an important factor in stage payments and customer acceptance and sign-off, just how many projects are getting through without ‘proper’ documentation?
The phenomenon known as
@Jesse Liberty
I can’t resist a comment.
Zero-tolerance is great exercise, not doubt but too strict for me and counter-productive in practice.
Herewith, five counter-arguments.
1. XML Documentation
XML documentation comments are a boon when they assist with usage. They are a requirement for product code (not my personal requirement but a market-driven requirement … and business always rules the roost).
2. Method Names Don’t Explain Anything
Let’s look at your example.
Your absurd method name “SetTargetToEmptyStringToWorkAroundBugInFrobnicator” is certainly indicative. But it’s not doing the job you say it is. It begins by making the same mistake as a comment … it tells me how the code works … “SetTargetToEmptyString” … which I can plainly see for myself. The only substantive aspect of the name is “WorkAroundBugInFrobnicator”. Ok … but what bug? What can you tell me about the bug and its consequences? Where would I learn more? You might as well call it “WorkAround_Frobnicator_42” … I might be able to look up #42 somewhere. THe point is that the method name isn’t giving me the information that your original comment did … or could have given. If that information is valuable to me, the programmer, then just give it to me in a comment.
3. Method Names Can Lie
Let’s also be honest about how little difference there is between a comment and a member name. Yesterday I was looking at some code I wrote a year ago. Nice “Log” method call sprinkled throughout. Happened to look at Log implementation … you guessed it … “void Log(string message) {}”. Never implemented.
Or how about this one, discovered at the top of the week, “CreateManagerFromPrototypeManager(Manager prototype)”. Hey … what could be clearer than that? Except it did no such thing.
4. Comment for Further Info, TODO, and Attributions
// Using “Sieve of Eratosthenes” because I’m no good at higher math
// TODO: will need something better to get to trillionth digit this year
// I got this great idea for zero-comments
// from my good friend, Jesse Liberty; see
// http://jesseliberty.com/2010/08/14/coding-without-a-net/?utm_source=feedburner&utm_medium=feed&utm_campaign=Feed%3A+JesseLiberty-SilverlightGeek+%28Jesse+Liberty+-+Silverlight+Geek%29
5. Justify your Choice
I’m writing a program to stuff a ballot box. The body of the main loop:
GetBallot();
MarkSarahPalinForPresident();
DepositBallot();
I know perfectly well how to mark the ballot for Palin. The mechanics of it need no explanation. But I think my readers deserve to know why we’re doing it. Enuf said.
—
Seriously, I’m onboard with the “No Comment” spirit.
I’m just unwilling to be meshugah about it.
I’ve wondered if some of the resistance to this idea is based on something emotional, like cognitive dissonance. The comment comparing it to the Taliban makes me think it may well be, especially as so many of the comments are in the classic “yes, but” pattern such as “yes, but not when you need to explain why” or “yes, but you still need the /// comments” etc. It is almost as if the mind rebels against the idea that every comment is an admission of failure. And indeed, who wants to agree that so much of our code, of which we’re justifiably proud, is such an admission.
But why should *why* be harder to self-document than *what*. In fact, isn’t that the whole point? What is a piece of cake, the code has no choice but to document the what. So, when you you say “yes, but not to explain why” you are really saying “yes, but no.”
@GraemeF
Excellent. Thanks, that is much better.
Uncle Bob has a great chapter on comments in Clean Code, and I haven’t needed to use them since I read that. 🙂
Don’t worry about fixing the bug as refactoring tools make it a trivial operation, but you could do it like this instead:
private void SetStringYouWant(string newString)
{
SetStringToEmptyToFixBugThenSetStringYouWant(newString);
}
private void SetStringToEmptyToFixBugThenSetStringYouWant(
string newString)
{
Frobnicator.SetTarget(“”);
Frobnicator.SetTarget(newString);
}
SetStringYouWant(“Norfolk”);
Then when the bug is fixed you can remove the inner method altogether without changing the calls or sacrificing readability.
Heh, I never comment (well, except for the occasional comment at the beginning of a large function summarising its purpose). I tend to work under the assumption that if I can’t figure out later what some code does, I should have written it better.
I agree 100%!
If you need a comment to explain something in your code, then the code is not clear enough. Almost 100% of comments could and should be replaced by better nomenclature of functions and variables.
//No comment
Interesting post. I am quite bad at forgetting to comment. The comment “so even if your code is sufficiently clear that it
Good XML comments that use the see, paramref, and typeparamref tags can alleviate a fair amount of the staleness problem since they are automatically modified in any refactoring in Visual Studio. I do like the idea as it applied to intra-method comments though. If you need to explain a method it’s probably better to do it within a remarks block in the XML comments. If those get outdated, it’d be instantly clear to the reader without cluttering up the code itself. And its much quicker to just select all the text inside of the remarks block and delete it if it’s stale than to go line by line deleting old, irrelevant comments.
As my opinion, we should use a comment in a right way. We need the comments for classes, methods and some situations inside the methods. I also knew the comments in code is useless, but in some case it also very useful for understanding the business of program. But any way, I also support the ideas from this article. IMHO. This article is very good for me. Thanks again.
Corey Haines makes a great point about the evil of comments in this Deep Fried Bytes podcast: http://j.mp/bMpDGk. On the first listen, I thought Corey was borderline nuts. Second time, not so much. Since then, I question my every comment critically–and am down to a very, very few. I’ve come to believe that most comments are just a lazy crutch. Write the code clearly and eliminate the need for inline explanation with good member names.
rp
@Anonymous
He did, but my point in this article was to take the stronger position. So far I’m finding that it is less extreme than it seemed at first.
In any case, I do think an argument can be made on both sides, but I’m intrigued by the notion that by eliminating comments I can, potentially create self-documenting (not write only) code.
@The LudditeDeveloper
Did you just quote Jesse’s own book to him? I think you did…
Maybe a little bit extreme and suffers from the usual extremist tendancies a la Tea Party’ers and the Taliban.
To quote from “Programming C# 4.0” by Ian Griffiths; Matthew Adams; and Jesse Liberty:
“There
Good thinking. The only other thing that remains is when an introduction to a complex bit of code would help another programmer. Not so much detail as why a general approach was taken.
I totally agree and have started doing this myself.
I can’t tell whether this is good or bad. But, I am sure it is interesting : )