> I've met a few senior level programmers who frown on detailed commenting (or commenting at all).
If they express those views, I wouldn't call them senior.
Commenting is necessary to express invariants, and to summarize complexity that would otherwise require each reader of the code to understand the code itself in depth.
Those are actually closely related things.
Very few languages are capable of succinctly expressing sufficiently detailed invariants. Some are better than others -- maybe they support Maybe monads instead instead of possibly-NULLs. However, it's rarely possible to express -- purely in code -- what the code is supposed to do, what the input is supposed to be, and what the output is supposed to be.
Failing to express those things means that any future reader/maintainer will be forced to trace your code, in its entirety, to reverse-engineer how it is probably supposed to work. In many cases said maintainer can never know for sure without tracing your code and ALL code that calls your code -- otherwise, any change to that code could break undocumented behavior that other code relies upon.
Anyone who advocates against comments is justifying laziness, and they're wrong. The only supportable argument for not commenting is if a language is sufficiently powerful and succinct enough to express all the invariants normally expressed through comments, as well as being readable enough to permit a future maintainer to understand the design of the code without requiring them to spend an undue amount of time studying its inner mechanics.
“Don’t comment bad code—rewrite it.”
—Brian W. Kernighan and P. J. Plaugher
Is that senior enough for you?
> Anyone who advocates against comments is justifying
> laziness, and they're wrong
No, they are actually advocating to put more effort in thinking about stuff: how you name your functions/methods/whatever, how do you name your arguments/parameters, how do you write the code itself.
To anyone interested I recommend to get a copy of "Clean Code" and read the relevant chapter. IIRC "Code Complete" mostly agrees.
No. Have you read 70s and 80s C code? Tried tracing through the original UNIX kernel sources? Tried working with them?
To understand all the invariants of one small aspect of the system quite often requires tracing through the whole system until you get to a well-documented input/output module point (via comments, man pages, or otherwise).
Also, the quote (aside from it being out of context) says to not comment bad code.
> No, they are actually advocating to put more effort in thinking about stuff: how you name your functions/methods/whatever, how do you name your arguments/parameters, how do you write the code itself.
You can't define all the invariants -- or summarize for readability -- in pure code.
They're actually quite decently commented. The functions describe what they do clearly, and the bodies show how they do it tersely, with comments around the sticky bits.
Have you read through the original Unix kernel sources? Claiming that they're uncommented and difficult to work with is surprising. (On the other hand, the directory structure could be better.)
Without tracing the backing kernel structures and the code that relies on them, please describe why sleep(chan, pri) works, and as a maintainer, what I need to watch out for when modifying that code.
What does swtch() do? What does issig() do? Does that mean it's checking for a signal during sleep? What signals could be generated? Under what circumstances do I need to check for those signals? Are there any race conditions? Does ordering matter? What happens if I move the call to issig?
Beyond the invariants, this code is NOT READABLE. I can't just glance at the comments for an atomic unit of 4-5 LoC and see what it does -- I have to examine the code in depth, running the logic in my head, and explore the workings that way.
Reading code without comments is like tracing out a circuit without a schematic or documentation. First you have to manually establish the what, and only then can you even start to spend your time determining the why.
I work on modern BSD code. It's better than this old stuff, and I still have to dig to figure out how/why things are supposed to work. It's a headache compared to properly commented and documented code, where I can just skim standalone units and know what they do without having to trace everything myself.
Of course you need context to understand code. You can't get away from that without essentially translating the rest of the code into prose and attaching it to each line. At which point there are enough comments that you need context to figure out which parts of them you care about, reading them becomes a chore, and they essentially become noise. I've seen codebases with insane levels of commenting. I found myself ignoring the comments and tracing through the code.
If the model is simple and the code is clear, learning the context becomes easy, and it fits into your head. Following code becomes easy.
Comments decrease the amount of code you must personally read and understand, and define invariants that can't be expressed purely through the code.
> At which point there are enough comments that you need context to figure out which parts of them you care about, reading them becomes a chore, and they essentially become noise.
I've never seen this outside of contrived examples from lazy developers that think they're too smart to need to comment their code.
> If the model is simple and the code is clear, learning the context becomes easy, and it fits into your head.
In other words, you must trace the entire system to understand it and then fit it into your head. This is not advantageous to maintainers.
No, just the part you care about. You do need a high level mental model of the system. I've never seen a system where this is not the case, regardless of the number of comments. Even literate programming -- or at least, the examples of it that I've seen -- suffered from this. (Amusingly, I found literate programming examples were often easier to understand by mostly ignoring the prose and looking at the code.)
> You do need a high level mental model of the system.
That is extremely time-consuming to build without code comments and documentation, regardless of how "literate" the code is, because code alone can not express sufficiently detailed invariants, and simple logical/atomic operations involve a non-trivial amounts of code. (especially when writing in C).
There's almost nothing I hate more than inheriting a complex uncommented code base and spending hours or days tracing out the code to build a high-level mental model, when instead, with reasonable comments, I could have had that model nearly immediately.
You want some sort of design document. Comments are not sufficient to describe the way that the concepts interconnect. They are almost always detail oriented, scattered and do not give the big picture.
Comments embedded in source code are singularly unsuited to giving the sort of interconnection of concepts that allows you to quickly and efficiently understand build a model of the system. They are a poor substitute for real documentation.
Something like this should always be present to describe the overarching structure of the system: ftp://gcc.gnu.org/pub/gcc/summit/2003/GENERIC%20and%20GIMPLE.pdf
http://gcc.gnu.org/onlinedocs/gccint/RTL.html
Incidentally, I'm not sure if you're familiar with literate programming. That's where the code is almost an afterthought to the comments. This is an example of a literate program: http://tug.org/texlive/devsrc/Build/source/texk/web2c/tex.we.... You may be familiar with it -- it's tex, the core engine used by LaTeX. Compiled to PDF, the source looks like this: http://eigenstate.org/tmp/tex.pdf.
Design documents are necessary, but are no replacement for comments. When working in GCC briefly, I found the design documents to not be nearly so valuable as the (few, poor) comments that existed in the code (objc).
The problem with comments is that they decay into irrelevance and worse, lies (that chapter of Clean Code will live with me forever). You can't write a unit test to ensure comment correctness, but you can for code correctness. Hence the code is the only reliable source of the truth.
Comments only decay into irrelevance if lazy developers don't do their job. Circularly, it's developers that don't write comments that claim comments decay into irrelevance.
However, for maintenance programmers to do their job, if the comments mostly describe the code, they have to ignore the comments. Why make the maintenance programmer's job any worse?
Good comments are golden, but bad comments (those that tell you what the code is doing or duplicate coding logic in the comments) are worse than useless because they make it harder to spot and read the good comments.
I think the only thing worse than an uncommented codebase is a codebase full of comments that tell you what the code is trying to do in full detail, every few lines.....
I work at a shop where we use comments sparingly if at all. Our primary product has 14m LOC and 400k unit tests. We enjoy over 75% global market share in our extremely lucrative industry. We didn't get where we are today by being "lazy" as you put it. Comments are by very definition a redundancy when the code is perfectly descriptive and self-documenting. Thus developers can get on with their job and be more productive when they don't have to duplicate their efforts for dubious benefit.
> We didn't get where we are today by being "lazy" as you put it.
The two are hardly correlated.
Have you ever worked with some of the Mac OS X code written by poorer teams? For instance, the security framework? The internals of that code is a disaster at best, and yet, the core OS enjoys tremendous success and market share.
> Thus developers can get on with their job and be more productive when they don't have to duplicate their efforts for dubious benefit.
How do you determine the invariants of your APIs when writing code against a module? I don't trust arguments that boil down to "we're much too important to waste our time documenting, code is perfectly expressive!"
It's not. You're just wasting your time somewhere else, in little tiny increments, every time you have to trace code a few steps down just to figure out what it probably is supposed to do.
Or, sometimes in BIG increments, when somebody new has to learn the code base.
> the core OS enjoys tremendous success and market share.
How is that relevant? OSX has at best around 10% global market share? I'm talking market dominance here.
> How do you determine the invariants of your APIs when writing code against a module?
We flick through the well-documented code just as you would largely ignore the code and flick through well-documented comments. Here is a simple example for you:
public class EntitySynchroniser : IEntitySynchroniser
{
public EntitySynchroniser(BusinessObjectFactory factory, IDirectorySearcher directorySearcher)
{
Argument.NotNull(factory, "factory");
Argument.NotNull(directorySearcher, "directorySearcher");
this.factory = factory;
this.directorySearcher = directorySearcher;
}
...
The arguments here are invariant - they must not be null. I don't need a comment that may or may not be written in precisely the same format between 100 developers maintaining the codebase. I simply look for the one call to Argument.NotNull that all developers use in this case. The code is MUCH more readable than if the constructor had a comment explaining that each should not be null, mixed in with explaining what each should do. I can also determine by file searching or through the IDE which methods have these requirements.
If readers want to know what this API is and what it can do they need only look to the interface, or the implementation of it's methods in the class. Each method explains what it does by maintaining the same level of abstraction within the method. Like:
public void MethodA()
{
DoFirstHighLevelThing();
DoSecondHighLevelThing();
}
void DoFirstHighLevelThing()
{
// do less high-level things
}
Each method call would maintain a constant level of abstraction so that the code is easily reused, easily tested and easily maintained.
> You're just wasting your time somewhere else, in little tiny increments, every time you have to trace code a few steps down just to figure out what it probably is supposed to do.
If I needed to figure out why code wasn't working the way it should what's to say a comment would be more forthcoming in explaining the reasons for the defect? Surely if MethodA did "thing A" but was really doing "thing B" the comment would tell me "thing A", therefore I'd be forced to examine the code further anyway, only I'd be hampered by the deceitful comment also? This is the nature of a defect - something that operates outside the documented behaviour of the system or module.
Not to mention that your stated opinion is that comments should explain the inner workings of things so that consumers can be well informed. This has the potential for exponential maintenance as really low level changes are made. Imagine that you change the conditions under which data access-level exceptions are raised. If anything that ever touched your data source explained what happened in exceptional circumstances you'd have to change hundreds or thousands of comments, or face the sort of comment rot I mentioned earlier. This is the real time waster!
> ...when somebody new has to learn the code base.
This is always going to be the case. Comments don't make this task any easier than a well structured codebase. A well structured codebase comes from developers making the conscious decision that any reliance on the crutch of a comment is a failure to write proper self-documenting code. A well-structured self-documenting codebase by definition requires no comments (except for the "why" not the "how", which I fully support doing by the way).
> How is that relevant? OSX has at best around 10% global market share? I'm talking market dominance here.
Fine, I'm familiar with OS X, but I'm sure there's equivalent stupidity in Windows.
> The arguments here are invariant - they must not be null. I don't need a comment that may or may not be written in precisely the same format between 100 developers maintaining the codebase. I simply look for the one call to Argument.NotNull that all developers use in this case. The code is MUCH more readable than if the constructor had a comment explaining that each should not be null, mixed in with explaining what each should do.
No, it's not much more readable, because if properly commented, I WOULDN'T HAVE TO READ THIS CODE AT ALL. Instead, my IDE or documentation browser would tell me, inline, exactly what I needed to know.
> If readers want to know what this API is and what it can do they need only look to the interface, or the implementation of it's methods in the class.
If you have to look at code's implementation, you've failed. Why isn't that code a black box to me? Why do I care at all how it's implemented?
Why on earth would I want to waste time doing that instead of instant access to high-level API documentation?
Moreover, it's a contrived example, because nullable/not-nullable is the least of an API.
> Not to mention that your stated opinion is that comments should explain the inner workings of things so that consumers can be well informed. This has the potential for exponential maintenance as really low level changes are made.
No, my stated opinion is that comments that are externally visible should document externally relevant invariants.
Comments that are internally visible should document internally relevant invariants (if the code does not adequately express those, as it often does not).
> A well structured codebase comes from developers making the conscious decision that any reliance on the crutch of a comment is a failure to write proper self-documenting code.
A well-structured code base comes from writing good code. Comments are part of writing good code. Self-documenting code isn't fully documented code, unless it's literally a literate programming language. Claiming otherwise is just an excuse for you to be lazy and not write comments under the misguided auspices of being much too smart to need them.
Sure, if I were publishing a public API I'd want to document the functions available, but the fact is, the vast majority of the code we write at my shop is not consumed outside our own codebase. Why duplicate the effort of writing documentation when everyone has access to the code? There is no benefit for us so we don't do it. We made that decision and it's the right one for us. Sure, you have a different situation and I'm sure using comments has helped and empowered your developers, but for us it makes no sense and is a waste of time.
I'd suggest you stop trying to tell the world that senior developers must conform to your narrow views (narrow, by the sheer size of the response against your point of view here). Calling people things like "lazy" and insinuating they inflate their own abilities simply because they don't do what you think they should do is a pretty trollish thing to do. You obviously missed the first point in the original link.
The beauty of literate programming, quite honestly, is that because of the way that the documentation and code are interwoven, it requires fewer code comments, and encourages both clear code and clear documentation.
Since you have already dismissed a well thought response, let's try irony instead:
"When you have spoiled ingredients, dispose 'em. Do not try to cover the bad flavor with condiments."
- Famous Master Chef.
"You see? Master Chef does not like condiments. They take away the natural flavor of the food and anyone who uses them is an idiot who never will be a true cook".
- Zealot Wannabe.
Actually the people I have met who tend to be most against documenting what code does with comments tend to have the best commented codebases I have ever seen.
You never specified that your backslash referred exclusively to comments that document what the code does. This kind of comments are in most cases the result of bad habits taught by introductory programming books and instructors alike, with possible one exception [1].
But comments are incredibly useful to document why code exists in the first place, what are the assumptions that must hold for it to behave as expected (including but not limited to preconditions, invariants and post-conditions), and possibly how to use it (if you are using some utility like javadoc to generate other types of documentation from source code).
[1] The exception I am thinking about is that in real life you cannot always deliver the best quality possible in your projects. You have to interact with horrible systems, make ugly tradeoffs and meet deadlines with limited resources. Things get convoluted from times to times, so the best you can hope for is to leave thoughtful comments explaining how some specially hairy component works. The maintainers of that software (including a potential future version of yourself) will be very grateful for this.
Agreed on this point. The idea is that the comments should have something to say apart from the code. You don't put a footnote in a book to repeat what you just said. You put one in to add a reference to something else, explain a caveat, or otherwise say something useful out-of-band.
In general, in my experience, the people who are most hostile to willy-nilly comments have some of the best commented code. They see the code as written both for the computer and the programmer, and the comments are thus either interface promises, or are footnotes. Most of the people like this I have worked with tend to produce extraordinarily readable code which contains a good number of comments which should be there. But the worst codebases I have worked with hands-down are full of comments.
As for your exception, I agree. I think it's worth flagging such comments however so that the reader immediately knows that this is a special clarification.
The last time I described what my code did, I was using Perl 5.6 or something and was trying to do a method call to a fixed name in a variable package and was having a horrible time. I ended up, I think, using the symbol table directly and the syntax was worse than hairy. It was downright misleading. So I added a comment something like:
# HELP! I can't find a better way to write this. The syntax is .... Anyone have any suggestions?
If you understand you are writing for a human audience and that your comments will be read only if generally useful, then the this leads to both code clarity and comment clarity. It may not always be possible to maintain and hence one would add comments explaining tradeoffs or flagging a section as unclear (and possibly explaining it). But these are avoided as best one can.
There are so many problems with trying to make up for unclear code in comments, that's a real losing battle. I recognize that it may be worth breaking that rule sometimes, but then it is worth noting that, and flagging it so that other programmers can see and fix it. A comment like "#FIXME: This code is unclear: What it does is...." is perfectly acceptable.
Comments are for collaboration. You do NOT want to make them even appear useful for debugging.
> that would otherwise require each reader of the code to understand the code itself in depth.
Is that a problem? Even in code that has good comments, I always skip the comments and go straight for the code. Comments are okay if the code needed to employ hacks for some good reason, but otherwise I've never met a function that I wish had them.
I often wonder if people come from different backgrounds, which leads to completely different points of view on the matter. Personally, I find code easier to read than natural languages, but that doesn't mean everyone is the same and I respect that you might find comments useful. But why then assume that everyone needs comments?
Wait until you start working on multi-million line systems in companies where nobody - and I mean nobody - understands everything, and the original authors of pretty much every subsystem has since left the company; and you need to fix 20 critical bugs in the last week before the thing ships. Clues that are more high-level than the code can ever be start being really helpful.
First, I think that requiring the reader to know the code in depth is a good thing. Comments should not be used to avoid this. Comments can decay in relevancy and, aside from function API documentation, should not be used in debugging. The way comments should be used is:
1) API documentation says this: does the code conform? If not, either the specification is bad or the code is bad.
2) Comments inform collaboration, but do not inform debugging other than as API documentation.
I do agree that there is merit to documenting public interfaces, but there are tools designed specifically for that job so that you do not have to go slogging through the source code at all when you want to look up a definition.
As a result, I feel that is a different matter to commenting for the purposes of code maintainability, which is what the parent poster is speaking to.
Yes, because it means I might need to read 6 layers of code and wind through multiple modules, instead of just reading the top layer that defines the invariants of input/output for a module.
When you document an API you make a promise to the programmer. If you use the API according to the documentation, the API will behave according to the documentation. Documentation of API's establishes interfaces. If the code doesn't conform to the comments describing the API, it is the code's fault not the comments' fault.
I don't think people here are even against commenting code. I think people here are against (and for good reason!) duplicating coding logic in comments designed to describe in line-by-line detail the code that should have been readable in the first place.
Comments like that are FAR worse than no comments at all. If there are no comments at all, a new comment that is clear and relevant will be read. If you have a codebase full of bad comments you cannot start adding good comments until you clean that up.
> If they express those views, I wouldn't call them senior.
I wouldn't be so hasty as to assume that anyone making the above claim should be taken literally. Indeed, frowning on detailed commenting (or commenting at all) seems more like hyperbole then anything. After all, what is "detailed commenting"? It's not indication of quality.
// Increments x by 1
x++;
That is a detailed comment, but hardly worth while.
And the commenting at all remark does not indicate that all commenting is to be avoided. Rather that comments should be scrutinized. After all, comments are indicative of a confusion. If your code requires a comment to explain itself, maybe it's best to review what you are doing, and work to avoid confusion.
> it's rarely possible to express -- purely in code -- what the code is supposed to do, what the input is supposed to be, and what the output is supposed to be.
It's actually fairly easy to do that in all languages I'm aware of. It's part of the reason you have Unit Tests. To document what the code can do, but also the expected input and output. More often than not, we forget that.
I dislike the idea of promoting comments for the sake of comments. I much prefer the push for clarity in code. Limiting clarity to comments is bad form, and generally those pushing for lots of comments excuse confusing code because they use comments freely. They also believe that these comments will remain relevant, and make the call that should they not, it's not their problem, but the programmer that fails to update the comment.
This is akin to blocking user out of an account after the first wrong password entered. It's their mistake, after all. And our jobs as programmers are not write robust code. Comments cannot (and should not) affect that code, and relying on comments to provide the quality missing from the code is lazy.
> Unit tests validate invariants, but they don't express them in a concise form
I'd be more in line to say that if your Unit Tests aren't concise, then it's a problem with your Unit Tests, or at least, your implementation.
> and they're not a suitable form of documentation
Well, the output that you can generate form unit tests can easily be documentation, explaining in great detail exactly what can be done with what is being tested, without any hand waving either.
Still, that doesn't take away from everything else I said. In the end, if you rely on comments to explain your code, your code is probably lacking.
> Anyone who advocates against comments is justifying laziness
That is a gross generalization. I do not, in general, comment my code (and I know and work with many other programmers who do not) but I go to great lengths to ensure that my code is easily understandable. Commenting is not the only way to communicate intent.
I suspect we work in different sections of the industry, but in my world, comments are often a red flag rather than a welcoming sight!
> That is a gross generalization. I do not, in general, comment my code (and I know and work with many other programmers who do not) but I go to great lengths to ensure that my code is easily understandable.
You're almost certainly not succeeding, because unless you work with a language far more expressive than one I've seen previously, then your code can not express all the information I need to work on your code.
A complete lack of comments is on my top three list of "bad times ahead" warning signs when I inherit a codebase.
The other "bad times" warning flags are:
* A lack of documentation
* A lack of automated tests (integration, unit, or otherwise).
These three things can make or break maintainability on their own, and they also often serve as a proxy indicator for just how much thought an engineer put into fully understanding the invariants and edge-cases of the code they've written.
The hard part of writing comments, documentation, and tests is in understanding invariants and edge-cases. The easy part is writing down what you've understood.
> I suspect we work in different sections of the industry, but in my world, comments are often a red flag rather than a welcoming sight!
Unless your section of the industry has no interest whatsoever in maintainability, I'm not sure our respective sections are very different.
You seem pretty convinced, so I don't have high hopes of changing your mind with a post on an internet forum, but in my experience most comments can be replaced by clearer names, better abstractions and better tests. The ones that can't tend to be about the "why" rather than the "what".
>Unless your section of the industry has no interest whatsoever in maintainability[...]
My primary motivation is maintainability, and your claims to the contrary come across as pretty condescending.
> My primary motivation is maintainability, and your claims to the contrary come across as pretty condescending.
It's simple frustration with ego-based arguments from programmers that ultimately results in poor code bases.
Ego-based programming arguments are predicated on the idea that those that fail to deliver clarity must simply not be smart, wise enough, or skilled enough -- whereas with just a sufficient level of intelligence and skill and wisdom, one can produce lofty, comprehensible, elegant code.
If there's one constant I've found in my career, it's that everyone is dumber than they think, and everyone screws up. The ONLY thing that produces high quality code is careful attention to detail and slavish devotion to documenting and testing.
It's no different than any other pursuit; even a master carpenter will draw up plans, follow them, and measure twice (or three times). To think that one is smart enough to write perfectly literate code is foolish, and to force your future maintainers to deal with your uncommented code is to foist the costs of your short-term decisions onto them.
Comments in the body of a function should never be necessary for maintenance. The most unmaintainable code I have ever had the displeasure of working with was code which either had no comments or documentation or code with sparse documentation and LOTS of code comments.
If comments are necessary for maintainability, a simple solution is to flag the comment with a FIXME tag so that the next guy reads the comment and realizes that a section of code is unclear and should be looked at with extra care.
That isn't to say I am against code commenting. I find that when I follow my own code commenting practices and try hard to avoid using comments to explain code, I still use them frequently, probably more frequently than average. I am just saying the purpose needs to be clearly thought out.
In my view, the most important thing is interface documentation. This is a promise to the programmer, and it forms the basis of what you might think of as a development contract. You write your code this way, call the function this way, and you will get a certain return result. To a maintenance programmer, then, the question is whether the code works and by "works" I mean whether it fulfils its part of the contract by implementing what the comments promise. If a caller is requiring a corner case, then that can either be added to the documenting comments (i.e. adding to the promise) or the caller can be changed. So these comments are of vital importance and I see nobody arguing against them.
But within a function body things are different. Comments can be helpful here for collaboration and future development (and a subset of this is maintenance, but if you mind the rest this will take care of itself). A good maintenance programmer knows when to read the comments. if the comments describe the code, a good maintenance programmer will ignore them all in order to focus on what the code is actually doing and whether it fits the API docs. Bad comments then hurt more than they help and this includes comments which needlessly describe what the code is doing.
On the other hand good comments are golden and these either flag potential issues for the programmer (# BE CAREFUL OF SQL INJECTION HERE BECAUSE WE CAN'T USE PARAMETERIZED QUERIES!) organize code (# variable declarations) or add footnotes so that it is clear why a given choice was made (# RFC XYZ specifies a max timeout of 120 seconds).
The hostility is not to comments in code. The hostility is to a certain common practice, whereby comments duplicate code. There is no case where this makes sense without flagging the issue to a future programmer and noting that a rewrite is in order.
That's why you "Inherit a codebase", as opposed to "Build a codebase". People who maintain and people who build are... well... they're just different people. We do need them both, but, they are different. Which is why we need them both.
People that build with no regard for future maintainers are building code incorrectly.
It makes me happy when I hand off a code base and the receiving maintainer actually tells me that they appreciate how clear and understandable it is. That's a level of care I wish I always inherited.
Maintainers versus builders aren't different people -- that's just what intellectually lazy programmers tell themselves when they're making another mess for someone else to clean up.
I don't think that is necessarily the case outside a corporate environment. I inherited the SQL-Ledger codebase when we forked to LedgerSMB. Now I am using it as scaffolding to build a very nice, clean, powerful codebase in its place.
Well, I inherited a codebase where all comments fell into two groups:
1) Copyright notices and brief (1-2 line!) file-level descriptions at the top of each file and
2) Comments that the code needed to have in place in order to run properly... Delete the comments and things break. I am not kidding.
Oh, no documentation and no unit tests either. We started adding unit tests and found that things like number rounding failed.....
Years later we are still replacing the old code as fast as we can. The obvious things including braindead security issues, were just the absolute tip of the iceberg.
Nowadays I write my documentation first, then code, then at least some tests.
I do not, in general, comment my code (and I know and work with many other programmers who do not) but I go to great lengths to ensure that my code is easily understandable. Commenting is not the only way to communicate intent.
I agree that commenting is not the only way to communicate intent.
I don't know what you mean by commenting code though. I find in general that the people who treat commenting as a last resort, and look for every other method to clarify code first, tend to also have some of the highest comment to code ratios, as well as the best comments.
This was driven home to me recently when I wrote some PHP classes for interfacing with LedgerSMB. I checked them into github and added the project to Ohloh, and was stunned when it said I had as many comments as code. But virtually all of these were interface documentation.
The problem with commenting code is that code is constantly refactored to deal with new invariants and edge-cases. What starts out as a great way to summarize the purpose and mechanics of a given function or statement becomes immediately stale once the function or statement is changed. In the best case, the comments are revised along with the code they describe.
However, everyone makes mistakes, as you have pointed out, and once a comment is forgotten during refactoring, that comment has become a liability to the future maintenance or use of the code it describes. Given that comments are, by definition, not executable lines of code, commenting errors do not show up in code execution. Since most bugs only become apparent because of incorrect execution, commenting bugs are difficult to spot. This is a problem when developers read the comment instead of the code to discover the purpose and mechanics of the commented function or statement, and can lead to further errors in client code of the function or statement when the called code doesn't conform to the specifications expressed in the comment.
Now the developer who has to fix the code has two things to debug; the code as it is written and the code as it is described in the comment. Which has authority? How do you prove the correctness of a comment?
You can prove the correctness of code, because it can be executed. You can test it using the scientific method, trace its execution paths at runtime and by reading the calling code. You cannot do this with comments.
Additionally, every line of source code is a liability to the maintenance of the code. Each line out source adds computational and mental complexity to the program they describe.
For these reasons, good, verbose variable and function names to describe the what, and corresponding tests to describe the how and why are superior ways to describe code over verbose comments.
The point of a summary though is to offer the promise of an interface. The code should implement the summary, not the other way around.
Code comments though are different. They are there to annotate code. They are incredibly useful in collaborative environments but only if they are used to organize, discuss, and debate the code, not describe it.
flatline3, I can tell you flat out that you are wrong. There are plenty of senior level programmers that are quite deserving of the name who deliberately comment very lightly if at all. There are also plenty of senior level programmers who think that verbose commenting should be required of everyone.
I have experienced both styles, both in forms that are implemented well and implemented poorly. I have read arguments for both sides. I have found that either can work well, and either can work out horribly. (Though attempting both at once is very much not recommended.)
Personally I prefer to work with (and write) code that avoids comments wherever I have any reasonable alternative (clear variable names, calls to descriptively named functions, error checks with error messages that make it clear what I was trying to do, etc). However when all other alternatives fail, I do not hesitate to comment.
The most important case where there is no reasonable alternative is in descriptions of an API. The code that is there is how it happens to work right now. If you want to know what you can rely on to remain true in the future, read the documentation. Anything not documented is not part of the API, and you should be prepared to find it changed in the next release.
> There are plenty of senior level programmers that are quite deserving of the name who deliberately comment very lightly if at all.
Senior in name (and possibly years) only. I've spent enough years cleaning up messes to know that master programmers:
- Design carefully
- Comment liberally
- Test thoroughly
Thus they produce clean, well documented, understandable code. Skipping any part of that list is foisting delaying the cost for a much larger later reckoning of some poor future persons.
You might get away without commenting, but you're not doing anyone any favors. Skip all three and you're incurring significant technical debt.
I have no respect for programmers that think their sole job is to write code (no matter how "descriptive" it is).
> The most important case where there is no reasonable alternative is in descriptions of an API. The code that is there is how it happens to work right now. If you want to know what you can rely on to remain true in the future, read the documentation. Anything not documented is not part of the API, and you should be prepared to find it changed in the next release.
All functions are API. Some is mutable, because you can check and modify all callers. Some is immutable, because you can't.
It all needs to be documented, and the cost for not doing so can scale exponentially as a code base grows.
Ah, the "no true Scotsman" fallacy. No matter what someone has accomplished, no matter how much experience they have, you're the judge of whether they are really a senior programmer. And all who do not meet your standards are not senior programmers and are therefore not data points counter to your position.
Read the source code for Arc. You'll find that Paul Graham is not a senior programmer by your definition. Read the source code to some of Damian Conway's modules. You'll find that Damian Conway is not a senior programmer by your definition (though his stuff does usually come with wonderful documentation). There are plenty of other examples of talented programmers in your books are not senior.
From where I sit, I know nothing about you other than your account is about 2 months old and this discussion. In particular I know nothing of what you've done. However people that I respect a heck of a lot more than you have defended very light commenting styles. I've seen it work. I've also seen it fail. Ditto for heavy commenting styles.
Therefore, based on my own experience, I'm going to say that it is complex, with valid arguments on both sides. Which puts me on about the same page as Steve McConnell's book Code Complete.
But I'm going to go further. The downsides of a comment heavy style have to do with the possibilities of the comments being misleading. People have to be very, very careful to maintain comments along with the code. Based on what I've seen, I would personally not trust any team of programmers to do this reliably without having careful code review processes. If you have this careful code review process to alleviate the potential issues with commenting, I would advocate a much heavier commenting style.
But there is one line that is very important that explains a lot of the difference:
It all needs to be documented, and the cost for not doing so can scale exponentially as a code base grows.
There are a lot of problems that scale non-linearly as a code base grows. There are two possible responses to this. The first is to try to create procedures to alleviate the problems that are intrinsic to growing code bases. The other is to maximize what can be done without growing your code base.
There is a fascinating data point on this that is cited in Software Estimation: Demystifying The Black Art. For projects of a fixed size (about 50k lines of code) there is a graph based on real world estimates of months to completion versus team size. Initially as teams grow, calendar months fall. Then the graph bottoms out with teams of 6-8 people. Then it starts to rise. And then falls again. It isn't until you get to teams of about 20 people that calendar months fall to the same level. (Given that lines of code was the measurement, it is likely that the productivity of a 20 person team was overstated.) And then they start to fall further.
If your experience is mostly on teams of 12+ people, your observations about software development will be very, very different than if your experience is mostly on teams of less than 8 people. What works for those types of teams teams is very, very different. And given the huge productivity valley between small teams and large teams, there are a lot of problem areas where the right approach is to maximize what can be done by small teams, rather than to figure out how to build procedures to scale to (the now inevitably necessary) larger teams and code bases.
(If your experience is with larger teams, your first encounter with the potential productivity on small teams can come as a shock.)
If they express those views, I wouldn't call them senior.
Commenting is necessary to express invariants, and to summarize complexity that would otherwise require each reader of the code to understand the code itself in depth.
Those are actually closely related things.
Very few languages are capable of succinctly expressing sufficiently detailed invariants. Some are better than others -- maybe they support Maybe monads instead instead of possibly-NULLs. However, it's rarely possible to express -- purely in code -- what the code is supposed to do, what the input is supposed to be, and what the output is supposed to be.
Failing to express those things means that any future reader/maintainer will be forced to trace your code, in its entirety, to reverse-engineer how it is probably supposed to work. In many cases said maintainer can never know for sure without tracing your code and ALL code that calls your code -- otherwise, any change to that code could break undocumented behavior that other code relies upon.
Anyone who advocates against comments is justifying laziness, and they're wrong. The only supportable argument for not commenting is if a language is sufficiently powerful and succinct enough to express all the invariants normally expressed through comments, as well as being readable enough to permit a future maintainer to understand the design of the code without requiring them to spend an undue amount of time studying its inner mechanics.
I'm not aware of such a programming language.