Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

Many people think their code is clear. The problem is it is clear often only for the author and sometimes for a limited time even for the author. If anyone else start to working with the code questions usually arise. And you can prepare comments for at least some of such questions.

In my practice I often see code where useful comments are missing and hours of research required to learn something author for sure knew. Code which has too much comments to me is an imaginary problem - I've seen it at most a couple times in my career and one of them was the code written by a junior developer in a style one can expect in a tutorial or a book. But usually people quickly learn to not add unnecessary comments (and eventually start adding too little of them).



>Many people think their code is clear.

This is true, but if you just get these same people to write more comments, they will also think their comments are clear when they're, in fact, not. I think anyone who is capable of writing clear comments is also equally capable of writing clear code.

If I was to suggest investing time in learning some skill, I would suggest learning how to make your code actually clear by getting the right people (with relevant domain expertise, but without experience with the code) to critique it for clarity rather than learning how to make your comments actually clear.

Why questions are best answered in architecture documentation, the code itself should be self explanatory (given the architecture documentation) for the most part with specific why comments carefully placed in places where it doesn't make sense to use the architecture documentation.

I've read code from various codebases from various companies, large and small. I very rarely see a comment which is genuinely both well placed and useful. From the bits of the linux kernel that I have worked on, I have generally seen pretty good why comments, although I think a lot of them could be shifted into architecture documentation.

All in all, when reading code, my default stance is to ignore comments unless I get lost reading the code, then I attempt to read the comments. It has been incredibly rare that I've found unclear code to have clear comments.


> I very rarely see a comment which is genuinely both well placed and useful

Your experience is different than mine: I write software which interacts with cloud (Amazon AWS, Google Compute Platform, VMware vSphere), and a well-placed comment describing the quirks of whatever platform I'm working with helps immeasurably, e.g.

> VMware NSX will throttle us with an HTTP Status 429 "Too Many Requests" if > 100 API calls/second. In that case, we back off and retry rather than fail.


Agreed. I’ve found over the years it is helpful to prefix comments like that with something like “HACK: “ as it makes it clear you are working around a limitation and not adding a feature - plus it stands out when browsing the code.


I’m a fan of comments, but in this case I would reach for an enum with descriptively-named members, e.g. HTTPStatus.TOO_MANY_REQUESTS


Making it strictly worse. TOO_MANY_REQUESTS? How many is too much? In what scenarios?

The code comment in the GP is pithy, explanatory, and reads in plain English. Yours is ripe for misunderstanding.


My bad for not being clear, I was really talking about the comment saying 429 means “too many requests”. By all means comment to say that service X has a rate limit of N req/min but a comment saying 429 means too many requests is exactly one of those things that’s better expressed in an enum.

301; 302; 401; 429; 504; I shouldn’t need comments to tell me what they are, nor should it be expected that anyone touching the code knows them off the top of their head.


Unless the API itself is poorly designed, 429 _means_ "you have reached a rate limit". That might not be so self explanatory for someone who isn't familiar with HTTP error codes, but that person maybe shouldn't be attempting to read a codebase which deals with making HTTP requests in the first place (e.g. my keyboard firmware doesn't have a comment explaining how a keyboard matrix works). It may be worth noting what the rate limit is somewhere, but likewise, I'm not sure how useful that is. If the rate limits change then your comment is now incorrect, but the code to handle backing off due to a rate limit should probably still stay, and should work independently of what the actual rate limit is. If someone questions why that code was included (first off, not sure who would question what seems like a perfectly sensible design decision) then that person can refer to the VCS blame (e.g. git blame) logs to find what _should_ be a detailed commit message explaining all of the 'in the moment' reasoning for why and how the code was written.

I don't mean to imply that your code is poorly written as I clearly can't see it and maybe it's a lot more complex than I am imagining it, but I don't really understand how your code was written such that it became unclear enough what code handling a 429 was doing such that you felt you needed a comment to explain it, but I can envision a codebase which handled rate limiting where comments weren't needed to explain the reasoning behind it.

I think the best way to think about it is this: What information is this comment conveying?

- "HTTP Status 429" means "Too Many Requests" - You can put this information in a comment every time you refer to 429, or you can simply use an enum.

- "429 Too Many Requests" means "a rate limit has been hit" - You can put this information in a comment every time you refer to the enum, or maybe it's best placed on a website like MDN[0] where it can be surrounded with far more detail and where the information has a much smaller chance of becoming outdated.

- The rate limit is 100 API calls per second - You can put this information in a comment every time you talk to this particular API, or it's best placed in a document which describes the API itself such that if you ever need to update it, you can update it once. Maybe you can demand that the vendor of the API provides and maintains this document as part of whatever contract you have with them. If necessary, the module of your code which deals with interacting with this API may benefit from a reference to this document.

- That the code should back off and re-try instead of failing - Okay, now we're getting to the core of something important. And I think the reality is more complex than the comment even lets on. Does the code re-try indefinitely? Does it have an option to disable retries in some contexts? I'd assume most likely a no for the first question and possibly a yes for the second. In that case, the names of variables within the code the name of the function, and the names of the parameters of the function should probably be enough to convey this meaning entirely.

That being said, I think that as far as comments go, there is still a benefit of having short descriptive comments for WHAT a function does for every function in a codebase. I've found that they're much more useful (as proper editor tooling can show you them whenever you make use of a function) and by being short and ONLY describing the _what_ and not the _why_ or _how_, the comments have a better survival rate and encourage people to avoid trying to make individual functions too complex.

In this case, your function may benefit from a comment such as:

// Request foo from bar, optionally backing off and re-trying <retries> times

The function signature itself might look something like:

foo(..., retries: Optional[int]) -> ...

Or alternatively you could do something similar with an explicit timeout instead.

The only missing piece I can think of is that if you have some form of back-off you probably need some initial delay before retrying, in this case this should probably be made a constant and this constant (without making any explicit references to its value or whatever value it is based on) may benefit from some reference to the method by which it was chosen. If you do intend to make it depend on the actual rate limit (e.g. 100 requests per second) then that should itself be a constant. But I think generally code like this should be avoided due to its fragility.

In any case, it is again difficult to give too specific of a recommendation given that I haven't seen the code but I don't think the comment you gave is a particularly good example of something I would personally ever recommend or want to see in the middle of a block of code.

[0]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/429


> then that person can refer to the VCS blame (e.g. git blame) logs to find what _should_ be a detailed commit message explaining all of the 'in the moment' reasoning for why and how the code was written

Agreed, they "_should_" write the reason why, but many committers unfortunately write the "what" rather than the "why".

I like comments in code, and they're the first thing I read when, say, browsing the kernel or the Golang standard libraries/packages. And I appreciate that you don't find them as useful--more power to you!


People have different ideas of value. I see a method that sounds like that and a 429 and I have a pretty good idea of what is going on without someone taking up more lines to describe the method than execute it.


> I see a method that sounds like that and a 429 and I have a pretty good idea of what is going on

Yes, you're a seasoned HTTP developer. The comment isn't meant for someone like you. It's meant for the other developers on a shared codebase who may not know much beyond the standard HTTP status codes (200, 400, 403, 404, 503).

> taking up more lines to describe the method than execute it

It's a one-line comment. the Ruby code with the exponential backoff, eight lines. It does not take up more lines than the method.


You split developers in to two categories, but how do you know those are correct categories? What if there's another type of engineer that only knows about 200 and 400?

My approach is that conventional knowledge doesn't need to be documented in comments. Attempts at guessing how much conventional knowledge someone is lacking are futile. Those comments are similar to:

  int a = 4 // set a equal to four
If someone doesn't know what 429 is, they should get confused, do their own research, and learn. Comments should not be turned into educational material about open standards, they should be about your business. There are much better places to learn about standards.


>if you just get these same people to write more comments, they will also think their comments are clear when they're, in fact, not. I think anyone who is capable of writing clear comments is also equally capable of writing clear code.

Think of it more like two lines of bearing. You are far more likely to get an accurate position from two lines of bearing. If you need to understand what past self was thinking, a comment is written in a different mindset than the code. Two different lines of reasoning.

Also, I rarely think about writing code for someone else. I write for my future self. And I really want my future self to like my past self. So I strive for clean code and write detailed comments, complete with references.


> Think of it more like two lines of bearing. You are far more likely to get an accurate position from two lines of bearing.

I mean in theory yes, but in practice I've usually found comments in such situations to either be missing, outdated or misleading.

>If you need to understand what past self was thinking, a comment is written in a different mindset than the code.

I don't think I agree with this at all, why would the mindset be different when they were both written at the same time?

Like I said, writing good comments requires just as much if not maybe more self awareness of what you're likely to forget in the future as writing clear code. I think if you're at that level where you can successfully muster that, you should spend your time just making your code clearer.

In reality I think it's even difficult to muster that requisite introspection skill in the moment and it's usually best left until after you solve the problem (let's say, the next day) to go over the code and check how clear it really is.


I have no idea what clear code without comments mean. I think I’ve actually once or twice seen that. The first was an erlang codebase. The second was a golang codebase (the letsencrypt codebase!). I’ve read a shit ton of code in my life and these were the only time I found something uncommented that I could follow easily. And even these codebases would have been clearer with comments.


I don't think your experience is uncommon, I agree that the vast majority of code out there isn't very clear. That being said, you have found code which was clear without comments, so clearly you do have an idea of what clear code without comments means.

Regarding why I don't think that clear code should have comments, it's very simple, comments are not type checked or syntax checked or even tested (unless, I guess, you hire someone to read them). It's very hard to ensure that over time comments don't deteriorate and become unhelpful. This is a much larger maintenance burden than the maintenance of clear code itself.

I think a lot of the issue boils down to people assuming that because all the code they've ever read was unclear, that code itself is inherently unclear.


> I think anyone who is capable of writing clear comments is also equally capable of writing clear code.

Imo, first, they are two different skills. And second, sometimes it is easy to write down what I am trying to achieve, but hard to achieve it with clear code. And other times it is vice versa - easy to write the code and hard to put it into words.


It's never easy to achieve something with clear code (unless you are writing a hello world program) but it is a skill you can practice and which will pay off more than any comment. At the end of the day, a comment which clearly explains your reasoning and intentions won't help prevent bugs which have an increased likelihood of occurring in unclear code.


The problem with this argument is that it's implying that there is no such thing as clear code. Sure some people think their code is clear when it is not, but that shouldn't stop you from striving to write clearer code.

A long time ago, I had a tendency to write comments to explain code that could be simplified. Refactoring it usually made the comments redundant.

Comments are still very useful when the why is unclear.


There is a culture that the l33ter the code, the more senior I am. So, many people will never refactor code to make it simpler to read. It affects their ego. In fact, I've seen the opposite: simple code refactored into more complex (not by the original author). The mindset: if it's more complex, it must be better.

Java example: rewriting non-stream collections code to use lots of chained streams. Using lambda functions when not needed. Rewriting case labels to use case lambdas. etc.


and don’t forget the implicit corollary - if you don’t understand it that just means your IQ is too low, find a job somewhere else noob…


> Refactoring it usually made the comments redundant

That sounds like a nice story


The fact that you don't believe me blows my mind a little, not going to lie. Maybe this will convince you a little more? https://refactoring.guru/smells/comments


Don't be too hard on them, they're only a baby after all.

More seriously, I agree with you 100%. Many, many, times I've stopped halfway through a writing an explanatory comment and refactored the to make the comment unnecessary.

This habit was formed by realizing that most people (including me) don't read comments half as carefully as they read code. So if you want something to be noticed and understood, you better put it in the code.


Many people think their subjective comments are clear! Code doesn't lie, comments do.


So train people to write better comments, because although code doesn't lie (questionable as that is since the intent behind the code and what it does doesn't always align) it can be literally the worst implantation of an algorithm imaginable, and so we teach people how to code.

Teaching people how to comment is a skill that's just as important and nothing turns me off a project faster than the "code is its own documentation" mantra.


This is misunderstanding the point. Code cannot lie. Reading code (correctly) gives you a correct understanding of the state of the system, no matter how clear or unclear it is.

Reading comments only tells you what the person who wrote the comment believed. It does not tell you anything in particular about how the system behaved, you have to trust the other human beings (in general a long succession of them) to have understood it correctly. And any one of you can mess that up.

Saying good comments have value is fine. But their ability to lie is unique; code doesn't have that misfeature. You can't make comments lie-free by fiat, for the same reason that you can't train your developers not to write bugs.

Given that, IMHO comments have limited value. Don't be a zealot in either direction, but when debugging hard problems, train yourself to ignore the lying comments.


While code gives you a correct understanding of the state of the system, it doesn't give you any understanding of why the system is in that state. That's the point from the OP. Code tells you what a system is doing, not why it was designed to be that way. Comments that try and explain what a system is doing can absolutely be wrong and therefore problematic, but there's no way for code to convey the context in which it was implemented a particular way, which is what comments are for.

Code without comments only gives half the story. It gives you the what, not the why.


> Code cannot lie

Sure, but it can take you on a freaking trip. Comment your code bro.

This whole argument makes me think of C coders who say C is perfectly safe as long as you don’t write bugs.


The point is not to fetishize comments. Write a comment if you feel something needs explanation, but don't freak out about "uncommented code" as a smell or whatever, when reading the code should have been your first step anyway.

And to repeat: when debugging, train yourself to ignore the comments. They will absolutely lie to you.


Imo comments are like formatting. If you don’t enforce it in CI it’s going to be bad


Forcing developers to write comments[1] just to get code merged seems like the best possible way to ensure those comments are lies.

[1] Which, it's important to point out since you used the term "CI", are fundamentally untestable. There's absolutely no way to ensure a comment is correct. A CI smoke test at the very least verifies code builds and doesn't break pre-existing cases. No such validation is even theoretically possible for comments.


I’ve seen it done before and no, it was beautiful, everything was commented


This is a good point, and I'm not arguing with it, but I don't think the words "code cannot lie" are the right way to express it.

Code can deceive even if, definitionally, the code states what the computer will do. So code most certainly can lie.

[By analogy, you'd still feel lied to if someone told you something that is technically correct but very misleading: "(Me) It's going to rain tomorrow." → tomorrow comes → "(You) It isn't raining today!" → "(Me) It is raining, in Japan. I didn't say it would rain here."]

I suppose it depends on whether you're considering what the code communicates to the machine or what it communicates to a person.


How about "code does what it does but comments say what it might have once, and possibly still might do?"

You can have your pipeline regression test code, but not comments. Just recently my mentee found some of my code where I had changed the code but not the comment. I'm a horrible human and wasted his time. If that comment hadn't existed the code might have taken a moment to understand but as it was, he wasn't sure which was the intent.


+10

It sounds like we have had similar experiences and have come to similar conclusions.

Learning to code, learning to comment and learning to log are all ways to learn to communicate and represent a means to risk-reduction and importantly, to cost-reduction.


How much do you charge to run training sessions on how to write better comments?


Here's a free method that's twice as much work but produces great results:

immediately after composing, for each step and nested step, write a line or two of what its place in the code is for. Write it as though the code is broken and you're following the imaginary line threading through, explained as if to your rubber duck.

Then, having written out the business logic map, look at each written step and see if they're just a description of the logic "iterates through file, passes hits onto nextFunc" and you can safely delete those. They're just glue, really, holding processes together.

What you'll have left is skeletal comments that are restricted to "we did this because this stackoverflow post gave the solution" as well as those mental maps of the solution in your head, which is really what comments are for, future programmers to grok your state of mind and thus better implement their code changes.


Comments can lie, but so can code...

  function Add(int a, int b) { return a - b; }
Code can lie in so, so many ways that are much more obscure and confusing than this simple example.


And also, the code can be clear and tell the truth along with the comment, while still being unhelpful:

  // Add with adjustment factor
  function AddWithAdj(int a, int b) { return a + b + 12345 }
When the function was written, everyone probably knew what the adjustment factor was for and how it was determined, but years later, someone's going to look at that code and have no idea.


>When the function was written, everyone probably knew what the adjustment factor was for and how it was determined, but years later, >someone's going to look at that code and have no idea

Well, to be fair that adjustment factor could be refactored to use a usefully named constant, with a helpful comment.

static const int ZEN_ADJUSTMENT = 12345; //When I wrote this only myself and God knew what this value meant, now...

int AddWithAdj(int a, int b) { return a + b + ZEND_ADJUSTMENT; }


  static const int ZEN_ADJUSTMENT = 12345; //When I wrote this only myself and God knew what this value meant, now...

  int AddWithAdj(int a, int b) { return a + b + ZEND_ADJUSTMENT; }

And now the maintainer is going to wonder why the originally programmer defined ZEN_ADJUSTMENT just above this function, but actually used ZEND_ADJUSTMENT (which is apparently defined somewhere else in the code). By design or typo!? :-)


// Adds two numbers together function Add(int a, int b) { return a - b; }

is even less clear.


Sure, but I don't think anyone would call this a useful comment - it's exactly the kind of comment which should be avoided.

Comments don't need to describe what the code does, but if there's an unexplicable line which handles an obscure edge case you better add a comment or even you won't remember why that line exists 3 months later.


Because comment is out-of-date. That’s technical debt. The comment is not the problem: the developer not updating it is.

You wouldn’t leave out-of-date code in a system, it would cause bugs. Why would you leave out-of-date comments? Oh, because you don’t like to write. Your strength is math and code, not writing. Now we get to the heart of the matter and not some ruse like “code is self-documenting.”


Not really. You clearly see that the intent at some point was to add two numbers, and not some fiction about ADD the diagnosis or what ever.


So which one is right, the name of the function (the comment), or it's implementation?


Rethorical question? You can't know that without looking on how the function is used.

You at least know something is strange from the comment.


i mean, this is actually perfectly clear—in the sense it’s clearly and obviously a mistake either with the comment and function name or it’s implementation. the example isn’t great because it’s devoid of context that might indicate what specifically is wrong with it.

there are many standard means that should catch this: code reviews, unit tests, etc.

this stuff can obviously still sneak through, but i don’t think this is a good example of what folks are generally talking about here.


+10

Comment review is as important as code review.


Exactly.

Here is another example where a comment can help.

  // Do does x, y, and z, in that order.
  func Do(x, y, z func()) { 
      x()
      z()
      y() 
  }
Sometimes, as here, the comment correctly describes what the code should do. But the implementation does not agree with the comment. Relying on the comment, a developer can confidently fix the bug, or, at least, notice a discrepancy between the intentions, as described by the comments, and reality, as implemented by the lines of code. This is particularly important in complex code. Think: HTTP keep-alive handling, in which many factors, with varying priorities, have to be taken into account (e.g. client hint in the request header, current server load, overall server configuration, per handler configuration).


It’s also plausible that the function used to do x,y,z in that order, but then a new requirement came to do z before y. The code was changed, maybe a test was even added, but the comment was never fixed.

That’s the problem with comments (and all documentation really) - it gets stale and has no guarantee of being correct.

A better way is to write a test which would break if the order of x,y,z was wrongly changed. This way the order is guaranteed to stay correct forever, regardless of any comments.


I agree with your points regarding writing a test. It is one of the best ways, and the right way, to handle the issue.

That said, I think my toy example wasn't the best way to show some of the points I was getting at. Consider a real example, such as this function from file src/net/http/transport.go in the Go source:

        // rewindBody returns a new request with the body rewound.
        // It returns req unmodified if the body does not need rewinding.
        // rewindBody takes care of closing req.Body when appropriate
        // (in all cases except when rewindBody returns req unmodified).
        func rewindBody(req *Request) (rewound *Request, err error) {
                if req.Body == nil || req.Body == NoBody || (!req.Body.(*readTrackingBody).didRead && !req.Body.(*readTrackingBody).didClose) {
                        return req, nil // nothing to rewind
                }
                if !req.Body.(*readTrackingBody).didClose {
                        req.closeBody()
                }
                if req.GetBody == nil {
                        return nil, errCannotRewind
                }
                body, err := req.GetBody()
                if err != nil {
                        return nil, err
                }
                newReq := *req
                newReq.Body = &readTrackingBody{ReadCloser: body}
                return &newReq, nil
        }

When you work with code in or around this function, the existence of the comments tell you what the function guarantees, for example, regarding the closing of the request body. If at some point, there is a bug, it is more likely to be noticed because of the discrepancy between the intentions in the comment and the implementation in the code. Without the descriptive comment, an unfamiliar developer working on this code will likely not be able to tell if something is off in the function's implementation.

Also, as a user of code, it's nice to first know descriptively what guarantees a complex internal function promises from its comment. Then, if necessary, be able to verify those guarantees by reading the function body.

Of course, in an ideal scenario, a unit test is the best way to address things. But this this is a 22 line function unexported function in at 2900 line file, and sadly it appears this function isn't unit tested.

So, given how things are in practice, I argue that the presence of a comment, like here, can help with correctness of code.


Comments shouldn't be there if they are not maintained in same way code is, meaning there isn't shared understanding in the team about their importance. And important they will be if you actually maintain your code, or somebody else is. Adding few comments means you show respect for their time (and sanity) so they can focus on delivering changes or fixes instead of just grokking your crap.

Every time I see 0 comment in complex logic I attribute it to laziness of coder. And of course every time excuse is the same - its self-documenting, you see what its doing etc. But why, what are the effects elsewhere in the system and outside, what part of business needs this is covering, what SLA it tries to cover, what are overall goals etc. can be even impossible to grok from just code itself. World is bigger than just code.


I wouldn’t use the word ‘lie’ but plenty of Rails code I’ve seen has mystery effects and hard to follow coupling due to monkey patching and the like. Comments please.


> Code doesn't lie, comments do

    pi = 3


You can't attach a debugger to the comments and figure out why your code is calculating that the circumfrence of a circle with radius 1 is 6 rather than 6.28...

You're proving the point of the person you are responding to.

pi = 3 isn't a lie, it's the truth of the program regardless of what any comment says.


But that is a lie. It's deceptive and misleading. The code states what the computer will do; nobody is contesting that or claiming otherwise. They were pointing out that, although part of what `pi = 3` communicates to a person (that the machine will assign the value 3 to the variable named "pi") is correct, another part of what it communicates (that 3 is close enough to the ratio between a circle's circumference and diameter for the task at hand) may be untrue – and thus a lie.

The programs that people work with in their mind are not the programs (the code) that the machine runs. What the machine does is definitely more important in the moment, but the models that live in the heads of people are more important in the long term. The code that the machine runs is just one implementation, a shadow cast by the real thing from one of many angles.


> Code doesn't lie, comments do

Code doesn't tell the full story either. And code can contain bugs so one cannot fully trust the code too.

If code/comments are out of sync it is likely that someone changed the code and forgot to update comments (which is possible to verify using VCS logs) or it may be that the comment stated the intention right but the code has a bug. Code+comments like a parity check to me - if they agree it is good, if not - I have to investigate if the comment or the code is correct.


Yet, code might not tell the whole story. It's a pitty.


Code can lie too. Example: poor naming of classes, functions and variables. A name can tell you it's doing one thing but it can be doing something different.


It may not lie, but it can certainly misdirect.


I agree with you. It’s like having too much doc, or doc so outdated it’s harmful. These are fairy tails. I’d take too much doc or outdated doc any time of the day over no doc/comments.


Too much documentation, outdated documentation or just plain wrong documentation leads to people simply ignoring it altogether, even the good parts.


Who cares if they ignore it. The moment where they get stuck on something then they can check the part that refers to that


IMO, it is better to err on the side of too much comments, as comments are easier to delete than code




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

Search: