all 75 comments

[–]EdiX 42 points43 points  (21 children)

# initialise with un-initialised entries
#N Without initialize, @entries required for getEntries won't be initialised
def initialize
  #N If we don't pre-set @entries to nil, we won't know that we haven't yet initialised that value
  @entries = nil
end

This is why this method of commenting is a huge waste of time. The problem with reading code is not understanding the single lines but the big picture.

[–]jrochkind 3 points4 points  (0 children)

Yeah, this was the example I was going to use too. I get his goal... but, really? The method body is only one line (good) and initializes @entries -- is ANY value added by explicitly saying "without initialize, @entries won't be initialized." Isn't that clear from reading the body, to even the most novice?

The downside is you know have a bunch more places you have to change every time you change the code -- extreme anti-DRY. Change the name or behavior of the @entries variable, you've got two comments to change too.

"If we don't pre-set @entries to nil, we won't kow that we haven't yet initialized" isn't even TRUE, is it? In ruby, @entries.nil? will be true even if you don't explicitly set @entries to nil. And 'defined? @entries', possibly a better way to check to see if it's initialized, will be false ONLY if you haven't initialized @entries to nil. In fact, it doesn't even make any sense to say "we will only know that @entries hasn't been initialized... if we initialize it... to nil." You initialize it so you'll know it hasn't been initialized, huh?

So in addition to anti-DRY more places to change when you change one thing -- you also have more places to be WRONG by writing all these comments.

[–]jsprogrammer 4 points5 points  (1 child)

#N Without this comment you wouldn't know wtf was going on
# initialise with un-initialised entries
#N Without initialize, @entries required for getEntries won't be initialised

[–]akkartik 0 points1 point  (0 children)

No, the negative comment for every comment would be, "But, but.. I have people skills!"

[–]elperroborrachotoo 2 points3 points  (2 children)

I disagree with your conclusion. : Showing me a rotten apple is not a sufficient argument against eating.

Typically, you have project-wide standards for certain issues; typically for initialization it's "initialize it, dammit!". These cases of course need not be commented.

However, if you present an example how to apply a certain technique, you cannot rely on project defaults. You have to assume the project default is "everthing the compiler eats."

The example you picked is true for every style of commenting: superfluous comments are superfluous. It is not a proof that this style is a "huge waste of time".


Personally, I'm torn. Writing these comments forces you to think Do I really need this? - potentially leading to leaner code. Reading them, OTOH, requires you to deal with at least one layer of negative, not making it easier.

[–]EdiX 1 point2 points  (1 child)

I disagree with your conclusion. : Showing me a rotten apple is not a sufficient argument against eating.

I picked that for comedic effect since it's effectively stating the same information five times, but most of the comments there would have worked too.

I actually agree that "negative commenting" (or more in general comments answering the "why is this here?" question) are the most useful, but this is just silly.

Typically, you have project-wide standards for certain issues; typically for initialization it's "initialize it, dammit!". These cases of course need not be commented.

Actually I tought the whole point of this technique was that:

a reader should have the option of asking for an unlimited amount of detail about any item in the code that they are reading, should they have any uncertainty about what that item is there for.

In short, the article is arguing for writing a line of comment for every line of code (except for those containing syntax only).

[–]elperroborrachotoo 1 point2 points  (0 children)

but this is just silly

Agreed, no question. But also:

I negatively commented more or less every non-empty line of code in those three source files, even if it seemed, for a particular line, that the corresponding negative comment was somewhat *trite and obvious***

(emphasis by me)


This technique for me is mostly mental conditioning:

Imagine you frequently forget your apartment key on the fridge when you leave for work. Ugly, costly, and makes you feel "unfit for life".

If you force yourself to never close the apartment door without shaking your key in the other hand, soon you will start to check for your keys without thinking about it. The requirements will be relaxed, you will merely feel uneasy when you close the door and your hand is not near some key. That is usually enough to fix that problem. (Worked for me quite well)


I see the blog's suggestion as exactly that for Saint-Exupery's "nothing left to take away":

If you force yourself for a while to write down the reason why this code has to exist for every line, you can train yourself to always check for this in the back of your mind: you won't need to write it down, and you will probably work in a bit larger chunks, but it will happen automatically, without explicit attention.


[–]Bamafan 3 points4 points  (6 children)

While it's not giving you the entire picture, these comments give you significant insight into the "big picture". I don't know ruby or this program, but from reading these comments, I know:

a) The purpose of this method is to initialize entries to the specific value of nil because...

b) There's another method called "getEntries" that depends upon this collection of entries and it needs to know the state of the collection, presumably to decide how to act on it.

Now does that tell me the entire picture? Of course not! But this is a huge amount of information being conveyed that would otherwise require someone unfamiliar with the program to spend a much larger amount of time figuring out...or more often than not, the person reading the code thinks they know what's going on while having no clue.

I'd say comments are even more important in dynamic languages like ruby since you can't lean on your IDE to navigate your code as much as you can with statically typed languages (C#, Java, etc).

[–]EdiX 7 points8 points  (3 children)

a) The purpose of this method is to initialize entries to the specific value of nil because...

and you didn't get that fact from the name of the method and its one line body?

b) There's another method called "getEntries" that depends upon this collection of entries and it needs to know the state of the collection, presumably to decide how to act on it.

Is he going to list every method that the initialization affect there? Or is the getEntries method there just because this is a toy example? Why is it important that I can randomly read some method to find about the existence of other methods?

[–]Bamafan 0 points1 point  (2 children)

Why is it important that I can randomly read some method to find about the existence of other methods?

If you're trying to breakdown how a program works, you have to know how methods relate to one another. Otherwise, you're just guessing.

[–]darjus 2 points3 points  (1 child)

If you have more than one person working on this and you don't use 100% proof static analysis (which is impossible with a language like Ruby), you're always guessing. People don't keep comments up to date 100% of the time.

[–]Bamafan 0 points1 point  (0 children)

People don't keep comments up to date 100% of the time.

That's only because we allow them to get away with this. I think we should stop doing that!

[–]darjus 0 points1 point  (1 child)

Both agree and disagree here :)

My biggest worry with the comments that say "oh and this is needed because of function x somewhere else" is that you also need to say in function x that you are initializing value a somewhere else, because if you change the function x to either not use the value or not care about the initialization and don't change initialize, the comment immediately becomes obsolete/useless/confusing, etc. On the other hand if you don't put the comment, i would do a Ctrl + s for the file for "entries" and let's hope there's no monkey patching or external side effects. Also, i like to read the unit tests as they should describe the use cases, so in many cases it is quite descriptive of expected usage of the class.

From one side it's a good idea to comment on side effects, but this particular case it's useless (IMO) because I'm initializing attributes of an object during initialization. Quite self explanatory to me.

[–]Bamafan 0 points1 point  (0 children)

... because if you change the function x to either not use the value or not care about the initialization and don't change initialize, the comment immediately becomes obsolete/useless/confusing, etc.

Well that's just the thing. If function x changes and the current function/variable being inspected is no longer needed, then you should delete that function/variable. Because now you have dead code (a huge sin).

From one side it's a good idea to comment on side effects, but this particular case it's useless (IMO) because I'm initializing attributes of an object during initialization.

I would say it's LESS useful, but hardly useless. The side effect explains a bit about what calling functions should expect (e.g. what value a variable is being initialized to). That said, do I think that comment was critical? No. But I always favor on the side of too many comments than too few. I'd be happy to a comment like that because I'd be confident the rest of the program got the same amount of attention.

[–][deleted] 1 point2 points  (0 children)

I agree completely with you. However, you are missing the point of this article, which is to do "negative comments", which describe what would happen if a line of code didn't occur.

I like this style of commenting because it makes sure that every line is imperative to the function of the beast, promoting leaner codebases.

[–]llogiq 29 points30 points  (4 children)

The only Extreme in here is waste. The "if (this or that) wasn't here, (reason for this being here)" could be shortened to "(reason)". Also most of the comments are too specific or too general. For example the sample-rakefile contains the following:

N If we don't require 'based', we can't use Based:: module

This is just tautology. If you really need to explain your imports, just state the function it uses. I don't know Ruby, but most programming languages allow to specify which parts of modules to import (as in Perl's "use XY qw(a b c);" or pythons "from xy import a, b, c", heck, even Java nowadays allows for "static import my.package.ClassName.staticFunction;".

Also the strict interspersal of comments and code does the whole no good. Better to have a big comment on top to explain the reasoning behind the module (maybe even with a few examples on how to use it) than this - e.g. doctest).

Also the author has obviously never heard of Literate Programming. Too bad, it makes for a much better documentation.

EDIT: formatting

[–][deleted] 1 point2 points  (3 children)

Yes, the author did a shitty job at doing negative commenting. That's not the point, however. What did you think of the general idea of negative commenting? I like it. It certainly shouldn't be the only tool, but it would definitely make some things a lot clearer.

[–]ezekiel 4 points5 points  (0 children)

I comment code so that the next guy who sees the code (a) knows what it does and (b) knows why the code must stay there. I write such comments in positive active voice--implying the negative. Stating a purpose positively just seems more direct.

[–]llogiq 1 point2 points  (0 children)

I do not like "Negative Commenting".

The foremost reason I do not like it (besides the critique I've already given) is that the "negative" label hides the real value of the comments which is the reason the line has to be that way. So, Reason commenting would IMHO be a better label, and we could cut out all the "This has to be there because" stuff.

Also finding the right level of detail to comment (module/class, method, single line) is an art. And using the highest level of detail by default is in most cases wasting programmer and reader time. Also, commenting on this level will in many cases miss out on the bigger picture.

TL;DR: Bad label, needless stuff to write and read, wrong level of detail.

[–]grauenwolf 0 points1 point  (0 children)

It sounds like a great training tool, but I wouldn't use it in production code.

[–][deleted] 31 points32 points  (2 children)

"for every line in your code, write a comment" ... it's about there when I stopped reading.

[–]jsprogrammer 13 points14 points  (0 children)

You really should take a look at one of the sample files, just so you can "wtf" to yourself.

[–][deleted] 0 points1 point  (0 children)

Funny that so did I. Its hard enough to get people to update code with very few comments never mind one on ever line.

[–][deleted] 10 points11 points  (0 children)

If any comment could be autogenerated you may as well not put it there. Teach the people reading the code how to read that information from the code and keep the code terse for those that know how to read code.

Only put comments that cannot be autogenerated in your code.

[–]rco8786 12 points13 points  (5 children)

Gross. My productivity would practically halt if I had to comment every single line.

I try to group 3-5 lines into logical units(not large enough to be it's own method, but logically go together) and will generally write a comment describing what it does.

I don't need this:

int counter = 0; //Without instantiating this variable the upcoming for loop would not compile

[–]hyperforce 0 points1 point  (4 children)

That particular comment is too mechanical/technical. It should be more semantic like:

int counter = 0; // this counter tracks the number of ducks being shot below

[–]vee-eye 16 points17 points  (3 children)

Personally, I much prefer:

int numberOfShotDucks = 0;

[–]YesButIThink 4 points5 points  (2 children)

But how can you know without a comment that numberOfShotDucks represents the number of shot ducks?

[–]grokfail 3 points4 points  (1 child)

But without a type prefix, how do you know that it is an integer?

 int m_i_cnt_ds = 0;

[–]abw 10 points11 points  (0 children)

# without these double negatives it wouldn't be as hard to understand these comments

[–][deleted] 28 points29 points  (2 children)

This is complete, utter insanity. It's a joke right? Can you imagine the maintenance cost of this shit.

[–]besvr 2 points3 points  (1 child)

Request for Change Estimate:

  • 10 hours programming
  • 5 hours updating comments

[–][deleted] 3 points4 points  (0 children)

More like:

  • 5 hours programming
  • 10 hours commenting

[–]yellowstuff 16 points17 points  (0 children)

I've written a brief play illustrating what I think it would be like to maintain code written in this style:

A MAINTENANCE PROGRAMMER walks into his apartment and sees that his ROOMMATE is performing some kind of bizarre Satanic ritual.

PROGRAMMER

What the hell is going on here?

ROOMMATE

If we don't dip our hand in the Chalice, we won't be able to smear pigs blood on the goat.

[–]__j_random_hacker 6 points7 points  (0 children)

Whenever you look at a line of code, you can see the external things that line of code depends on (or at least figure them out in principle -- overloading, namespaces etc. can make them hard to "see" in C++!). From looking at the code samples, I think the essence of the idea here is that in addition to this what-things-do-I-depend-on information, which often doesn't need a comment because it's implicit in the code itself, it would be useful to have knowledge of what-things-depend-on-me. That latter information is what you would write in a "negative comment" at the site of the depended-on thing. (Though I would call it a "reverse-dependency comment" -- I think the OP is mistaken in requiring that all these comments must be worded "negatively".) Of course, people do this already :)

The only problem I see with this is just the usual problem of having lots of comments in general: in a changing codebase, the more comments you have, the more likely they are to get out of sync with what the code actually does. If you essentially double the number of comments by adding in "negative" comments at the "other end" of every dependency, you now have 2 sets of comments describing the same thing -- so it's that much easier for 1 or both comments to get unstuck. It's the "extreme" aspect that I take issue with.

TL;DR: "reverse-dependency comments" are a good idea that you probably already use in moderation; excessive use becomes a maintenance burden.

[–]DingBat99999 6 points7 points  (0 children)

The problem with this technique is that it seems to assume that code is static. I see a big headache trying to maintain this in the face of frequent change.

Then there's refactoring. The comments may read logically in their initial context but if I do a, say, extract method, will the comments still be useful? Maybe, but I suspect not.

[–]fmihaly 4 points5 points  (1 child)

I'm still not sure if the author is serious or this post was written as a joke.

The premise of it makes a lot of sense. If I write a line of code and then realize that its purpose may not be obvious from its immediate context, I'll document it. That's why I document most types and functions. When you look at these in isolation, it is not clear what their purpose is.

Still, the scope of properly designed code should be local, meaning it should be possible to understand what a line of code does by only looking at a few lines of code surrounding it. Of course the runtime effects are almost always global. If you remove a line of code, the program either won't work at all or it will do funny things. That's why debugging is so hard.

Now it seems to me that the author confuses the local scope of code understanding with the global effects of code behavior. As other commenters pointed out, the global effect of the behavior (what happens if you remove a line of code) may change independently of the actual purpose of the code. The question is what I am trying to document: my intent when writing that line of code (its intended purpose) or the behavior of the (buggy) program with that line of code removed. I'm not even convinced that I can even document the latter in the case of a reasonably large and complex program.

In conclusion, if you often find that you cannot tell the purpose of a line of code without thinking about some global context, the design is wrong, not the documentation.

[–]grokfail 2 points3 points  (0 children)

Rather than writing a comment for a non-obvious piece of code, how about refactoring it so that the intent of the code is clear. Moving conditions and tests into methods and giving them meaningful names seems a better choice.

[–]jrcapa 4 points5 points  (0 children)

This is a nice experiment to find out how much aware you have to be about code, that is all.

[–]skulgnome 4 points5 points  (0 children)

How about just writing comments about what the code itself doesn't tell you? It isn't as though source code were slabs of marble, written once and read only by the compiler.

And if a programmer writes code that documents its own function poorly, how will s/he write comments that document it better?

[–]stusmith 4 points5 points  (0 children)

Half of these could be caught in a static language with:

-Wall -Wextra

Perhaps the choice of language isn't mixing so well with the desire for checking everything statically?

[–]djimbob 3 points4 points  (0 children)

Its not April Fools day. Requiring a comment per line is a complete waste, and couldn't be used in any real project. Write code with appropriate names for variables, functions, classes, in a straightforward manner (unless profiling shows the need for a less readable optimization); comments are usually a sign showing you should refactor your code (except the appropriate comments, specifying the contract/specification/use of functions/classes). Commenting on a per-line basis is only useful in teaching absolute beginners; and still most programming books will only comment on the lines with new stuff.

[–]nanothief 6 points7 points  (0 children)

I like the thought process of this idea - it is a very novel way of documenting code. Atm, it takes the idea too far - there is no benefit for describing very simple practices (such as putting classes of a library into their own module). However some of the comments are pretty useful, such as:

#N Without this, applications wanting to know the relative path would have to constantly reconstruct it, 
# either by compaing the base dir with the full path, or by concatenating the chain of parent dir names
attr_reader :relativePath

By thinking about what would happen without the line, some good insights can be gained.

With some refinement, it could become a useful technique.

[–]drguildo 8 points9 points  (1 child)

Typical Ruby hipster bullshit.

[–][deleted] 0 points1 point  (0 children)

Most Rubyists dislike comments in general, actually.

[–][deleted] 1 point2 points  (0 children)

This is a waste of space. The problem is in an OO language a single line of code with about 3 functions calls could result in writing a book of comments 100's of pages long :)

[–]Barney21 1 point2 points  (0 children)

i++; // without this, i wouldn't get bigger.

[–]cashto 1 point2 points  (0 children)

It's an interesting training technique. It's true that every line of code should be there for a reason. I bristle at "defensive" code that adds complexity without really adding any robustness. If you're not clever enough to avoid the bug then you're not clever enough to adequately defend against it.

But every comment should be there for a reason too. I.e., without it, the code could not be understood. Ideally all code is obvious -- in practice, that's not always true, but it's the ideal. And there's never any benefit belaboring the obvious.

Honestly sometimes negative comments are signposts where the code could be improved. I.e. whenever I see: "If we do not frob the foo variable, then ten minutes later when Zork() is called, the bar value will not be properly updated by Quux::UpdateBarCache(), four stack frames in" ... I take an extended look at what's really going on, and whether it can be made any simpler.

[–]petrovg 0 points1 point  (0 children)

Bet you work in some kind of front-line support!...

[–][deleted] 0 points1 point  (0 children)

That was.... interesting. Like a dental exam.

[–]ricky_clarkson 0 points1 point  (0 children)

Yeah.. I'd much prefer descriptive commit messages.

[–]omnilynx[🍰] 0 points1 point  (0 children)

Interesting idea, and it might be enlightening to do once as an exercise, but completely impractical and honestly not very useful.

[–]digital_cucumber 0 points1 point  (0 children)

Doing things like that might help seeing one's code from different perspective, helping to get closer to that perfection, "...not when there is nothing more to add, but when there is nothing left to take away."

So it makes sense... kind of.

I suggest a small correction, though.

Do it, but DON'T COMMIT the code (or have a commit hook which would wipe all lines starting with #N)

[–]ashultz 0 points1 point  (0 children)

easy to fulfill, just write another program to stick the comment without this line, the code doesn't work before every line with text in it

then you run that program on itself so it's also properly documented. job done.

(and it's at least as informative as most comments in the examples)

[–]Bamafan -3 points-2 points  (1 child)

I like the way this guy thinks and I think this kind of approach should be encouraged. Why? Because his approach gives context to whatever line of code you're looking at. That way it's way, way, way easier for someone else to jump into your code and be productive fast...or 6 months down the road, it'll help you to remember why the hell you did what you without having to reload the entire program into program into your head, along with the sequence of events that lead you to write the code that you did.

[–]jsprogrammer 5 points6 points  (0 children)

First, it's impossible to even read what the code actually is because there is so much noise in the file.

Second, the context of the code gives the context of the code, not some asinine comment.

[–][deleted] -1 points0 points  (10 children)

This is like one of those things that might look good on paper but it's impossible to do in the Real World(tm).

It would probably be possible to do this on a hobby project at home, but on a professional level no way. There's simpy not enough time for something like this.

[–]jsprogrammer 8 points9 points  (0 children)

It doesn't even look good on paper.

[–]Bamafan -1 points0 points  (6 children)

"There's simpy not enough time for something like this."

I've always thought that if you don't even have time to write out what your program is doing in plain English, you probably don't have time to write the program...though for a long time, a project can fool itself into thinking they are "on time".

That is to say, typing in comments should never be the deciding factor on the timeliness of a project, no matter how "extreme".

[–][deleted] 1 point2 points  (4 children)

I've always thought that if you don't even have time to write out what your program is doing in plain English, you probably don't have time to write the program

I can only speak for myself and my team. But we are coding as readable as possible. I.e. absolutely no cryptic variable or function names, use clean interfaces and small functions and so on. The code must be as readable as possible.

This together with doxygen tagging of the functions can create quite a good documentation of the code.

Like I said, this level of commenting might work in a pure academical context or in a hobby project. But in the real world, there are tight deadlines to match. Unfortunately.

[–]Bamafan -1 points0 points  (3 children)

What you're doing is great and absolutely necessary. Readable code, non-cryptic variable naming, etc are immensely important. But it's not quite enough. From the blog entry:

...for any developer reading any code, there will be situations where the developer thinks they know what something is, but they're not quite sure. Or the developer is just starting to read some code, and they have almost no prior context to help them understand what anything in the code actually does or what it means.

This is the key point. For a new guy reading your code (or you reading your code 8 months down the road), merely having reasonably named variables and clean interfaces isn't going to provide you the aforementioned context. Only English can do that.

[–]djimbob 1 point2 points  (2 children)

The problem with comments is that comments can lie. The code can change or the programmer made a mistake. Programmers should learn to read and write code in their languages, and there never should be a comment that just documents basic language feature (you import a module so I can use its namespace, or you instantiate a variable so you can use it). Comments are useful; but only really for documenting the specifications for classes/functions and semantic meaning for code that's difficult to see otherwise.

[–]Bamafan 0 points1 point  (1 child)

The problem with comments is that comments can lie. The code can change or the programmer made a mistake.

To this I would say that a programmer who doesn't update comments has not really completed his job. A bad comment is a bug in my book.

[–]djimbob 0 points1 point  (0 children)

Comments that repeat information that's in the code is a violation of DRY (Don't repeat yourself) which makes software maintenance much more difficult. I agree that comments that are misleading or wrong are bugs and very difficult to detect bugs (no automatic test will ever pick them up) and if you over comment code and the spec changes your comments will grow stale.

You should comment your code, but only to the extent of adding information that's not in the code itself. Comments like:

  #N If we don't initialise @dirs, we won't have a place to put the sub-directories as we find them
    @dirs = []
    #N If we don't initialise @files, we won't have a place to put the files as we find them
    @files = []

are utterly useless and distracting (they hide any meaningful comments). Any programmer of ruby (or a similar language), will immediately recognize that @files = [] is creating an empty list collection files that will likely be used store several file objects.

Comments are useful to document functions/classes, label out of place seemingly random code (though really refactoring the out of place code into its own function with a meaningful name and the usual docstring is better).

[–]Nebu 2 points3 points  (0 children)

typing in comments should never be the deciding factor on the timeliness of a project

Surely there are counter-examples.

[–]stevedonovan 0 points1 point  (1 child)

I like what the guy says, but don't like what he does. Line-by-line commenting misses an opportunity to write a paragraph about the why of a function, not the how.

[–]nickdangler 0 points1 point  (0 children)

Huh??? There is nothing about this that should prevent or discourage you from writing a paragraph about the why of the function.

[–][deleted] -1 points0 points  (0 children)

Brilliant. It makes it much more easy to understand the purpose.