Hacker Newsnew | past | comments | ask | show | jobs | submitlogin
On Comments in Code (henrikwarne.com)
179 points by nikbackm on June 15, 2021 | hide | past | favorite | 232 comments


Another use for comments: to document the strategies you tried and why they failed.

In other words not just the "why" but the "why not".

Many times I've gone back to code I'd written previously, it seemed overly complicated, I replaced it with a simpler version... that failed... that reminded me that was what I'd tried originally and then replaced it with the more complicated version for a good reason.

So now I have a new rule: every time I try a simple approach and it fails and I replace it with a more complicated one that works, I add a comment explaining the previous strategy and why it didn't work.

Hilariously, some of these have grown to several failed attempts. "Tried A library but it has a critical bug where B happens. Then tried C function but it also has a bug where D happens. Using external command E doesn't work because F..."

But hey -- neither I nor anyone else will try to reprogram something simpler. Or we can check if the library mentioned still has the bug in question.


//

// Dear maintainer:

//

// Once you are done trying to 'optimize' this routine,

// and have realized what a terrible mistake that was,

// please increment the following counter as a warning

// to the next guy:

//

// total_hours_wasted_here = 42

//


The inverse of this is also useful:

// Dear maintainer,

// The code which follows was hacked together under desperate pressure.

// It's not smart. // It's not doing anything really subtle. // It's the only thing we could get to work in the time.

// If you want to chuck it and replace it, you absolutely should.


Hey, that one I actually can replace with self-documenting code! Oh joy!


It's useful, until you realize you have this on 90% of your code.


That's when a full rebuild can be justified.

I'm doing that atm, but I think my predecessor lacked the humility to admit that his code was bad, which is how it went up to 150K of code that basically concatenates XML, converts it to JSON and concatenates HTML on the front-end from the result.


Not a bad idea.


My code would probably be better served by:

This place is a message… and part of a system of messages… pay attention to it!Sending this message was important to us. We considered ourselves to be a powerful culture.

This place is not a place of honor…no highly esteemed deed is commemorated here… nothing valued is here.

What is here is dangerous and repulsive to us. This message is a warning about danger.

The danger is in a particular location… it increases toward a center… the center of danger is here… of a particular size and shape, and below us.


I refer to this type of problem a lot when arguing comments are useful. No amount of code can document the code that isn’t there for a reason.


Or you can write tests for every single not there case. Just bringing it up, I usually write lots more comments than tests. I also encourage my teammates to add comments. The problem is when one can't really explain why the simpler approach didn't work. That requires more research just to write the comment, but I think it pays off really quick.


Tests are useful, but the big reason that comments are useful is that they are co-located with the relevant code. At the moment, I don't know of any tools that allow you to 1) specify which lines of code are directly relevant to a particular test case, even when the surrounding code changes and 2) see a list of test cases related to the currently highlighted line.

I'm sure it would be possible to build such a tool, but the complexity is quite substantial compared to a simple comment or two. If you really want to go the full-test-coverage route it makes a lot more sense to focus that energy on pure/immutable/statically-verified programming rather than some finicky test cases that add substantial maintenance cost to the code.


> Tests are useful, but the big reason that comments are useful is that they are co-located with the relevant code.

That's a not-often-talked-about (that I see anyway?) thing I really like about rust - I don't get to use it much, but when I do I think having 'doc tests' alongside comments heading a function and 'module tests' at the bottom of the same file is great.


Exactly. And then the question remains: why? Why hate comments so much? I never got that


I would conjecture that it has two components:

1. Ancestral memory of programming in languages like assembly or early Fortran where your code was going to be spaghetti because the language was capable of little else, so it had to be drenched in comments that would be unnecessary in a better language.

2. Overreaction to personal memory of overzealous professors who demanded assignments be drenched in excessive comments.


Related to #2, I'm still recovering from high school AP English. We had to meet quotas for a certain number of underlines / notes written in the margin per page. For the better part of a decade I haven't been able to pick up fiction without the feeling that I'm working through a textbook.


Until the code changes, then the comments are usually worse than nothing


No. Comments are like a parity check. If the comments don't match the code, then you know that either:

1) The comments are correct, but the code is wrong. This is a bug. 2) The comments are wrong, but the code is correct. This is equally a bug. Whoever makes the change has an obligation to describe their changes with a comment.

Code with no comments? Could be right, could be wrong, who knows?


Good luck maintaining that.


I wish I could upvote your comment more, but putting it in my bookmarks will have to do for now.


I've seen this counterpoint brought up many times before, but I'm struggling to think of the last time I experienced it. Is it really a common problem for you?


Yes, the issue isn't that most comments are inaccurate, it's that the inaccurate ones are so costly. When the comment doesn't match the code, it makes you question the code and the intent. 90% of the time, comments are accurate or just redundant (the code is descriptive enough), but that 10% of the time when the comments says A and B is happening, I end up chasing down whoever or digging through changelogs and tickets to find the comment wasn't updated.


For the kind of code comment we started this thread talking about (explaining why some simpler/more obvious process is not used), this seems vanishingly unlikely.


Then you fire the coder who changed the code without updating the comments?


Most code doesn't need comments.


That's a waste. Just train them better.


> The problem is when one can't really explain why the simpler approach didn't work.

Another benifit I have found is that in studying the problem to understand why the simpler approach doesn't work, you find out that it can actually work.


I love having commentary like that around, but I prefer to keep it in either the commit message or (more frequently) in the issue thread linked to from the commit. That way I can use as much space as I like for it and the timestamps make it clear that it's historical commentary, not a description of how the code works right now.


Some people advocate putting lots of stuff into commit messages, which makes me think I'm missing something -- commit messages are much less visible/accessible than comments in my workflow, so I don't expect my commit message to be seen.

Do you always read the whole git history of a file before editing it? What interface do you use for that?


An idealistic reason for encouraging longer-form commit messages is that they have the side effect of more coherent commits, making the history easier to navigate, making the history more useful, and so your workflow will probably use the history more.

A practical reason for longer-form commit messages even in modern PR workflows is that they allow you to create and view commentary on a group of changes across files without leaving your editor.

As an interface to git, nothing beats magit. Even if you never use Emacs for editing any text files, it's useful as a magit runner.


VSCode git-lens. Mandatory extension. Either way, I think both are useful, although for documenting weird code I think code comments are more important. I the commit message you should explain why you change the code. In the code, why it works like that.


gitlens is incredible. It passively educates on the git history so you learn about how old each section is and who was mostly behind it or worked with it last without ever requiring dedicated effort since it just sits there at the end of the selected line.

I still wouldn't use git as a replacement for comments since git history is wiped out all the time. Moving files or reformatting or a million other things could remove a critical commit message.


It’s super useful, rarely, when things haven’t moved around or someone wrote a good commit msg.


It’s a dumb idea, because that content gets lost as soon as you move things around.


Counter-point: moving things around in a way which doesn't preserve history is a dumb idea.

Moving/renaming a file? Commit the deletion and insertion together, preferably with no other changes (including to the contents of the file; commit those afterwards). In the best case, VC will treat this as a move and showing the history will include that of the old place/name. In the worst case, that history of file 'foo' will "end" with a commit like 'Rename bar to foo', with a diff showing the content moving from 'bar' to 'foo'; we can continue reading the history by switching to 'bar' if we want.

Moving code from one file to another? Similar story: commit the insertion and removal together; preferably with little/nothing else in that commit; preferably with a commit message explaining the change. This way, the code doesn't appear from nowhere in the commit history: when we look at the commit where it appears, we will also see where it came from before.

Moving a file from one repo to another? Dump that file's history as a patch, apply that patch in the new repo, then clean up (e.g. rename, move, etc. as appropriate). Alternatively, for larger sets of changes, add the old repo as a remote for the new repo, make a branch in the old repo which contains only those parts we want to move, fetch that branch into the new repo and merge it, then remove the remote.


> moving things around in a way which doesn't preserve history is a dumb idea

I don’t disagree with you but you can’t prevent it.


If you use an IntelliJ based IDE you can view commit entries for each line in the gutter.


I prefer comments but yes. If something doesn't make sense, one of my first things to try is to check the `git blame` and see if there's anything recent (or close to when the bug reportedly appeared, such as between two versions). Sometimes the commit message tells me something but usually not, but just looking up the ticket number from the commit message on our issue tracker can be enough hint sometimes. Especially on our SaaS product, if a problem just popped up in Prod and especially if the bug seems both easy to reproduce and feels like "wasn't us" I'll make a quick guess on a 'known good version', try to reproduce and the `git bisect` to find the culprit. Not to blame but just to figure out what's wrong in a very easy way. Sometimes I can fix it easily from that or ping the person who made the boo boo and they will usually know how to fix it quickly.

In the context of regular development? I almost never do any of that.


Not with every file but I have a question as to why something might exist or why it's implemented the way it is or it just doesn't look quite right then I'd absolutely go back and read the commit message that goes with the code - "Blame" feature works well here, I use TortoiseSVN.


The GitHub web interface, specifically the "blame" view for a file.


That only shows the most recent commit, which is IME often not substantive, just some treewide commit like "autoformat" or "moved class into another file" or whatever. I can click on the parent commit button repeatedly until I find all the info but that's really not a good interface for exposing the history of a class.


Each line in the GitHub web blame interface has a little icon which, when you hover over it, says "View blame prior to this change" - I use that all the time.


Yeah that's the parent button I was referring to in my comment.


I use fugitive, which lets me pop open a blame view for code I'm looking at and trace its lineage. It's often helpful, and when the commit messages are good, very helpful.


> I love having commentary like that around, but I prefer to keep it in either the commit message or (more frequently) in the issue thread linked to from the commit.

Having worked with codebases that have switched SCMs and SCM-adjacent issue management systems multiple times without retaining full history, I'd prefer to have the commentary in code even if it is also in those other places.


One caveat with this method is that your source control system evolves and things get archived. Code is around forever but everything around it may change.

10 or 20 years from now your code may still be running, the issue system or the git commit log may not be.


I am fiercely protective of my issue tracker and source history for exactly that reason. I have tools that can grab a full backup should I ever switch to something else: https://datasette.io/tools/github-to-sqlite


I find an issue link only works if e is a good enough comment alongside it (ie. Attempting to eliminate this mutex is bug prone, see <link> for archiyectures and their problems).


I also do this with optimisations, when I work on low-level code:

If I come up with an inefficient algorithm that's short and readable, I tend to optimise it to something better but leave the reference implementation inside a code block.

(This goes without saying, but: I don't leave "commented code", but code inside comment, generally formatted with Markdown)


Sounds like a good use case for property testing!


Is there a reason you don't leave a comment with the commit hash of the change instead?


Some day in the distant future someone will only have a tarball of the source of the last version that worked; if they're lucky.

Save that poor sod; have your comments live in your code, not in an SCM system for your code.


GPL has this idea in it: trying to define what exactly should go into that tarball. The question seems meaningful and important even for proprietary code. If some authors assume that anybody modifying their code should be able to look at git commits, that probably simply means that "the preferred form of the work for making modifications to it" is a git repo.


Yes, text is better for convenience and for being future-proof. It's like leaving a description of the bug I'm fixing, instead of just a JIRA ticket identifier.


not relevant: I often left comments that helped to explain my situation. One of my last comments:

> Resignation letter sent

Sometimes code is the only way to love and to talk with...

Edited: fix some typo errors


>Many times I've gone back to code I'd written previously, it seemed overly complicated, I replaced it with a simpler version... that failed... that reminded me that was what I'd tried originally and then replaced it with the more complicated version for a good reason.

>So now I have a new rule: every time I try a simple approach and it fails and I replace it with a more complicated one that works, I add a comment explaining the previous strategy and why it didn't work.

My strategy is to comment out the failed attempt and leave it there for next time.


I use a design doc for this in the style of a append journal. I made this decision a/e/i/o/u based on this and that. the why and the why not. Then I keep appending. easy reference.


If you have a unit test for that piece of code then that would probably help to act as a stopgap measure against attempting to "fix" the complicated-seeming code.


I mean sort of. If the goal of leaving the a comment about the approach that didn't work is to save somebody time before they try that approach again, a regression test is essentially asking the next developer to reconstruct a broken algorithm from thin air based a test. In my opinion, that's close to impossible. So the best case scenario is they re-implement the bad approach and it fails a test. They still wasted a bunch of time that could have been prevented with a simple comment.


Unit tests have a much bigger chance of being seen as well. There have been a few times where I will write unit tests that don't really test something is working but just check if it has changed. For example there is one table where every time you add or remove a column, you have to make a considered change to another section of the code.

Rather than adding a comment saying "hey make sure you change that other section" I have test which lists the columns in the table and fails if they change. Then the person who changed it will see the comment on the test explaining why it failed and what they must do.


The author touches on this a bit but I want to state this really simply:

Codes needs "why" comments, not "what" comments. The "what" can be done by self-documenting code, _most_ of the time. You still need to write "what" comments sometimes, don't rule it out completely. And you routinely need to write "why" comments, self-documenting code will never provide the context of "why".

Write more "why" comments.


> _most_ of the time

This is the thing that annoys me with arguments about all this. I will generally say "document the 'why' and not the 'what'; if the 'what' isn't clear from the code, fix the code to make it clear". And people will say "that's invalid because sometimes you really do need to do something clever and the 'what' needs to be documented" or whatever. And yes, that's fine! Stop taking everything people say as if it's an absolute, 100%-of-the-time statement! Obviously there are exceptions. That doesn't make the common-case rule useless or uninteresting. People should assume "most of the time" is the default implication about these sorts of "rules" unless otherwise noted.


I think people often lean too far in favour of "self-documenting code," and "what" comments wind up being underused. The idea of self-documenting code is that the documentation is encoded in the function and variable names, more or less. Sure, extraneous comments should usually be avoided, but frankly, sometimes a couple sentences of plain English is just clearer. I'd rather people just tell me what's going on than try to squeeze it in to a few camel-case words if that would compromise the clarity.


It's much easier to fool yourself into thinking you're writing "self-documenting code" if your "documentation" is just a natural language rephrasing of your code.


When your coding standard enforces 80 characters, you end with a single logical statement split across many lines. This quickly approaches un-readability if you fetishize self documenting code. In my opinion, short variable and function names with a comments are often more readable that self documenting behemoths, e.g.,

double compute_angular_acceleration_in_radians_per_second_per_second(double torque_in_newtons_per_meter, double moment_of_inertia_in_kilogram_meters_meters);

vs

// Units are base unitsSI.

double compute_angular_accel(double tau, double J);

I'll take the second any day.


What about the day the Mars climate orbiter was lost because one piece of code wrongly assumed that the units of figures out of the other piece of code? :)

I find that you do sometimes need symbol names that long even though it's a code smell indicating something else is up - usually scopes that are too large or insufficiently expressive types.

I view excessively long variable names as a midpoint on a journey to improving code quality on really bad code bases.


While what you say about long variable names can be right in certain circumstances, the example with the wrong units is inappropriate.

In my opinion any code that deals with physical quantities, but which does not use dedicated types for each kind of physical quantity, where the type definitions include the units used, is erroneous.

Any mistake like in the Mars orbiter must be detected at compile time.


It's also substantially easier to update a comment, making it more descriptive, than it is to update a variable name.


The funny thing is, when someone writes really 'clever' code, I need a why more than ever. Why isn't this simpler?


I find the exceptions usually boil down to:

* It's not your code - I was working with some UNIX TTY code recently and the APIs are horrendous 1970s throwbacks. But they're not changing. Working with crappy APIs is where comments about the "what" shine the most. You can only go so far with abstraction/encapsulation/facades.

* You don't have time - there's an urgent bugfix you need to get out yesterday. Do you A) rewrite the architecture to make it perfectly understandable and tell the users to wait B) drop a comment in explaining what's going on.


> And people will say "that's invalid because sometimes you really do need to do something clever and the 'what' needs to be documented" or whatever.

Yep, that'll happen, and when it does, you document why you documented the 'what'! :P

This kind of lazy black-and-white thinking is what 'consistency is the hobgoblin of small minds' is talking about. The exception proves the rule (...most of the time...)


Nicely said. One small adjustment I'd suggest -- because I care a lot about setting incentives -- is that we generally want not just _more_ "why" comments, but in particular concise "why" comments that empathize with and improve the life of future developers. They're a kind of message-in-a-bottle conversation.


What belongs in comments describing API methods, why belongs everywhere else.


The point on API methods is incredibly important. True, "Why" is the most important kind of comment, but I disagree with the author's critique of the documentation-generating comments and agree with you.

Yes, "what" comments are a source of additional developer effort and of possible inconsistencies between code and comments, but good API documentation is worth writing and maintaining.

No matter how well you name your method and its arguments, if it's part of the public API and you don't include a comprehensive documentation comment, I'll be forced to dig through your source.


If it's impossible to make "what" clear through the code itself.


With a public API it's important to distinguish "currently true from reading the code" and "promised to stay true through minor updates". What comments are useful for that


If a method is part of an API that might be used by developers external to your team, they don’t want to be looking through your code to figure out how to use your methods.


I mostly agree with you, but there are certain cases where you’re making weird and non-intuitive performance optimizations and have to explain “the what”.


But still you have to explain why your code is the way it is on top of that. You can always deduct the what from mentally processing the code, but you can't deduct the why, you only guess.


Definitely agree there are still cases where "what" is useful. Especially in some code that I come across that I just can't grok (e.g. badly named things), I start writing what it does just as a rubber duck method, and I don't have capacity to refactor the whole thing right then, at least I will leave behind a "what" comment because if I had trouble grokking what it does then someone else likely will too.


Wanna jump in here and say I'm working on this exact problem using GPT-3. The results when added to other dev tools have been really inspiring, and I'm learning how flexible comments can be when addressing the "why"[1] instead of just the "how".

[1]https://replit.com/@bramses/stenography-carbon-bot#index.js


Should my 'why' comment go further than a Jira number?


Absolutely. I worked a codebase that was littered with ticket numbers for a few years; many members of the team religiously added them but never read them. How do we know? Self hosted issue system and access logs. New starts would read a couple and that was it.

A ticket is a really opaque way of showing something. If you click the issue you're now going through several tangentially related comments and a few MR back and forths just to work out if its even useful to you. People will stop bothering to even open the link unless they are really stuck.

Whack a summary comment and then by all means include the link, but the comment is what most people will use.


I wonder if there are jira integrations that would bring ticket info into the ide. Although, I hate jira and would definitely prefer good git commits.


IntelliJ lets you expand links from patterns, so if in our codebase there's a BUGREPORT-12345 link, it's blue and clickable and goes to jira.


Yes. Unless your explanation is thousands of words (which it probably shouldn't be), just inline it. I only speak for me, but if I had to look up (potentially multiple) Jira tickets just to understand what was happening in a source file, I wouldn't be at that job very long.


Absolutely. All that information dies when your organization migrates off of Jira years down the line and the issue ids no longer exist.


That depends on whether or not you think the Jira ticket will outlast your code or not. If the company will definitely never replace Jira then no. If there is a chance that they will, and for your sake I really hope there is, then you'll need a better comment.


>Codes needs "why" comments, not "what" comments.

Indeed. While there are exceptions, "what" comments will usually only add noise thus making things more difficult.

This isn't necessary:

    // Total count
    int total_count = 0;


I find it's often useful to put a 'what commment' on a block of a few (2-10) lines of code. Then you can skim through the function without reading every individual line of code.


You might as well be able to extract a method with a meaningful name then.


Please no. Don't extract methods methods just to avoid using a comment. You end up making code more difficult to follow when you do that since you're now jumping somewhere else in the file and you're adding a lot of noise by having to pass the function's current state along as arguments to the new function.


>by having to pass the function's current state along as arguments to the new function.

But then the state being read and mutated by a block of code is explicit. The alternative is having to inspect the code to determine if and what state is being manipulated. The more code in a functional unit, the harder this gets.


If you're mutating variables then I'd agree that it might be best to encapsulate that in a function. But I'd argue that except for performance sensitive code, that's bad practice. The vast majority of code I write has 95% immutable variables. So even in a large function they'll typically be at most one or two mutable variables to keep track of (and very often zero).


That then makes the code non-linear, which IMO makes it a lot less readable in most circumstances.


It depends, if it needed a comment in the first place it likely was at a different (likely lower) level of abstraction than the rest of the code in that method.


Yes, but that doesn't mean it doesn't benefit from being inline. I love being able to skim over the paragraph-comments to get the big picture and then dip into the details without having to jump to another file / part of the file and lose my context.


To me it's actually faster and easier to read code instead. This is because i generally don't trust "what" comments - either I know the code already or I don't, and if I don't, then I don't trust the "what" comment fully, so I both have to parse "what" and code.

A "why" comment usually ages well, so I generally trust it and can use it to better parse the code and its intentions.

So I belong in the "what only for API methods" camp.


Do you also read through every function call (at least the first time you encounter a given function)?


This is Damian Conway's "coding in paragraphs" advice, and in my experience, it's the single best advice for more readable code. When you have a large function, split the code into blocks with a heading comment on each section. That way, you can skim through the function body quickly by just reading the headings, then dive deeper into whatever block you're interested in. Like section headings on an article.


I do something like this, but I write them as debug log statements so that you get the additional benefits from logging.


Yes, I've also done this in places. It works pretty well, although I wish I could get my syntax highlighter to de-emphasise these lines like it does with comments.


What would be your opinion of this comment, though?

  // Reset the counter for the next run
  total_count = 0;


Ignoring the pedantry elsewhere, then sure this comment explains what you are doing.

The contention is whether it is necessary or common enough to be assumed. In most places this would be self evident and should be avoided to reduce mental load, however I have seen and done exactly this many times - in distrubuted or embedded systems where the control is neither synchronous or co-located (ie, coming in from interrupts / messages). In such places there may even be call for more description, however presuming the context is appropriate this could be correct.

I would imagine a game with a react redux style state engine might result in a comment like this as well.


it feels like this suggests a design flaw. You should probably be creating a new local `total_count` variable for each run that goes out of scope at the end of the run, rather than reusing the same variable over and over again in different contexts


  // reuse counter for performance, this brings 2% speedup
  total_count = 0;
would be a quite useful why comment, if not creating a new variable each time is intentional


sure, but reusing an integer variable is never going to bring a 2% speedup. allocating a new variable of almost any type is not going to cause any performance issues, at least if it is allocated on the stack, and if the construction of the variable is particularly expensive, resetting it probably will be too.

I would need to see a realistic example to believe that something like this would ever be a useful comment.


I feel like you're getting bogged down on the literal code and missing the point of a hypothetical example.


In a compiled language, this is true for a local variable in general, it costs nothing because the compiler uses a register for it (or at worst spill it on stack but the stack frame size is reserved once for all stack allocated variables when the function is called).

The story is different, if the variable is captured by a closure/lambda, the current stack frame or part of it may be allocated on heap, leading to perf issues.


> the stack frame size is reserved once for all stack allocated variables when the function is called

Is there somewhere that's documented for LLVM? That's my expectation of what the final compiler output should be, but I read that the IR allocates every variable dynamically, and then they optimize away whatever they can. I haven't been able to figure out how or where it's guaranteed that all allocations will be coalesced.

I wouldn't normally worry about it, but I've talked to folks who don't believe me when I say it doesn't matter whether you declare an integer inside or outside of a loop. It would be nice to be able to explain exactly why it can never matter.


I don't know LLVM well enough, but you can play with godbolt

By example, with https://godbolt.org/z/9Kv7oo9oK you can see that values goes into registers (and that thank to 'lea' there is not many registers used).

And if you remove the option -O2, values are spilled on stack.


why are you resetting the counter?


For the next run. Why is in the comment, it's likely a design flaw though and no comment is going to help here. See comment about using proper scoping.


The thing that made my code 1000% more readable has been code reviews with a team that gives a damn.

When reading their code I'll add feedback to parts I don't understand (why do we need this cache invalidation, why do we use a worker pool here instead of throttling requests etc).

I find that questioning sits in the back of my mind when I write code - almost like a pair coder - to the point that I try to preempt questions like this by adding it as a comment.

Similarly for anything that's publicly accessible like public functions/properties/interfaces/classes, my goal for codedoc comments is to prevent the consumer (me or my team) from having to open the code to see what it does and how to consume it. If they can use it with just intellisense then it's a win.

Just like code readability and design, I'm seeing comments as another tool to communicate intent that can't always be communicated by code alone.


> If you wonder what the method does, or what the valid input range for a parameter is, you are better off just reading the code to see what it does.

I couldn't disagree more.

I was recently programming a library where some parameters could be 0 or greater, some parameters necessarily greater than 0, some parameters could be Infinity, others couldn't...

Similarly, if one parameter is set to zero than another parameter will have no effect...

JSDoc kept the whole thing sane. "Reading the code" would take several minutes to figure out the answer in each case, which would be wasted time in my book.

JSDoc is awesome. Not every function needs it, but plenty do.


When I started out programming I was taught that the code should "document itself" and that comments were an anti-pattern to writing good code. It took me a few years realize how idiotic that was and deprogram myself.

It's one of those things that sounds nice, but once you've moved beyond a certain level of complexity you realize how impractical it is. The fact is that "good code" is often in the eye of the beholder and not everyone has the same skill or vision, so they might as well write a comment about what something does and the intent behind it rather than leave others guessing.


Yeah, while it's true that a misleading comment can cause more harm than no comment at all, saying code is the documentation is cheating

Either we admit we'll never budget maintaining the comments metadata on top of the code, and embrace that risk for the cost reduction it provides, or we do document for real and maintain and review and fix regularly at a cost.

But saying we dont need to do it because it s already done is a quick stunt that everyone saying it knows is dishonest.


I've seen people refactoring the code just to avoid writing a single line comment, like it's a dirty thing to do. After the refactor the new code is probably more readable, but not as good as it would have been with the comment.


> was taught that the code should "document itself" > comments were an anti-pattern to writing good code

I've been programming in one form or another since I was 8 years old (around 38 years) and this was obviously incorrect to me back then, even though I wasn't sharing my work with anyone else, and hadn't heard this concept.

Years later I was astounded to move into a "modern" dev environment where people (developers, devops) parroted this line regularly. As you say it's nice in principle, but in reality relying on it proves to be impractical.


Exactly - please do javadoc style comments. “It’s not an API” is not the way to look at it. You have to look at it as - I will not be the last person to use this code block. You don’t want to force someone else on your team or your replacement to dig into your method to figure out what the parameters are and the correct usage when they see it used somewhere. Having a javadoc pop up an illuminating description is very valuable. As the code base gets bigger you can even just look at the exported javadoc to figure out if someone (maybe you) already implemented the method you are thinking of. The part of the article rejecting javadoc sounded like it was for only ephemeral projects and not a mature code base that’s been handed down.


The worst, though, is when a comment tells you the valid input range, but it's wrong, because someone later changed the code and didn't update the comment. While this doesn't happen frequently, I've gotten bit by it enough that I will generally at least take a cursory look over the function body to verify that the comment is still correct.

I wouldn't say this makes the comment useless, but it does reduce the usefulness. And this might end up biting someone who has decided to trust the comments.


Full agreement.

Unfortunatly it is a story, that is set to repeat 3 times.

There is a similar tragedy of outdated documentation.

And then the final part of the trilogy is named "outdated and even misleading naming" (vars/functions).

In all cases, one should have same amount of trust as with weather forcast or politician's speech. Trusting 100% would be naive, but complete dismisall would be foolish as well.


To add onto this, the documentation of a method is often a contract. If the documentation is good, the actual implementation of the method shouldn't matter to someone only wanting to use that method. Even moreso, the implementation could change: maybe there is a more concise or efficient way of implementing the contract.


This is great if you're using a loosely typed language (like JS), but I think the need for this is why things like Typescript are gaining in popularity.

I used to love the eslint-enforced jsdoc in a repo I maintain, but since we embarked on a TS migration, it has become painfully redundant in 90%+ of cases (there are cases where the jsdoc contains extra commentary/context that TS doesn't cover, but I think those cases are covered by the author's other comment types).

So given the above, I think it's notable that you are referring to JSDoc (and by extension JS) whereas the author is referring to Javadoc (and by extension Java). The language choice is particularly important here.


Libraries are an exception. Here, from the article, talking about Javadoc.

> These comments may be useful for API:s exposed externally, but in an application where you have access to all the source code, they are mostly useless.


All code is library code


On the contrary, I find standard JSDoc and its variants to be an excellent tool for internal documentation. With hovering support in modern editors, it allows context explanation in a very streamlined and human way.

The author mentions for preconditions to just “read the code”. I consider this bad advice. If using an external library, would you rather hover over the method and see its conditions, or would you rather crawl into the third party source code?

I recommend that you treat the internal structures of your code as reusable third party libraries, and not assume that anyone will be familiar with it or how it’s used.

Often my JSDoc comments take up more vertical space than the code itself, sometimes even with ASCII tables or example usage code. I believe this is one of the best approaches to documentation, especially paired with a automated documentation site generator tool.

Code is read much more than it is written. You need to think like a writer and consider your audience.


If the name of the function and the parameters are clear, documenting the code seems useless.

Take this real example:

    /**
     * change the temperature set point in use by the thermostat
     *
     * @param ctx the thermostat context
     * @param sp the new set point in 0.1 celsius degrees
     * @return 0 on success, < 0 in case of an error
     */
    int change_sp(void *ctx, int sp);
But we can change around the name of the parameters like this and use proper strict types:

    /**
     * change the temperature set point in use by the thermostat
     *
     * @param thermostat_ctx the thermostat context
     * @param set_point the new set point
     * @return SUCCESS on success, otherwise an error code
     */
    error_t update_temperature_set_point(thermostat_ctx_t *thermostat_ctx, celsius_degree_t set_point);
And thus the doc comment now it's useless and can be removed, leaving only:

    thermostat_error_t update_temperature_set_point(thermostat_ctx_t \*thermostat_ctx, celsius_degree_t set_point);
And in a codebase, more than 95% of the comments would be like that. There are the exception where you need to explain something in more details. In that case you first should ask yourself if there is really not a better way, and if not in that case the doc comment is fine. In all the other cases, it's probably not.

Doc comments on the other hand really makes the code less readable, the increase the number of lines for most of the times not saying anything useful at all.


Why are method names priveleged over comments? They're both text read for human understanding. Why must the full documentation/definition for a function fit into the length of a method? These are silly restrictions, and lead to worse code.


Because what the code does should be obvious without looking at the documentation. Plus editors will autocomplete function names by looking at the name, not at the documentation. Thus using meaningful names can speed up the development.


Because writing a(a,b) is not ok even if comments are great, so why not make the method name a clear enough verb that comments are often unnecessary.

The problem is that not everyone code under the same circumstance, even inside the same codebase: you have the new joiner that has to reverse engineer most of what he uses, the senior who did or touched enough that he doesnt even see the color code for comments, the rushing helper who need to fix a bug now or else and cant maintain comments or he'll miss the deadline, etc.

Comments are sacrified first, tests seconds, code clarity third, correctness in edge cases next, etc. Embracing the reality that we're going to have to deal with crap once in a while would solve a lot of frustration.


Accepting that comments are sacrificial does not mean sacrificing them eagerly. In general, code with comments is better than code without.


This is maybe OK until you get a library user who doesn’t know what “ctx” means and now you have another Discord ping or GitHub issue. Just write the documentation.


what is "set point"? Is it a point that is a part of some kind of set? What's "point" - is it part of some kind of coordinates?

You are documenting _what_. To document _why_, you must explain why somebody would want to change the "set point" and what is the effect, and not in terms that "setA sets a", but the semantics of it. What does setting point accomplish? What are the circumstances when you want to do it? _WHY_ would somebody want to call this method? Make the room colder? Make the room hotter? That kind of thing.


You have to assume a certain amount of domain knowledge, or you end up explaining the entire universe.

In this case, "set point" is a well-understood term, and its purpose is similarly well-understood. [1] Although the team may wish to document it, the place to do so is in the team glossary (or other overview documentation), not in every function that uses it.

[1] http://faculty.washington.edu/brengelm/neut_zone/pg3.html


Thanks for info, I did not know it's a common industry term!

Anyway, the point I am driving is, it's more interesting to discuss _why_ would anyone change the "set point" - common scenarios and pitfalls, than just explaining the "update_set_point changes the set point".

It's nice to go into details what are the consequences and common use-cases.


> But we can change around the name of the parameters like this and use proper strict types

Sometimes. Other times proper strict types aren't possible because the language doesn't support them (many scripting languages, C, etc.)

Assuming this is C, even a type like "celsius_degree_t" tells me nothing about the valid range. Am I supposed to just try it out and see what error code I get or are we back to looking at the implementation? In the case of C this will most likely involve locating and opening a completely different file whose name doesn't even have to be related to the header file.

The comment also doesn't need to be about all parameters and can contain additional information that's non-trivial to determine: is the function thread-safe, are there performance implications, is there notable resource usage, and so on.

Python in particular is notorious for having optional (keyword-) arguments and polymorphic arguments. Proper naming schemes are impossible in this case (lest you accept monstrosities like "node_as_id_or_name_or_object" as proper argument names) and type annotations have only very recently (as of 3.10) become somewhat sane. Type annotations don't help with kwargs, though.

TL;DR it greatly depends on the programming language and its capabilities whether naming and types alone can replace comments.


That's more of an argument for them being overused, not for them being useless.


It's an argument for a certain code style, characterised by descriptive names and specific types. This calls for a language capable of e.g. doing maths with user-defined types, which not all languages can do.

I think one of the major motivators for the original style of code are legacy pressures and a concern about code width.

If every other function that manipulates temperature set points takes "int sp", then you're going to get a lot of pressure for consistency. A lot of programmers regard consistency as a goal in and of itself, and it's very easy to demand it during a code review. However, the demand for consistency prevents us from finding a new consistent target without excessive amounts of work. It may be better to reach a new consistency within a narrower scope, as long as a consensus has been reached to extended that consistency outwards. In this system, consistency should be viewed as a compromisable target: something that makes you ask a careful question. And when asking a question, take into consideration the propensity of the code author to view a question as a demand. If you're a senior and the code author is a junior, presume that means: ask a genuine question vocally; write down minutes of your discussion.

The code width concern is a bit silly, but for some reason we assume that things get weird when lines exceed 80 characters. That's easy to do.


You’re missing under what conditions an error is thrown. I used your method now I got an obscure error code. I’ll change it - whoops a different error code. Documenting it would let someone know what values of set_point are valid and what context states work/don’t.


JSDoc !== Javadoc

The reason I say that is because the language features (or lack thereof) are a big contributor to the need for JSDoc/Javadoc.

i.e. JSDoc adds much more to Javascript than Javadoc adds to Java.

For example, there is much less need for JSDoc in a Typescript project.


nothing wrong with the tool, the issue is with the comments that exist and those that don't.

getFoo() does not need a comment.

if it does, (it shouldn't) and its JavaScript, JSDoc is a fine format.

if getFoo() does need a comment, consider changing the code so it doesn't.

Code is read much more often than its written: so be concise.

If the docs can be automated by a simple tool, by definition, they were not necessary.


I generally enjoy a brief description of the overlying concept, at the top of each function. I don't care to know how a function is implemented as much as rough details to help me navigate the new/forgotten code space/context. Usually, a quick example of usage, within some relevant context, is enough to push me in the right direction.

If I have to read every line of implementation to know wtf is going on, then I'm probably going to have a bad time.


Depending on the context, I might mention if getFoo is expansive, is cached, talks to the network, or can throw.


I care much more about revision history than I do about comments. When I'm trying to figure out code I do it in "git blame" mode - what I'm hoping for is a single, atomic commit that links back to an issue thread. Ideally that issue thread will have all of context I need to fully understand the change.

This works great in codebases that are designed to be read in that way, which is why I'm so keen on every commit combining tests, implementation, updated documentation AND a link to the associated issue thread.

I'll sometimes open an issue seconds before I make a commit, just so I can have an issue number I can associate the commit with. This is great for adding commentary later on - I might post a comment on an issue thread a year after the commit that help clarify some useful detail that, with hindsight, I should have recorded.


Definitely.

Commit messages are updated with the code automatically. Comments seem to become out of date almost immediately.


Isn’t this an argument for better code review, rather than against comments?


Sometimes, as you become a better programmer, a comment that you thought were a "why" comment is now clearly a "what" comment. One programmer's "magic super-efficient pointer gymnastics" in C is another programmer's standard idiom. When working on a large project as a team, most of the project may be run-of-the-mill code for most of the team, and so it doesn't warrant "what" comments. However, there will be times when you have to introduce coding idioms that are foreign to everyone on the team, in which case a "what" comment may be warranted.

For example, a standard 5 year old React codebase probably used to contain a lot of class-based components and now is probably switching to function-based components with hooks. I know the first time I did a code review on my colleague's code that introduced some weird hook concept - I asked for some more comments to explain what magic was going on. I would probably not ask for such a comment today now that everyone is more or less familiar with hooks and function-based components.


> I didn’t need comments if I wrote self-documenting code.

More than any other approach to coding (x-based-development etc), this has come up most frequently for me personally, and it astounds me how many people have this mentality.

Comments are a way to break out of whatever terse syntax your given language requires and speak directly to the developer. A single comment can house so much more context and insight the best-formatted code could ever hope for. When the only downside is some holier-than-thou idea of "I shouldn't be doing this" (despite the fact you clearly need to), I'm surprised so many people fall for this terrible mentality.


There are 4 main types of comments I use:

- javadocs: at the top of the function. Explains what you need to expect from it, very useful when autocompleting (yes, you can go read the code...but that's slow)

- block description: before a bunch of lines. Explains what they do without need to read and understand them all, so you can read them faster.

- line description: at the right of a line of code. Explains the use of a specific variable, the reason you used a function call, etc.

- flow descriptor: the line after an if, an else and other path divisions like while or for. Explains why the code took that path. Useful when you need to understand the context of a specific line.


I'd like to argue against the author's disdain for javadoc-like comments.

> If you wonder what the method does, or what the valid input range for a parameter is, you are better off just reading the code to see what it does.

I feel that this is a very inefficient approach to coding. If you tell me what the function does, what its valid inputs are, and what it returns then I don't need to look at the code at all.

More so when I'm collaborating with people outside my area of expertise: a colleague of mine wrote a function to "convert molecule SMILES into their neutralized form". What does it do? Beats me, I'm not a chemist. But thanks to the comments I don't need to know, and I'm grateful for that.


Javadoc comments problem begins as soon what is in javadoc stops being true.

So you are usually better of reading the code anyway because you cannot trust that some dev updating code updated javadoc as well.

When something goes wrong I usually have to do is to dig into GIT history and see when and what changes were connected.


Having said that you can spot bad code by its JavaDocs.

The most reliable Javadoc is @author, git tells you the author, @author tells you who the code was copy/pasted from.


Is this different from git blame or does @author take the info from git blame for you?


Same with naming in code.

Names do become misleading. Of course making callstack deep enough, will hide that.

Code reviews have same power to rectify both: naming and comment issues.


> Code reviews have same power to rectify both: naming and comment issues.

Great point.. except for when you're dealing with a lead and/or reviewer that refuses to approve comments because "we write self-documenting code" yikes


To me the above quote says that author never worked with anything more complicated or more big then simple crud web app.


To me it says that author is perfectly aware that people are not updating Javadoc comments or normal comments as well.


If your method documentation is out of date, the problem is not about the doc.

The problem is that someone on your team drastically changes existing methods behavior instead of writing new ones, and by doing that, is changing the behavior every historical caller expected.

I really think that if your changes are so important that they need the doc to be updated, it’s probably that you should write a brand new method. Changes in an already called method should only concern implementation details.


It is not about my team.

It is about people. In the world where team members last ~2 years and move on, expecting that documentation is left not updated is in my opinion perfectly valid assumption.


I was not directing my comment to your coworkers. I was just arguing that a documentation can only be out of sync if the method's intention is changed. And if an existing method intention is changed, your problem is not the out of sync documentation, but the fact you probably broke something in your existing code, not in the years to come, but today.


Which is still better then no explanation nor minimal hint at all unless you are doing something simple.


I come to a conclusion that the main reason why some programmers argue against comments is just laziness. Writing comments requires an effort. Being smart they can find multiple reasons why their don't have to do this.

Of course it is possible to intentionally create a harmful comment, but if you trying to write a useful comment it is likely will be useful for most readers. In my career there was a lot of situations when a small comment would have saved me time - I've spend many minutes and even hours to discover something a code author knew but was too lazy to put into comments. I don't remember a single case when I suffered from an outdated/incorrect comment (though in this discussion such situations are mentioned).


I suspect this "no comments" movement (which roughly argues that comments are hard to maintain, and you should avoid comments in the code, as writing clear code, and naming things properly, is enough, and if you have to comment, you should do it in organized doc strings) ultimately came from the idea that we will have "code refactoring tools" that will modify our code to be better and cleaner and it will increase our productivity. Such refactoring tools might understand the code itself, but they have a hard time with human language of comments.

I always hated that sentiment of "no comments", although I share the wish of computers understanding our code better. I think the refactoring tools didn't really live up to the promise, because they require the discipline of writing everything in the code in computer-readable format, otherwise they will leave fragments of wrong documentation in their wake. One of the benefits of human language is that you can easily create a DSL (concepts and terminology), and the refactoring tools usually cannot handle custom DSLs (much less vague ones) very well (seems like a strong AI problem).


I have a personal rule: If I need a comment, it goes at the beginning of the function.

This neatly groups the comment with the code it applies to.

Occasionally I have to make a function "just" for this grouping purpose, but that's fine.


This is also my practice. Any code that is complicated enough to require a special comment is also complicated enough to be its own function.


Exactly my thinking. Very well said.


This is a nice rule of thumb. Works great for 90% of use cases. For the other 10%, it's "acceptable". I like it. It also discourages "what" comments, and encourages longer "why" comments. The biggest benefit is: standardization, and no need to think about comments again.


I have never cursed an author for having too many comments. There are many cursed developers out there after my long career.


I have.

And stripping comments before working on it is a thing I have done many times, on code I wasn't familiar with.

The biggest problem is lies. If you don't update your comments, don't write them. If you know someone less careful than you is going to take over and not update your comments, don't write them either.

And then, there are the redundant comments, the ones I see most often. For example

- Don't describe the function both in the header and source code, it is a useless copy-paste that will never be updated correctly. (mostly for C/C++)

- I know the syntax for declaring a constructor, thank you, you don't need to tell me that is is a constructor in the comments. And I can also guess that getX() gives me the value of X, no need to fill my screen with dozens of useless lines of comment.

- I don't need a comment to know who did what. We are under source control and we have a "blame" command.

- Don't use comments to disable code. Just delete it, it is not lost, we have history, and we are unlikely to need it anyways.

But the one that makes me rage the most is something like "int time; // the time". Not only it is useless, but you are not giving the info I want: the fucking unit! I've seen it way too often, sometimes with far from obvious units, like tens of microseconds. So if you want to put a comment, at least tell us the unit. Or better yet, don't comment anything and make your variable something like time_in_ms, or define a type.


You never lived through auto-javadoc?


Ah, the awesome flavour of Markov chain nonsense that is auto-generated docs. I think the existence of this phenomenon shows the danger of strictly adhering to policy that was written by someone who never suffers its effects.


I'm quite irritated by this train of thought "JavaDoc is useless because you can write a useless JavaDoc". Can't we get at least past elementary logical fallacies.


In scientific software, from my experience, we need a lot of "javadoc" like comments because you push data into functions which are basically equations. This means that you need to document the units (if not in SI), the assumptions, etc. Basically, the comment block is explanation of the equation.

I was bitten many times thinking "yes, this is the equation (21) of the well-known paper, no needs to comment" to then fall flat on the nose because this was well-known to me, not the other engineers coming from another field, an assumption was there for let say a concentration of a chemical in the formula but then it was used in another context where the assumption does not make sense, etc.

For all the "bit-pushing" part of the software, opening files, reading data and so on, it is way easier to have self documenting code.


I find Rust crate code to be quite difficult to read sometimes because it contains a lot of comments and executable examples destined to be incorporated into auto-published (and auto-executed) documentation. That's a fine thing of course, but it would be nice if there were facilities to see "just the code and code comments".

A somewhat random example is https://github.com/ogham/rust-ansi-term/blob/master/src/styl...


I wish for a text editor that shows the comments to the side of the code, like in a split pane.


Not always, but I noticed I often find I write my comments first on what I want to achieve like a sort of psuedocode in a very high level.

Then under each one-line comment I'd write the code that does what's written.


Important topic.

Documentation, in general, could use all the help it can get.

I wrote up a long piece on this[0]. No one will read it, because it's long. I've found that no one reads anything that is more than about a "7 minute read," these days. Part of my documentation problem, is that I can get too verbose. It's not a good thing.

[0] https://littlegreenviper.com/miscellany/leaving-a-legacy/


One of the key things that I believe is that the world has gone to far in the metric direction. Metrics lead to things like fake reviews, teaching to the test, and SEO. The only way to avoid this is to put your trust into people that you believe have good signal to noise ratios.

While posting on HN I believe that your posts have good signal to noise ratios, so I will now henceforth go through your post history looking for quality content. This post was one such event. Because I viewed your content like this, length went from a cost to a value. I read the entire article(okay, I skimmed the code sections).

Love the blog. It made my skills as a developer better. Not much to add, a benefit of the verbosity.


Hey, thanks!


Sometimes code relies on some condition being true, where that condition can be reasoned about by the developer rather than at run time by the program they are writing. I don’t think such comments fall cleanly into either the “what” or “why” categories people have mentioned here – perhaps they are “how”.

In mathematical terminology, the condition may depend on some lemma or theorem the programmer proved to themselves when writing the code. (I say “lemma” and “theorem”, but this applies to any kind of complex business logic, or the state of a realtime system, etc.) For a lemma (fancy name for a small theorem), the reasoning can go inline in the code, as a comment. If it’s a theorem, a more substantial thing you proved to yourself when writing the code, it might be better put in a separate document which a comment in the code should point to.

The reasoning you used to show the code works is better off written down for those who follow than forcing them to think through the same logic again. And the act of expressing the logic in a comment will tend to flush out errors in that logic. Those are both good reasons to spend the time writing such comments, unless you don’t care about technical debt.

As a special case, runtime assertions often need a brief comment to explain why they must be true.


Sometimes you come back to a block of code you wrote a long time ago and go "what?" enough times that you go ridiculously overboard documenting it just to create the illusion of understanding it quickly the next time.

I still don't understand https://gist.github.com/chowells79/996f2749b088d287937e3eff1... on the first read, even with the ridiculous overdocumenting. On the plus side, it's clear enough what it does, even though the details of "how" are hard to follow.

Still, if there ever was a case for documenting the "how" over the "why", that code is it. It's pretty easy to understand why that code exists. It's actually quite hard to follow the details of how it does it. Those comments are excessive, but they do cut the time it takes to rediscover the "how" whenever I get curious.


The way I think about it is that comments needs to provide information that is both new and useful, where "new" and "useful" depend on the audience

http://jeremymikkola.com/posts/2021_03_21_useful_comments.ht...


Code is for computers to make them do exactly what you want them to do, comments are for your co-workers (and you) to make them understand what you actually meant to achieve.


Code involves names of methods and variables which can greatly aid in understanding as well. I've always maintained that comments should only be in code to explain something that is not obvious.

If you're calling the SaveUser function and passing in a new User object that you had just created, a comment of "Save the new User object" adds nothing but noise.


A comment like "This method opens a separate database connection so as not to mess with the ongoing transaction" or some such would be rather helpful, though.


Within the code I write, I can't think of a scenario where that wouldn't be obvious. But if it is indeed not obvious, then I agree that would be a helpful comment.


What's obvious now might not be obvious later or to another person.


I guess that was what I was trying to say. Make your code as obvious as possible, and use comments to explain what's not obvious.

Although people have vastly different ideas of what is or isn't obvious.


- Do you SaveUser to the database directly or do I have to somehow call something to validate the transaction ? - Once it’s saved, can I continue to use my User model or should I fetch the more complete one from the database ? - Does this even SaveUser to the database or on a temporary structure that will be fetched by our UserCreationBot ? - Does SaveUser checks if the username already exists or should I check myself before calling it ? - Does SaveUser checks that current user is allowed to create new users or should I check it before ? - What happens if SaveUser is called with a User with an empty password ? Does it means that the input is wrong or am I legitimately creating a user that can’t login?


Check the code of the SaveUser method.


Most code (and the effects of removing/refactoring it) are not that obvious at first glance. But I agree, if your code is as simple and self documenting as that a comment like that doesn't add anything. But a lot of the intention cannot be expressed in code alone. This is where comments help enormously. It allows me to review the code and compare it to the writers (often me) intent and spot bugs or refactor if needed. Without it a lot of knowledge has to be rediscovered again.


All code is literature intended exclusively for humans. Computers read machine instructions; they're incapable of reading code. Know your audience.


By the powers of compilers computers got the ability to read code. To leverage their powers we need to write code which the computer (~ program, aka compiler) understands. I write code for the compiler to read and translate. And yea, also for humans. But not exclusively. The compiler is not a human. It is only made by humans, like the computer.


Humans wouldn't care so much about semicolons, but I do want the compiler to understand my code, too.


Have you seen decompiled code? That's all that compiler cares about, it is not pretty.


nonsense. code is intended for a computer by definition.


No. Code is intended for your teammates.

Compiled machine code is for your computer.

If you were addressing a machine, you would be writing 0s and 1s, because o boy do the machine know how to execute those little ons & offs.


People often insist on this point, and I still don't get it. Honestly it comes across as intentionally exaggerating a claim beyond reason, in order to make it sufficiently counterintuitive to sound clever.

The point of the program is to get the computer to perform some task; the way we get the program into the computer is to write code.

You can say we're writing code for the compiler if you want to be pedantic; or you can say we're writing code for humans too, which is a perfectly valid point. But what do you actually mean by insisting that no, the code isn't for the computer at all, it's solely for other humans? It's clearly the language we use to communicate with the computer to tell it what to do; the fact that there's a translation step (performed by the computer) between what we write and what the computer executes doesn't change that in any relevant way.


> But what do you actually mean by insisting that no, the code isn't for the computer at all, it's solely for other humans?

By insisting on this, I mean that, at any given time, if I have the choice to write code that is easily readable by an human XOR a code that is easy to execute (fast), I will always choose the first.

And it’s not a dogmatic ideology : sure there are tradeoffs where writing efficient code is needed, sure it depends on the industry you work.

But in general, when needed, it’s much easier to make a readable code faster than to make a fast code easier to read.

I’ve seen so much « optimized for machine » code in my career. Probably written by really smart person who chased the millisecond perfection. But 90% of this code is « one shot execution » where millisecond doesn’t change anything and is probably wasted anyway by the surrounding framework/library/context…


That seems reasonable enough when you unpack it; I just don't see the point of stating it in falsely absolute terms. Maybe (almost certainly) I'm too much of a literalist, but instead of saying 'always' and then clarifying in the next line that of course you don't mean always -- or saying that code is for humans not computers, when you mean that code is for humans and computers -- why not say what you mean the first time around. Maybe it'll be a bit less pithy, but it will also drag you into fewer discussions with people like me :)


But you end up with compiled machine code by using a computer to compile your high level code into machine code. You tell that computer exactly how you want it to compile your code into machine code. So in the end the code still is for the computer first.

I can write a basic function in 10 different ways that basically do the same, but have bugs or small differences in side effects that might not be obvious to a human reader at first glance. Languages just lack the expressiveness to explain those nuances, hence comments.


I disagree. Code is not just for controlling the computer. Just as importantly, it's also meant to be read by humans.

So, code should be written in a way that is easy for a human to read and understand.

Code should easily and naturally show what it's intended to achieve 99% of the time.

Comments should be used sparsely, and only to express things that must be expressed and cannot be expressed in code.


I like comments to be an "alternative" way to read the code , e.g. understanding the flow / logic solely by reading through the comments (and only having to look at the actual implementation / code when more details are needed).


Comments should never be "what". They should always be "why".


Most documentation in dynamic languages I've encountered (like JS) have been wordy attempts at documenting function arguments. This almost always falls short of the goal. Describing object shapes and types is difficult in documentation, especially in languages that mutate objects willy-nilly. TypeScript and mypy are really essential documentation tools for that reason; they liberate developers from the Sisyphean task of describing object shapes and mutations and lets them write documentation that is actually useful.


I often weigh the value of comments -- I used to write more, now I write fewer -- by weighing odds of utility against decay into misinformation. Comments conveying something of high utility that is fundamental to the program and unlikely to change make the cut.

I save most of my remarks for commit messages, which are understood to be contemporaneous. This method requires the average commit message quality be high, otherwise, people are unlikely to think to run blame on the file, even though most text editors can do so effortlessly.


+1 for log statements as comments; at least these don't tend to become obsolete. When looking at unfamiliar code i tend to trust log statements more than comments, for this reason.


The author is not very positive about JavaDoc. I agree that using it everywhere is probably overkill, but when you are writing a library JavaDoc can be useful for documenting it.


I use comments to break up a large block of code into smaller chunks to explain what is happening / where we are in the process.

I used to be a firm believer in self documenting code, but that approach often led to a large number of functions that only get called once. So lately, I have been just putting a comment line where I otherwise would have refactored the code into a function, and I feel that it has made my code a lot easier to read, and understand.


Same here. The majority of my code is usually readable but still add comments on bigger chunks of code to split that code into logical sections, it's particularly useful when using a text editor with code highlight


How has your testing been impacted? I usually write several functions to isolate code for testing.


> Every time I come back to those parts of the program, I am happy I made the effort to add a comment – they have been very helpful!

Exactly. Rarely hear someone say there are too many comments in this code! And feel free to not stop at the docstrings. Nested loops, obfuscated 1 liners, business logic that required a cross functional meeting to understand, are all valid reasons to be generous with comments.


Half-OT:

What happened to literate programming?

Back in the CoffeeScript days, it's creator adopted a literate programming format, which was basically Markdown with code blocks being CoffeeScript.

He talked about that as the future of programming. Whelp, CoffeeScript got killed off by ES2015 and the file format never caught on.

I know the concept of literate programming does come from Knuth, but I first heard about it with CoffeeScript.

Why did this never catch on?


I think many programmers are not big on writing, you can see on this thread there are a large number that object to almost any comments at all, and support the assertion with the belief that comments go stale and won’t be updated because people can’t be bothered to write. I think the appeal of no comments is the quest for perfection in the source code - that you can achieve something that needs no explanation. In contrast literate programming nakedly admits the discovery of the solution and how code was developed and its imperfection.

That said it has caught on some with data science and actually is an option with swift playgrounds.


I like notebook-style programming (e.g. Jupyter, Mathematica, etc) for this. They don't quite fit the bill, and for example, don't provide a mechanism to render into a clean library with unit tests extracted from the notebook. But I still hold out hope for a good cross-language system.

Having read some of Knuth's literate code... good god that man is brilliant, but aesthetic language design isn't his wheelhouse


The only thing I would add is that header-style comments are immensely helpful for "chunking" the code into distinct sections. I first saw this recommended in Code Complete, and it stuck with me, since I've seen it in a number of other domains. It's a basic part of cognitive psychology that makes information processing and retention much easier.


Can you explain further what you mean by header-style comments?

I'm having trouble drawing up a distinct example.


Probably

    // --- Init ---
    
    // --- Mainloop --
    
    // --- Cleanup ---


I recall having to write a set of long comments to explain a rather complex routine. When it got to code review we discussed the routine and I made the remark that, if I had to explain the code I’d written, it was probably too complicated to start with. Re-wrote the code to be simpler for the sake of maintenance.


Whenever I'm not clear on something I wrote, I have to spend the time deciphering it, and then add a comment to save myself the time next time.

After a while of doing this, I get a sense for what kind of stuff I'll find puzzling later and can comment preemptively.


I comment stack overflow links when using some random code I copied.


Yeah because it is so much faster to read the whole method and all methods it calls then ... hower over it to quick read javadoc in popup.


/* * DO NOT EDIT THIS CODE YOU MORON. * THESE AREN'T THE LINES YOU'RE LOOKING FOR. * MOVE ALONG. *


My golden rule is inline with javadoc being largly useless.

Don't ever add SBO comments.

SBO = Stating the Bleeding Obvious.


Sometimes what is obvious to the code author won't be obvious to the person tasked with maintaining it.

Sometimes, the "obvious" code has a bug, but its intended purpose is no longer obvious. Commends for "obvious" things add redundancy, like error-correcting codes.


antirez (creator of redis) has some good thoughts on this topic, that people here might find valuable: http://antirez.com/news/124


Or to put it more succinctly: Code is the what, comments are the why/why not.


Tests should really fill this gap, not comments.


I agree with most of the article. Explain the why and tricky parts. Attempt self-documenting code, don't loose your head over it.

On other aspect, I can't believe this lived for 6 hours without the mandatory quote: https://xkcd.com/1421/

Enjoy.


// I'm honestly convinced the compiler ignores all my comments.


I try to never write a comment about anything that I've already written in code. I only add information that is necessary to know to run the code but is not in the code.

I do it like this as I think that conceptually duplicating code logic through e.g. comments can be dangerously imprecise. E.g. when someone changes the code (and not the doublicating comment), there are no checks in place for this mismatch of code and comment to be caught by e.g. a test.


If you have really good test coverage that might be okay, but otherwise, how do you know if the code is doing what it's intended to do?

If I see a line that looks like it might be a bug, or an unnecessary duplication, how do I know if it's a mistake or not?




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: