> The second one is ok, but please don't follow the first one as a good example, it takes away the ability to scan the code.
IMO if at all, this type of comment ("Why was X designed this way") should go to the very bottom of the file (maybe with a very short comment at the top of the file referencing it), so it doesn't bother anyone who works on the code on a regular basis. And one could (should) also decrease its verbosity.
A lot of code files starts with lengthy copyright notices, and no one seems to mind. I find comments at the top very easy to ignore if I work on that code regularly. Also, I don't think I've ever seen comments at the bottom of a file!
I wonder if Protobuf wasn't open-sourced by Google, that comment would've been replaced with a link to a design doc. Google docs weren't a thing in early 2000s when Protobuf was originally written though.
> A lot of code files starts with lengthy copyright notices, and no one seems to mind.
Hmm, maybe I'm the odd one out but I actually find them quite annoying if they're longer than just a few lines.
In any case: People often just scroll past and ignore lengthy comments at the top (maybe precisely because they're used to copyright notices), so I think a short comment at the top like "For design considerations and reasons this code has been written the way it is, see the very bottom of this file" will attract much more attention.
> Also, I don't think I've ever seen comments at the bottom of a file!
True, but how often do you see code comments about design considerations in the first place?
I agree that some comments in the first example are unnecessary, e.g. the one pointed out in [0], but I find comments like that at worst useless, but not harmful. They have a potential to become harmful if someone updates the code but doesn't bother to update the comment, but I can't see how it takes away the ability to scan the code.
It’s tricky, I think I remember reading a paper by Microsoft research (I’m really sorry; looking for a source) that showed a correlation between bugs and all lines of code including comments.
So if that’s true redundant comments do hurt you.
Anecdotally in dynamic languages incorrect comments related to types seem to be a constant pain for me. They’re unverified and so a second source of truth that often wrong and can’t be trusted.
These days I write my code as comments first and then write the code.
But for example this one
// If either token bucket capacity or refill time is 0, disable limiting.
if size == 0 || complete_refill_time_ms == 0 {
return None;
}
The comment is the same as the code. It is pointless. Instead I might say under what circumstances I expect them to be zero or why Im disabling limiting when they are zero.
This one is great, though at first glance I cant relate the actual code to the comment, at least I understand why the code is there.
// We still have burst budget for *some* of the tokens requests.
// The tokens left unfulfilled will be consumed from current `self.budget`.
tokens -= self.one_time_burst;
self.one_time_burst = 0;
In defense of the first comment, when first approaching a body of code like this, it's not always going to be clear what returning None is going to mean in any given method.
Also, one thing I think doesn't get mentioned enough is the use of comments as anchors for text search. Having "disable limiting" expressed in English that way makes it easier for newcomers to explore the codebase.
Good point. Also the phrases in the initial comment "token bucket capacity" and "refill time" may serve as hints and can be used as entry points to searching external documentation.
It’s hard to judge out of context. IMO None meaning “disable limiting” should be a docstring/comment at the method level, describing what its return values mean, not inline next to this code.
I don't think the comment is the same as the code. If "size" was called "token_bucket_capacity" I would agree but since it's not, if you remove the comment you lose some context.
You hit the nail on the head here. This is the single most important reason for having comments in code (aside from just being a part of a coding standard).
Speaking of source code comments, antirez (of Redis fame) wrote a fantastic article[0] about that topic some time ago and I still recommend it to colleagues whenever they make the hollow statement that "code should and can be intelligible on its own, without any comments".
Maybe it's a buggy HTTPS redirect in GP's browser? Due to HSTS or something?
The HTTP version of your URL works fine. The HTTPS version has an expired cert. If I click past that, it redirects to redis.io, then gives a 404.
I know antirez is a smart guy, but if this is some kind of "I'm taking a bold stance against HTTPS" then I'd rather read the archive.org link with functioning HTTPS. My threat model prefers trusting archive.org to correctly reproduce the blog, over trusting everyone between me and antirez.com.
Wow, you just opened my eyes – I really thought he had deleted his blog! Must be the HTTPS Everywhere extension I'm using – though I really don't understand why it redirects me to redis.io just because antirez's TLS certificate is for redis.io, not antirez.com. I would really prefer a clear error message here.
I've forgotten who first wrote this, so I can't credit them, but there's a saying that if someone can't write clear, clean, and understandable code, why does anyone expect them to be able to write clear, clean, and understandable English (or whatever language)?
It's quite a bit easier to write something the compiler or runtime can understand, there's no need for meaningful names, consistent structure, or conceptual coherence. As long as it builds and passes whatever tests, the computer will accept it.
> if someone can't write clear, clean, and understandable code, why does anyone expect them to be able to write clear, clean, and understandable English
Isn't the answer to that obvious? The code is significantly constrained in form by having to be executable. The comments have no such restriction.
While surely not the source of the saying, antirez argues in a similar direction:
> You may think that writing comments is a lesser noble form of work. After all you can code! However consider this: code is a set of statement and function calls, or whatever your programming paradigm is. Sometimes such statements do not make much sense, honestly, if the code is not good. Comments require always to have some design process ongoing, and to understand the code you are writing in a deeper sense. On top of that, in order to write good comments, you have to develop your writing skills. The same writing skills will assist you writing emails, documentation, design documents, blog posts, and commit messages.
In any case, you're making a good point, though I would argue that the reverse of the saying (with the modification that "expectations" get replaced with "trust") also holds:
If someone is not able to write intelligible, stringent English, I wouldn't trust them to write good code, either, because writing good code requires similar qualities (good stringent structure, empathizing with the future reader of your code etc.) and, as antirez argues convincingly, it also requires writing comments (which are in plain English).
> if someone can't write clear, clean, and understandable code, why does anyone expect them to be able to write clear, clean, and understandable English (or whatever language)?
The comments don't say the same thing as the code. In the comments, the author might tell us - albeit not clearly or in proper English, what they want to achieve, or why they're doing it this way.
If someone takes a dozen lines of convoluted code to express what can be done in 2-3 lines concisely, the explanation isn't going to help. Think of the worst mess of if/then/else clauses you've seen, or someone who switches on a type instead of using polymorphism. Even if they can explain it well enough that you can follow it, the comments aren't going to improve the understanding much. They are more likely to add cognitive load and make it harder to grasp the intent.
I'm not sure we agree. But I guess the question comes down to what you and I mean by "intelligible".
antirez provides several examples where the code without the comments would be much harder to understand and/or maintain. Whenever this is the case, I would argue that comments are a must and without them the code is at least barely intelligible.
Very often it is just not possible to truly understand code without comments (or other form of documentation). This becomes obvious if you realize that code by itself can only tell you what is being done, but not why.
I love this line: "Comments are rubber duck debugging on steroids, except you are not talking with a rubber duck, but with the future reader of the code, which is more intimidating than a rubber duck, and can use Twitter."
I tend to write 'debate comments' of the software that I write for my own business (sole proprietor). I think they fit the 'why' category above.
I often doubt my own decision making process, so I tend to write it out in comments, so that I can I can see reasoning.
My general challenge with comments is of 'maintanence'.
The tools to maintain comments, cross link them across diagrams or other hand-written documents -- are hard to find.
So am gradually switching to my own directive that 'all documents about implementation, the API and their usage, are to be generated from my comments'.
Again, not a lot of tools that I found in this area, but at least it is possible to write my own tools (using IDE APIs) in this area.
A lot of this I find to be kinda bad commenting, you've got to remember NOT to just directly comment on what the code is doing, but rather explaining why. With future updates your comments will eventually be wrong if they do anything other than give context.
If all your comment does is say what the code on the next line is doing, don't. Instead just try to make the next line more readable.
While I agree with the general sentiment, the first example in the article IMO demonstrates how "what" comments make understanding code easier. When I first read that code, I was pleasantly surprised how easy it was to understand everything going on there, even though I had no familiarity with the code base. This is rare for non-trivial projects. I'm not sure if it could be made as clear without those comments.
Agree; could be very helpful if somebody not fam with token buckets arrives at this code for some reason and needs to make sense of it. Also, I think one person's "what" is another person's "why":
> if self.one_time_burst > 0 {
What is this code doing? It's setting up a flow control statement. It's dereferencing the "one_time_burst" property on the object self and comparing the value to 0. If the value is greater than 0, it will execute the proceeding code block.
I’ve similarly been paying much more attention to convey INTENT which I think is massively missing from computer science. The code might suck, but if the intent is clearly defined, it helps to refactor later.
How do you know what a function does, without a "what" comment to explain it? Even "obvious" functions like Math.max have edge cases, and I rely on "what" comments to understand how those cases are handled.
I just prefer nice, long, descriptive function names.
I was working on an unfamiliar codebase yesterday and had to work with the postMessage function. It was React, so one might assume that it sends the message to the backend, which was my initial assumption. Nope. It posted it to the page. Didn't help that another utility had another postMessage that was about what to do after the message was sent.
I worked with a guy who wrote a CPU simulator and exceeded the MSVC 256-char function name limit. It's hard when you like 80/100 col code and a function name is longer than that.
Better than writing really long descriptive function names is to not get carried away but write well described function names that show some intent or description and are chosen carefully. I worked on some code bases using long descriptive function names (inherited from another dev) and it wasn’t always useful. It was overkill. The descriptions were either too generic, too descriptive (redundant in half the cases) or handling such long saussage names was simply tiring. When you have to scroll right to read a name it becomes a problem..
The takeway is that merely writing very long descriptive names isn’t a silver bullet and could cause harm despite good intentions.
I suggest going back a after a few days for a refactoring (renaming functions or variables) and see how it reads to you. Then repeat the process a few days later when you’re even more detached from that code.
In many cases self documenting code is going to help you remember the model you had in your head when building it. And if done well it will help others as well, your code will end up not giving headaches to future maintainers.
Even something simple like “if the function starts with “is” it will return a Boolean has helped me organize things that return status codes and have side effects. Small thing, but I like it.
> The code should explain what it's doing (self documenting code) and tests should explain why it's doing it.
I agree at a surface level, however:
- this makes us assume that there are tests in the first place
- this makes us assume that someone will read these tests instead of asking the developer
- this makes us assume that these tests will be readable enough on their own to replace free form text
- this makes us assume that these tests will even be able to contain a representation of why the code exists
- personally, i have never seen a test that explains a business requirement with enough context not to miss out on details
- i have also never seen code that encapsulates these requirements 1:1, without getting too mixed up in implementation details
I think that code definitely should describe what it's doing, tests should explain how it's doing it as far as possible (though this requires discipline to have loosely coupled and testable code, which isn't always the case) and that there still should be comments that explain the realities of needing technical solutions for people problems and all of the aspects that are carried with this.
Doing anything less feels like giving ourselves constraints that will lead to suboptimal results because the tooling and testing solutions aren't quite there yet. Maybe when frameworks and languages will become more expressive, we'll be able to live without comments. However, that day may not come anytime soon.
Nor will companies be interested in the overhead that writing extensive and good tests entail, nor will they want to wait for their engineers to figure out how to convey everything in computer code, as opposed to just dropping some comments into the codebase, right next to the actual code that they concern. Maybe when companies are ready for 50% of the development time to be spent on testing software, that won't be an issue. That day may also not come anytime soon.
As a possible counterpoint, look at RSpec, i think it's headed in the right direction: https://rspec.info/
I was going to say "So for performance "hacks" there should be a clean implementation that's benchmark against the current implementation for example?" as a way to disprove what you said, but while writing it I realized that it may actually be a pretty good idea.
You've just written some messy unclear code for performance reasons, so it deserves more thorough tests than average.
And you've already written the clean version anyway, since you hopefully didn't write the optimized version until after you profiled the slow one. So it's not even significant extra work to turn that into your test suite.
This could also be a great way to check if your optimized version is still necessary with new versions of your language implementation. The more I think about it, the more it seems like a great idea.
I wouldn't generally throw benchmarking into the unit test process, because it can be brittle. What if something else clobbers the CPU on your test machine at just the wrong time.
What you really want from your unit tests is for them to run quickly, so you run them as often as possible, and reliably, so any failure means something is wrong. I'd use the slow implementation just for checking correctness.
But separately, if you want to add a performance benchmarking process (great!), you have a reference baseline implementation for free.
Personally I found most of those examples to be not great. I think they would be improved better names overall, more well named private methods and most importantly well structured companion test classes proving the behavior.
I really dont want to read another developers comments on their mental state while I am feverishly debugging their code during a 3am page.
The number of times I have been misled by an outdated comment. I generally open git blame to see if the comments predate any code now. Tests on the other hand almost never lie.
Readmes or comments explaining why something exists vs what it allegedly does are generally much better. If you can’t write expressive code why would you assume your English is much better?
In a vacuum I like them and when I bump into a piece of 10 year old code commented like this it is great.
There is one caveat however, they have to be meticulously maintained and always updated to reflect every change made to the code. It is a huge caveat because more often than not the comments are out dated and no longer reflect the actual code and at that point they are detrimental.
That's why Knuth had the idea of creating literate programs where documentation and code was maintained in a single block. Unfortunately, this idea was never used in large scale.
Yeah, I think there's a fundamental problem with the implementation -- with small, single-file programs where the code can be written in a chronologically linear manner it works well. But with that there's no need for reordering logic, so much of the more complex parts of weaving are redundant. Scripts, for example, are pretty easy to set up as [for example] markdown files, which works great (particularly in a project that requires a set of helper scripts which need why communicated -- having a set of markdown files in a folder makes it IME much more ergonomic for other devs). Anything larger and it gets increasingly fiddly and (again IME) not worth it.
>The number of times I have been misled by an outdated comment
Imo a problem with code review and not leaving comments. Just like tests need changed during refactoring, documentation and comments should also be cleaned up as part of the change
I have found those as well but place the blame on the person who made the subsequent change and ignored them
I agree, but git and most code reviewing tools I've used only show a few lines of surrounding context so the reviewers might not even realize there's a comment further up that needs updating.
Generally speaking, for all but the smallest of changes you should never only review the diff, but pop open the actual file on that branch (GitHub makes this fairly easy, I can't speak to other tooling) and consider the change in the context of the surrounding code. Does it contradict comments? Needlessly duplicate code from elsewhere in the file instead of creating a single function to be used in both places? Shadow variables confusingly? Add yet another 5 lines to a 100 line function instead of leaving the code better than it found it?
You can't really judge any of this if you're just eyeballing a diff. Diffs are just the starting point for a review, and while tooling could make this easier, the full file is always just a git checkout away.
There’s not many code review platforms that are great at showing you relevant comments in a diff because they are often in a much different part of the file, so I kind of think it’s hopeless in a large code base to catch this sort of thing in a code review
I was mostly thinking about how small changes can sometimes touch a larger quantity of files on moderate or large code bases, so a bit more things to wade through when doing a review, but point taken.
Comments are "reached for rarely and last". Whatever shortcomings comments have pale in comparison to being faced with and trying to figure out undocumented or too sparsely commented code, which, in my long experience, has been an order of magnitude more prevalent than sufficiently documented/readable code. Heck, even a wrong comment is sometimes preferable to no comment if it at least gives me a clue as to what the purpose of that section of code was at some point in its evolution.
I personally strive for code that can be read as a sentence, especially in complicated sections of code.
This sometimes leads to weird intermediate variables which might look superfluous, e.g. intermediates like:
foo_has_at_least_1 = len(foo) >= 1
(not a great example, usually it’s a bit more semantics. than that) but later code using those intermediates reads as english,
which can reduce cognitive load when reading the code and obviate comments, and preconditions are more readily verified.
It’s literate programming and I prefer that to long comment blocks like those in some
of the examples. All that said, it can be hard to get coworkers into such a habit, especially those who feel brevity and abbreviation is a virtue.
The problem comes not with what the code does but why the code exists in the first place.
The only time I ever feel the need to leave comments is to explain code that doesn't appear to be needed or isn't obvious why it exists. Usually this comes from agreed upon technical debt, short notice requirements with tight deadlines, or some other form of tradeoff.
"We're doing a simple check and throwing an exception here since we have work to introduce a more comprehensive permission system in xyz epic"
or something like
"There's a complicated race condition in xyz so we're doing a simple sleep here since the proper fix involves introducing a distributed lock"
Sure those types of things are cases you want to avoid but unfortunately you occasionally end up there anyway and leaving a short explanation about a compromise is better than ambiguous code that appears to serve no purpose
I dont think that held in the examples or a lot of what I have seen in practice once comments become the norm. Most classes should not need a comment in them at all. Most methods should be self-explanatory. A comment detailing every line of code is a huge smell.
Agreed, I think that the code itself should be readable through better names, with the comments being a bonus rather than critical to the understanding of the code.
In my experience, it's much easier to get just the right level of abstraction for quick reader comprehension in natural English, compared to any programming language.
Yup, the rate limiter comments are unhelpful. A top level comment explaining the idea is fine (and very useful) but code should largely be self documenting.
The problem with all discussions of good commenting style is that it's like debating good footware. Good for what? Office? Hiking in snow? Walking on the beach? Except that we have different footware for different uses but only one set of comments.
Having such a limited commenting syntax is like assuming one permanent type of footware and debating which one would be best. I'd much rather have a smarter commenting system.
I'm not talking about supplementary docs stashed elsewhere to gather dust. I'd like to have expandable comments right where they are needed but usable differently for a glance at familiar code or puzzling through unfamiliar code. Something very brief that doesn't clutter the code, a couple of words or no words at all, with an expansion arrow to something more detailed, expanding to something fully documented with links to everything.
And comments with scope (this comment applies to this line, this one to the function, this to a group of functions...) that actively use the scope. By active I mean that if you make any edits to code in the scope of a comment, that comment changes color or some other mechanism similar to a Git merge conflict: You changed the code without changing the comment, so check and make sure the comment says what you want and click OK. You don't have to fix the comments immediately for each edit. Make a few changes, test, make sure it's working, but when it is, you can see at a glance which comments need to be checked.
The general idea is instead of debating The Best Way to Comment, consider ways to improve the commenting system itself.
> (this comment applies to this line, this one to the function, this to a group of functions...)
This is probably the major reason I much prefer introducing new variables and functions solely so I can give them descriptive names over using comments. Comments aren't scoped so they're often ambiguous and imprecise compared to code, which also contributes to them becoming out-of-sync with the code over time. Comments above a function definition are generally better than comments inside a function for example as it's clearer what the scope is.
I have to agree. Unit tests are some of the most helpful things I’ve used whilst refactoring the Libreoffice vcl module. In fact, I’m now at the stage where if I only move a class into a new header I’m writing a test that covers that class.
To me, comments in code are like descriptions in a novel.
I would agree that comments which unnecessarily describe what is to come are bad, in the same way that a novelist should prefer to show, not tell, unless there is a compelling reason for the reader to keep that description in mind as the immediate events unfold.
But to require almost all comments gone in favour of well-named code and external docs feels wrong too, in the same way that one would probably not like to read a book with no chapter headings, no visuals, simply describing the story in a dry (but informative) language, and relying on cliffnotes for actual context.
And if you say code is more like a technical report than a novel, I will disagree. Good code is always a pleasure to read, and typically for similar reasons that a good novel is pleasurable.
Well documented code is respectful of the maintainer's time. Nobody wants to read a monologue full of noise to understand what is happening.
Comments are not monologues. Explain what the line you are commenting does, and perhaps elaborate why. But always acknoweledge: more words = more patience required = more maintenance cost.
Also, nobody will care about what your name is in 2 years. Do not make the code about you.
On the other hand, if something is missing in the comments, it could take days to find out exactly what you need. Maybe a "level of comments" like log levels could help here?
That's a good point. Maybe add a check if the function changed and the comment didn't to remind people? But comment are already easy to forget to update, as they are not code.
I like meta comments about the business or technical decisions behind the code. You can come up with clever method and variable names to help enlighten the reader, but nothing beats an intimate, first-hand account explaining the why.
The Protobuf documentation made me cringe. Every character of its "personality" adds a cognitive burden for the reader and a maintenance burden for anyone who has to update it. If a developer wants to be cute with the same brevity and clarity that the comments would have otherwise, fine. Otherwise it's self-indulgent performative trash that should be rejected in review.
Worth comparing: http://steve-yegge.blogspot.com/2008/02/portrait-of-n00b.htm... A "n00b" is scared of code, and wants as much help to understand it as possible. An "expert" already knows all they need to know to work on the code, and is more productive by putting as much code on the screen as they can.
Rather.. I think part of the point is, context matters. If the team is small, and the project is changing rapidly.. I think the needs and expectations for documentation are different than if the project or team is large and change is slow.
Here's the problem: "Experts" (or "veterans" as the author calls them) are not created equal: There's the expert that already knows the code because she's worked on it countless times and already has a very detailed mental model of the code and there's the expert who's a very experienced programmer but has never seen the code before.
Even experts of the latter category appreciate good comments when they read code (surely not comments of the "n00b" kind portrayed in the article but comments nonetheless).
I agree with others, code commentary shouldn't be a novel. Comments should only provide info that the code can't make easy to understand. Why it was done this way, what it's intended to do, complex or nonlinear interactions that aren't clear from the code. But adding things that make reading the code sound more like English isn't helpful, it's extra work and prone to getting out of sync.
For the first example with conditions, I much prefer rolling the "why" of the comments into boolean variable names where possible e.g.
// We still have burst budget for *all* tokens requests.
if self.one_time_burst >= tokens {
...
} else {
// We still have burst budget for *some* of the tokens requests.
becomes something like (I'm missing context but you get the idea):
enoughBudgetForAllTokenRequests = self.one_time_burst >= tokens
if enoughBudgetForAllTokenRequests
...
else
...
I don't see this often though. I see the commenting pattern a lot where the comment usually duplicates the "what" of the conditional code, and it's often ambiguous if the comment is talking about the condition or a whole branch.
I think a descriptive variable makes the code easier to skim, it's more precise and less likely to become inaccurate. For a big complex conditional, you can break in up into several well-named boolean variables you compose together (but obviously comment the bits that can't be covered by a concise variable name).
Long variable names mean you perceive your simple code as being too complicated. It's an if statement. I would refactor your long variable name to something more compact like enough_budget.
IMO that should be in a comment, instead of duplicating that information every time you mention the variable. (This applies more for local variables in short blocks than for, say, global variables.) At some point the length of the name makes everything around it harder to read, since it’s been pushed so far apart.
On the other hand, token bucket implementations are hard to understand and hard to debug. And an ambiguous variable name can cause trouble because some devs might think it "obviously" refers to enough budget for some other slice of requests.
I think my preferred solution here is to extract the condition into a boolean function with a long name like HasBudgetForAllRequests. This solves the long variable name issue and also gives you a useful place to add to your budget computation logic if you need to.
The words Has and For are unnecessary words in that variable name.
Think of code as mathematical notation. Some degree of familiarity with the domain is expected. You can use shorthand symbols or words as variable names.
Otherwise you're trying to write English sentences into compact notation and that's just noise. Hard to read.
Try read the A* algorithm when the variables have all been expanded out and you'll find it's impossible to see the forest for the trees. Sometimes G is the correct name for the collection of the cheapest scores known so far. It's compact and is best explained with a comment.
I prefer this too, but sometimes poor type-narrowing support hinders it. For example, TypeScript only recently added support for aliased type-narrowing:
This. And the extra documentation is provided by tests, which are living code and evolve together with the production code.
That should be enough to understand the code.
The top of the file comment is good and well received. At the same time, you could have a wiki page with that info, where you can also have diagrams etc.
Comments are not the first tool people should try to reach because:
1. That's a lazy way to make the code clear, most code should be self-descriptive. If the teams are spamming comments it's likely to be a bad code base already.
2. There's no guarantee the comment is compatible with the code: It's natural language and there's no obvious way to test that. After versions of modification, the comments might still look like they make sense but that's not how the code work anymore.
Two alternatives:
1. Declarative programming: Try to leverage declarative programming styles more. For example, top-down style dynamic programming or memoization is always more readable and less error-prone than the bottom-up ones. You don't have to fully adopt functional programming or logic programming, but do take some inspiration from them.
2. Testing. Tests are like comments, they reflect some meaning of the code. Tests are not like comments, if the code breaks, they break.
Of course, comments are very valuable, but it's most valuable when applies in the right spots only.
On my team fit/engineering values interview I always asking about benefits of autotests. People who said that tests written alongside the code are the best documentation are getting a mental "plus one point".
152 comments
[ 3.4 ms ] story [ 208 ms ] threadThe second one is ok, but please don't follow the first one as a good example, it takes away the ability to scan the code
IMO if at all, this type of comment ("Why was X designed this way") should go to the very bottom of the file (maybe with a very short comment at the top of the file referencing it), so it doesn't bother anyone who works on the code on a regular basis. And one could (should) also decrease its verbosity.
EDIT: Confused first and second example
I wonder if Protobuf wasn't open-sourced by Google, that comment would've been replaced with a link to a design doc. Google docs weren't a thing in early 2000s when Protobuf was originally written though.
Hmm, maybe I'm the odd one out but I actually find them quite annoying if they're longer than just a few lines.
In any case: People often just scroll past and ignore lengthy comments at the top (maybe precisely because they're used to copyright notices), so I think a short comment at the top like "For design considerations and reasons this code has been written the way it is, see the very bottom of this file" will attract much more attention.
> Also, I don't think I've ever seen comments at the bottom of a file!
True, but how often do you see code comments about design considerations in the first place?
[0]: https://news.ycombinator.com/item?id=28416777
So if that’s true redundant comments do hurt you.
Anecdotally in dynamic languages incorrect comments related to types seem to be a constant pain for me. They’re unverified and so a second source of truth that often wrong and can’t be trusted.
> So if that’s true redundant comments do hurt you
Anyway, even if there was causation proven it might need to be weighed against other priorities.
These days I write my code as comments first and then write the code.
But for example this one
The comment is the same as the code. It is pointless. Instead I might say under what circumstances I expect them to be zero or why Im disabling limiting when they are zero.This one is great, though at first glance I cant relate the actual code to the comment, at least I understand why the code is there.
Also, one thing I think doesn't get mentioned enough is the use of comments as anchors for text search. Having "disable limiting" expressed in English that way makes it easier for newcomers to explore the codebase.
You hit the nail on the head here. This is the single most important reason for having comments in code (aside from just being a part of a coding standard).
[0]: https://web.archive.org/web/20210226004600/http://antirez.co... (I still don't understand why he deleted his blog)
> Sorry, I can't find that page :-/
for several months
The HTTP version of your URL works fine. The HTTPS version has an expired cert. If I click past that, it redirects to redis.io, then gives a 404.
I know antirez is a smart guy, but if this is some kind of "I'm taking a bold stance against HTTPS" then I'd rather read the archive.org link with functioning HTTPS. My threat model prefers trusting archive.org to correctly reproduce the blog, over trusting everyone between me and antirez.com.
I certainly wouldn't trust Comcast to keep malicious ads out of their ad network, either.
[0] https://www.techdirt.com/articles/20140908/07191228453/comca...
If you run this command you can see a little more clearly what’s going on:
If you use the plain HTTP URL, everything works fine.If you try https://antirez.com/news/124 the web server at antirez.com:443 will answer this:
So it’s not HTTPS Everywhere that redirects, it’s the web server itself.However, many clients won’t heed this response, since antirez.com:443 serves a certificate that’s not valid for that hostname.
It's quite a bit easier to write something the compiler or runtime can understand, there's no need for meaningful names, consistent structure, or conceptual coherence. As long as it builds and passes whatever tests, the computer will accept it.
Isn't the answer to that obvious? The code is significantly constrained in form by having to be executable. The comments have no such restriction.
> You may think that writing comments is a lesser noble form of work. After all you can code! However consider this: code is a set of statement and function calls, or whatever your programming paradigm is. Sometimes such statements do not make much sense, honestly, if the code is not good. Comments require always to have some design process ongoing, and to understand the code you are writing in a deeper sense. On top of that, in order to write good comments, you have to develop your writing skills. The same writing skills will assist you writing emails, documentation, design documents, blog posts, and commit messages.
In any case, you're making a good point, though I would argue that the reverse of the saying (with the modification that "expectations" get replaced with "trust") also holds:
If someone is not able to write intelligible, stringent English, I wouldn't trust them to write good code, either, because writing good code requires similar qualities (good stringent structure, empathizing with the future reader of your code etc.) and, as antirez argues convincingly, it also requires writing comments (which are in plain English).
[1]: https://twitter.com/KevlinHenney/status/381021802941906944
The comments don't say the same thing as the code. In the comments, the author might tell us - albeit not clearly or in proper English, what they want to achieve, or why they're doing it this way.
antirez provides several examples where the code without the comments would be much harder to understand and/or maintain. Whenever this is the case, I would argue that comments are a must and without them the code is at least barely intelligible.
- * Function comments - * Design comments - * Why comments - * Teacher comments - * Checklist comments - * Guide comments - * Trivial comments - * Debt comments - * Backup comments
"
I tend to write 'debate comments' of the software that I write for my own business (sole proprietor). I think they fit the 'why' category above.
I often doubt my own decision making process, so I tend to write it out in comments, so that I can I can see reasoning.
My general challenge with comments is of 'maintanence'. The tools to maintain comments, cross link them across diagrams or other hand-written documents -- are hard to find.
So am gradually switching to my own directive that 'all documents about implementation, the API and their usage, are to be generated from my comments'.
Again, not a lot of tools that I found in this area, but at least it is possible to write my own tools (using IDE APIs) in this area.
If all your comment does is say what the code on the next line is doing, don't. Instead just try to make the next line more readable.
Well I stopped reading further.
> if self.one_time_burst > 0 {
What is this code doing? It's setting up a flow control statement. It's dereferencing the "one_time_burst" property on the object self and comparing the value to 0. If the value is greater than 0, it will execute the proceeding code block.
Why is this being done?
> [to] consume the one-time-burst budget.
I’ve similarly been paying much more attention to convey INTENT which I think is massively missing from computer science. The code might suck, but if the intent is clearly defined, it helps to refactor later.
That's what works for me.
Self-explanatory code can't explain themselves if they do not exist
* Common name of the algorithm you're using
* Reference to somewhere else in the code that's related
* "You may think this code only does X, but it really also does Y"
* "We used to also do XYZ here, but that was removed because of ABC"
and so on.
I was working on an unfamiliar codebase yesterday and had to work with the postMessage function. It was React, so one might assume that it sends the message to the backend, which was my initial assumption. Nope. It posted it to the page. Didn't help that another utility had another postMessage that was about what to do after the message was sent.
Edit: Hah. It does.
The takeway is that merely writing very long descriptive names isn’t a silver bullet and could cause harm despite good intentions.
I suggest going back a after a few days for a refactoring (renaming functions or variables) and see how it reads to you. Then repeat the process a few days later when you’re even more detached from that code.
In many cases self documenting code is going to help you remember the model you had in your head when building it. And if done well it will help others as well, your code will end up not giving headaches to future maintainers.
Even something simple like “if the function starts with “is” it will return a Boolean has helped me organize things that return status codes and have side effects. Small thing, but I like it.
I did write up a thing about it, but it's a long read, so folks don't usually read it: https://littlegreenviper.com/miscellany/leaving-a-legacy/
Has some pretty heavy-duty examples.
Comments tend to just become a place for misinformation or get disconnected from the actual logic.
Adding more comments sometimes doesn't clarify the situation, it just acts as a second source of truth.
I agree at a surface level, however:
I think that code definitely should describe what it's doing, tests should explain how it's doing it as far as possible (though this requires discipline to have loosely coupled and testable code, which isn't always the case) and that there still should be comments that explain the realities of needing technical solutions for people problems and all of the aspects that are carried with this.Doing anything less feels like giving ourselves constraints that will lead to suboptimal results because the tooling and testing solutions aren't quite there yet. Maybe when frameworks and languages will become more expressive, we'll be able to live without comments. However, that day may not come anytime soon.
Nor will companies be interested in the overhead that writing extensive and good tests entail, nor will they want to wait for their engineers to figure out how to convey everything in computer code, as opposed to just dropping some comments into the codebase, right next to the actual code that they concern. Maybe when companies are ready for 50% of the development time to be spent on testing software, that won't be an issue. That day may also not come anytime soon.
As a possible counterpoint, look at RSpec, i think it's headed in the right direction: https://rspec.info/
I was going to say "So for performance "hacks" there should be a clean implementation that's benchmark against the current implementation for example?" as a way to disprove what you said, but while writing it I realized that it may actually be a pretty good idea.
You've just written some messy unclear code for performance reasons, so it deserves more thorough tests than average.
And you've already written the clean version anyway, since you hopefully didn't write the optimized version until after you profiled the slow one. So it's not even significant extra work to turn that into your test suite.
But separately, if you want to add a performance benchmarking process (great!), you have a reference baseline implementation for free.
I really dont want to read another developers comments on their mental state while I am feverishly debugging their code during a 3am page.
The number of times I have been misled by an outdated comment. I generally open git blame to see if the comments predate any code now. Tests on the other hand almost never lie.
Readmes or comments explaining why something exists vs what it allegedly does are generally much better. If you can’t write expressive code why would you assume your English is much better?
In a vacuum I like them and when I bump into a piece of 10 year old code commented like this it is great.
There is one caveat however, they have to be meticulously maintained and always updated to reflect every change made to the code. It is a huge caveat because more often than not the comments are out dated and no longer reflect the actual code and at that point they are detrimental.
Imo a problem with code review and not leaving comments. Just like tests need changed during refactoring, documentation and comments should also be cleaned up as part of the change
I have found those as well but place the blame on the person who made the subsequent change and ignored them
You can't really judge any of this if you're just eyeballing a diff. Diffs are just the starting point for a review, and while tooling could make this easier, the full file is always just a git checkout away.
With GitHub, not so much.
Not sure why code base size would make it harder... Workflow? Code unit size? The larger the code base, the more comment discipline matters IMO
This sometimes leads to weird intermediate variables which might look superfluous, e.g. intermediates like:
foo_has_at_least_1 = len(foo) >= 1
(not a great example, usually it’s a bit more semantics. than that) but later code using those intermediates reads as english, which can reduce cognitive load when reading the code and obviate comments, and preconditions are more readily verified.
It’s literate programming and I prefer that to long comment blocks like those in some of the examples. All that said, it can be hard to get coworkers into such a habit, especially those who feel brevity and abbreviation is a virtue.
The only time I ever feel the need to leave comments is to explain code that doesn't appear to be needed or isn't obvious why it exists. Usually this comes from agreed upon technical debt, short notice requirements with tight deadlines, or some other form of tradeoff.
"We're doing a simple check and throwing an exception here since we have work to introduce a more comprehensive permission system in xyz epic"
or something like
"There's a complicated race condition in xyz so we're doing a simple sleep here since the proper fix involves introducing a distributed lock"
Sure those types of things are cases you want to avoid but unfortunately you occasionally end up there anyway and leaving a short explanation about a compromise is better than ambiguous code that appears to serve no purpose
Because English is optimized for communicating human intent?
> // Returns None is x = 0
if x = 0 { return None }
Having such a limited commenting syntax is like assuming one permanent type of footware and debating which one would be best. I'd much rather have a smarter commenting system.
I'm not talking about supplementary docs stashed elsewhere to gather dust. I'd like to have expandable comments right where they are needed but usable differently for a glance at familiar code or puzzling through unfamiliar code. Something very brief that doesn't clutter the code, a couple of words or no words at all, with an expansion arrow to something more detailed, expanding to something fully documented with links to everything.
And comments with scope (this comment applies to this line, this one to the function, this to a group of functions...) that actively use the scope. By active I mean that if you make any edits to code in the scope of a comment, that comment changes color or some other mechanism similar to a Git merge conflict: You changed the code without changing the comment, so check and make sure the comment says what you want and click OK. You don't have to fix the comments immediately for each edit. Make a few changes, test, make sure it's working, but when it is, you can see at a glance which comments need to be checked.
The general idea is instead of debating The Best Way to Comment, consider ways to improve the commenting system itself.
This is probably the major reason I much prefer introducing new variables and functions solely so I can give them descriptive names over using comments. Comments aren't scoped so they're often ambiguous and imprecise compared to code, which also contributes to them becoming out-of-sync with the code over time. Comments above a function definition are generally better than comments inside a function for example as it's clearer what the scope is.
An example I’m currently working on is:
https://gerrit.libreoffice.org/c/core/+/121403/5/vcl/qa/cppu...
I would agree that comments which unnecessarily describe what is to come are bad, in the same way that a novelist should prefer to show, not tell, unless there is a compelling reason for the reader to keep that description in mind as the immediate events unfold.
But to require almost all comments gone in favour of well-named code and external docs feels wrong too, in the same way that one would probably not like to read a book with no chapter headings, no visuals, simply describing the story in a dry (but informative) language, and relying on cliffnotes for actual context.
And if you say code is more like a technical report than a novel, I will disagree. Good code is always a pleasure to read, and typically for similar reasons that a good novel is pleasurable.
Comments are not monologues. Explain what the line you are commenting does, and perhaps elaborate why. But always acknoweledge: more words = more patience required = more maintenance cost.
Also, nobody will care about what your name is in 2 years. Do not make the code about you.
> self-indulgent performative trash
A little harsher than I would have used; but now that you say it.
>that should be rejected in review.
Without question. I would have absolutely denied that until it was trimmed to at most 10% of what was there.
Want well documented (and tested and thought out) code?
Then give the coders people outside of their team / hierarchy who are going to check it / read it / use it.
And then give them time.
And repeat.
Rather.. I think part of the point is, context matters. If the team is small, and the project is changing rapidly.. I think the needs and expectations for documentation are different than if the project or team is large and change is slow.
Here's the problem: "Experts" (or "veterans" as the author calls them) are not created equal: There's the expert that already knows the code because she's worked on it countless times and already has a very detailed mental model of the code and there's the expert who's a very experienced programmer but has never seen the code before.
Even experts of the latter category appreciate good comments when they read code (surely not comments of the "n00b" kind portrayed in the article but comments nonetheless).
I think a descriptive variable makes the code easier to skim, it's more precise and less likely to become inaccurate. For a big complex conditional, you can break in up into several well-named boolean variables you compose together (but obviously comment the bits that can't be covered by a concise variable name).
On the other hand, token bucket implementations are hard to understand and hard to debug. And an ambiguous variable name can cause trouble because some devs might think it "obviously" refers to enough budget for some other slice of requests.
I think my preferred solution here is to extract the condition into a boolean function with a long name like HasBudgetForAllRequests. This solves the long variable name issue and also gives you a useful place to add to your budget computation logic if you need to.
Think of code as mathematical notation. Some degree of familiarity with the domain is expected. You can use shorthand symbols or words as variable names.
Otherwise you're trying to write English sentences into compact notation and that's just noise. Hard to read.
Try read the A* algorithm when the variables have all been expanded out and you'll find it's impossible to see the forest for the trees. Sometimes G is the correct name for the collection of the cheapest scores known so far. It's compact and is best explained with a comment.
https://devblogs.microsoft.com/typescript/announcing-typescr...
The top of the file comment is good and well received. At the same time, you could have a wiki page with that info, where you can also have diagrams etc.
Comments are not the first tool people should try to reach because:
1. That's a lazy way to make the code clear, most code should be self-descriptive. If the teams are spamming comments it's likely to be a bad code base already.
2. There's no guarantee the comment is compatible with the code: It's natural language and there's no obvious way to test that. After versions of modification, the comments might still look like they make sense but that's not how the code work anymore.
Two alternatives:
1. Declarative programming: Try to leverage declarative programming styles more. For example, top-down style dynamic programming or memoization is always more readable and less error-prone than the bottom-up ones. You don't have to fully adopt functional programming or logic programming, but do take some inspiration from them.
2. Testing. Tests are like comments, they reflect some meaning of the code. Tests are not like comments, if the code breaks, they break.
Of course, comments are very valuable, but it's most valuable when applies in the right spots only.
One of those habbits is to update documentation (tests/comments) when software is evolving.
Unfortunately it is a very rare habbit it seems.