Reducing technical debt by valuing comments as much as code
blogs.oracle.com
blogs.oracle.com
I agree that comments explaining 'what' is happening are mostly useless. Write clearer code. But 'why' comments are good. Most things can be coded up different ways. Tell me why you chose this way. Tell me about constraints that might not be immediately obvious. Let me know if indeed, it could be cleaner, but you were in a hurry (this is a thing that happens in the real world), or if it's that way for a specific reason.
1. Rewrite your code to make the answer obvious.
2. If that's not possible use a comment.
While it's anecdotal, my understanding is that we were simply working on very, very different codebases. I was refactoring multi-million lines C++ codebases, implementing concurrent algorithms in which dependencies cannot be expressed through language constructs and I had to make non-trivial choices to prioritize performance, or safety, or security at the expense of readability.
On the other hand, these (few) developers were working on writing fresh code, with less footgunny languages, with simpler data and control dependencies and didn't need to make hard choices due to perf/safety/security.
What kind of domain was it?
And this is despite significant and on-going investments in test cases, test infra, integration testing infra, and good overall dev culture around quality.
Also, pair programming has nothing to do with any of this. Mentioning it is like saying that their tests are better because they use IntelliJ instead of Eclipse. It's a very interesting fact, but irrelevant to this.
[1] I will, however, point out, that there have been many times in my career that I have said 'This comment should be a test'. Tests are incredible. [2] But there is no circumstance where I would ever agree with a blanket policy of 'Every comment should be a test'.
[2] It's entirely feasible, and highly desirable to get a small project to the point where just running the tests makes you feel 100% confident in the correctness of your changes. It is highly desirable to drive large products towards such a point, but those efforts can, at best, approach it asymptotically, and cover some enumerated, but limited set of use-cases and data-flows. [3]
[3] And don't even get me started on verifying adherence to security best-practices through testing. It's an utter miracle that security gets two thoughts from a test-writer, and those thoughts are inevitably "These checks are annoying, how do I disable them to get my test to work?"
Seriously, PL is all about TDD, I'm not joking. PP actually does matter because two people sign off on commits that they worked on together and it is quite an achievement to convince your coworker that you're sitting next to, to not write a test. Consider it a sort of checks and balances. PL's version of pair programming is 100% of the time, it works.
I have been running an open source project for a few years now with 40k downloads a month on NPM. This project has a heavy dependency on two other projects. Testing isn’t 100%, but it is enough to rely on it for releases. I also started out with TDD as well. Nothing is perfect, in fact we just had a release yesterday with a contributed fix in it, that came with a test, and still ended up with a bug... but out of 118 tags, a few here and there isn't bad. I routinely upgrade all the dependencies and never hear a peep out of people who depend on it.
Most recently, I wrote some software that ran on 20k servers... it was extremely well tested because if it failed, it could have caused massive amounts of downtime.
I've worked for a number of other companies where we had fantastic testing infrastructure, CI/CD... mostly because we started from day one with that. Bolting it on after the fact, never happens to the degree it should.
I just saw Hashicorp release Hermes today... and was saddened to see it had zero testing in it. I just sighed and closed the browser window. It just isn't worth it.
So, just like a proper code review process.
> I have been running an open source project for a few years now with 40k downloads a month on NPM. This project has a heavy dependency on two other projects.
Are they dependencies on libraries, or are they dependencies on services?
Library dependencies are 'easy' to test. Service dependencies are very, very difficult. Tractable, but very difficult. That's just one of the difference between a small project, and a large product.
Just because we have vastly more than two dependencies doesn't mean that I'm working in a shitty environment. It just means I'm working on a large problem.
> I've worked for a number of other companies where we had fantastic testing infrastructure, CI/CD... mostly because we started from day one with that. Bolting it on after the fact, never happens to the degree it should.
I'm not sure why you believe that all of these things weren't with us at day 1, either.
Except it happens in real time, with a real person, sitting next to you.
> Are they dependencies on libraries, or are they dependencies on services?
In this case, other libraries... but I honestly don't see the difference. Libraries and services have APIs. They either work or they don't. Services have the additional complexity of network failures and runtime errors, but these are things that can be dealt with and tested in the primary project.
> Just because we have vastly more than two dependencies doesn't mean that I'm working in a shitty environment.
You made the wrong equation there. The environment is shitty because you said that you're in an environment where people have created products so complex that it is very difficult to achieve adequate testing. You also shrugged off Eclipse vs. IDEA... where I'd actually say that matters. You also talk about disabling tests for security... that seems absurd.
> It's entirely feasible, and highly desirable to get a small project to the point where just running the tests makes you feel 100% confident in the correctness of your changes.
I've built multiple companies that have achieved significant revenue on that confidence. Not small projects. I know it is possible to do.
> I'm not sure why you believe that all of these things weren't with us at day 1, either.
So you started off good and ended poorly? Another reason to believe that the environment is shitty.
I assure you, I am a real person, generally sitting adjacent to people whose code I'm reviewing, or who review my code.
The projects are complex because the business needs are complex. This criticism is the 'I could build Twitter in a weekend, why does it have five thousand people working on it, anyways?'
I, like most people, have plenty of opinionated preferences on the subject of Intellij and Eclipse, but I'm not going to drive any broad conclusions regarding their impact on a product's test coverage. And I will postulate that most attempts to do so reduce down to cargo-culting. It was an example of a largely irrelevant technical decision, and I think it's telling that you are latching onto it.
And it's not disabling tests for security, it's disabling security for tests, as a distressingly common example of a routinely undertested interaction between two complicated spaces.
Not really. The theories around testing are all well established and trodden at this point. People who've been around long enough, have this experience.
> The projects are complex because the business needs are complex.
Complex business needs are separate from the functional testing of individual components. Testing business logic is well... a matter of writing a test, seeing it fail and then writing the business logic (however complex), to make that test pass. Books and PhD's have been written about TDD. The stuff isn't rocket science.
> generally sitting adjacent to people whose code I'm reviewing
Pivotal Pair programming is literally sitting next to the person, sharing a single computer, two mirrored monitors, two keyboards, two mice. Two people independently working together to control a single computer. 8 hours a day (with breaks, of course). Is that what you do?
> I think it's telling that you are latching onto it.
I think it's telling that you dismiss it. Tools are important. It is like telling a car mechanic that every wrench is the same and unimportant. There is no debate on this, IDEA 'eclipsed' Eclipse, especially for Java development (and honestly, everything else), over a decade ago. The final straw for me was when Eclipse crashed for the 1000th time and torched my workspace to the point that I had to delete Eclipse to get it running again.
> it's disabling security for tests
Which says to me that the 'frameworks' used for testing aren't set up well or that the developers you're working with don't have an understanding of or care for how to do that. No thanks. Get it right from the start and make it friendly to the people you're working with so that they aren't so annoyed they have to disable tests. It also says to me that the way things are coded are so intertwined with the security layer that they can't be easily tested independently... which is also a fundamental design issue. Obviously, there are exceptions, but the underlying issue still exists if developers are disabling tests because of this.
> In this case, other libraries... but I honestly don't see the difference. Libraries and services have APIs. They either work or they don't. Services have the additional complexity of network failures and runtime errors, but these are things that can be dealt with and tested in the primary project.
In my personal experience, there are considerable differences.
From the top of my head:
1. Typically, your libraries don't shift under you without any action from your part. External services do.
2. In CI, you can either use the external service (which may require piercing holes in your CI's security and may break due to no change of your part), replicate it (which is more stable but can be extremely painful and resource-consuming) or mock it (which is even more stable but limits the realism of your tests).
3. And of course, as you mention, services have all sorts of failure modes, including but not limited to network failures. Normally, your tests should cover all these failure modes. I don't think I've ever seen code that does that, in part because service errors are very often notoriously under-documented.
YMMV
External services should have versioning, just like libraries.
> 2. ...
They don't need to be 'or'.
> 3. ...
I write tests for this. If I'm using a networking library/function (let's use `fetch` as an example) to talk to a 3rd party external service, I write a wrapper around it to deal with error cases. I then write tests for that wrapper. Anything that uses that wrapper is then inherently tested at the networking level. I then write tests for my own code which uses the wrapper, to deal with the thrown exceptions and how that code should deal with them (retries, throw again, etc).
You don't do that? Do you just assume that all calls to `fetch` succeed?
Mind you, no serious project is anywhere close to 100% coverage. It may have 100% unit-test coverage, but that is a far cry from 100% coverage.
And the valuable comments are the ones that describe integration interactions.
I'm pitching comments as a compromise when the test that encodes their meaning is impractical.
I found that pretty much any methodology works fine in a team like that.
"Don’t comment the code" still sounds pretty crazy to me, but I can believe that it works for them.
/*
The phone number
*/
private static String phoneNumber;
That is considered 'the what', the documentation doesn't explain 'why' the phone number is a field on the class. This might be obvious because the class is called 'Address'... so people will argue that it is self documenting, and it is.The WTF code is 'the why'...
The way is useful in addition to that, and often IME far more important than the what. IMO you should document both, as necessary, and that's the hard part/skill. You have to treat it like you won't remember it in 6 months, because in 6 months, you won't. A lot of devs don't do that.
(A fair number of devs won't follow the style guide / idiomatic patterns of a language if there isn't a CI check forcing them to, and will argue to all ends with a human as to why it ought not apply to them, to the great detriment of their code's readability to other experience practitioners of the language. Oddly CI enforcement usually works better, why I don't know.)
So then the question that needs answering is:
"why" is the what not obvious?
Document the "why."
What is the phone number for? When I read it, is it ready for display as-is or should I be formatting it? Same question when I set it. Can it be null or empty? Does or can the system use this number for anything - such as sending SMS messages?
Being static is a huge red flag, though, and even though it's private I'd still ask. Why is it static? Is this thread-safe (and how)? What context does it get set in, and when can I use it?
Better not write tests either, because those will become stale too.
And any sort of user documentation/support/etc. It'll all just become stale.
It's almost as if code is just part of a larger 'thing' that has to be maintained.
Unit tests are easier to maintain when incorporated to a CI/CD pipeline. Then every pushed commit (or Merge Request) will trigger the test suite to run and in case one of the tests fails the team will know.
(I'm not arguing against writing comments though - the 'they'll get stale' thing is not enough to make them not valuable)
If you write good tests and use a tool (CI) that detects them going stale, tests will never be stale.
If you write good comments and use a tool (code review) that detects them going stale, comments will never be stale.
In order for tests to not get stale, you need perfect (well written) tests.
In order for comments to not get stale, you need perfect code reviews.
Neither of those exist in real world: code reviews are done by humans, tests are written by humans.
They do go stale, but tests were invented exactly so that your documentation is able to alert you when it has gone stale. Their existence rests on being an attempt to solve to this problem.
But if you are capable of writing perfect tests, why haven't you written perfect software in the first place?
Comments transition from truth to lie without any indication.
Only if you don't do code reviews. The reviewer should be checking for this.
Guess what: Comments are part of the code. Like all other documentation!
If you have a strong discipline of manually checking every possibly relevant comment with each review, I can see how that can mostly work (manual human checks are never perfect).
I've never seen anything close to that process, so it's hard to know how it would work. It seems to require a lot of discipline and effort.
You seem to think that git invented blame. This appeared in previous version control systems, e.g. "cvs annotate" whose synonym is "cvs blame".
This is a strawman argument.
Let's assume best CM practices (no vandalism of change sets when moving changes among branches), best practices for commit messages and best practices for commenting.
Commit messages win.
Code comments should be like road signs. E.g. how high can your truck be to pass under the upcoming bridge. Not blueprints for the bridge, or paragraphs about why it was built there, what communities it serves. (That information must exist and be available, just not on the bridge.)
I've never been disappointed when digging back in history to figure out why the heck something was done.
It would be a strawman of my position to say that I'm favoring zero comments. For instance, a /* fallthrough */ comment in a C switch statement cannot be in a commit comment, not the least reason for which being that compilers look that that nowadays.
Comments should be like road signs. I need a warning about a dangerous curve ahead, not a discussion of why it was built that way.
You don't seem to have understood my remarks; It's not "commit per function", but cover each function that was touched (or other entity: class, global variable, type, object member) in your commit comment.
When someone does "git log" they should be able to search for the name of a function of interest and see all commits which touch it, explaining what was done to it and why.
Banish squash commits; it's a poor CM practice. If you're not able to get your developers to commit to a good practice, then that's your main problem. You have to fix that before engaging "comment versus commit".
Tests represent truth in the same way code represents truth. In many ways the tests represent truth more than the code represents truth. Tests state "this is what I want" and then interrogate the code to verify that the code itself does what I want.
Tests by definition can not be stale (unless they are never called).
The ruby community is where I first learned about test driven development which is philosophically the idea that tests are the highest level of semantic importance.
There are DSL's in ruby land for writing tests like you might write comments: https://semaphoreci.com/community/tutorials/getting-started-...
If tests describe what you want, and code describes how it happens, then the major piece left is why it is the way it is, which almost everyone in this thread agrees is the most important thing to comment.
There is an argument about reducing the amount of work.
On the staleness of comments, it's a real thing. In particular, on comments explaining design decisions, they will often touch on aspects of the system that are outside of the specific method they are attached to, and nobody will go back to them to rewrite all that prose.
We had a project with a ton of documentation written in the first 2 years, and as engineer count grew, these comments just disappeared as again and again they were causing misunderstandings, and actual documentation was already written in the internal wiki as each refactorings and new features were discussed and designed.
It's not just a rails thing, and after a while people stop trusting comments altogether, which make updating them a chore more than anything.
I think that's a reasonable approach if it's easy to find the relevant section of the wiki that describes the code you're looking at by searching. Or just have a comment in the code that points to the wiki. The important thing is to document the "why's".
What this means is that if your Ruby code is clear it should read like natural language. Injecting subtitles into the middle of the expression
# I decided to phrase it this way because I was in a rush and it was the first thing that came out. With more time I could no doubt articulate this in a more communicative way, but for the sake of a random post on the internet I'm not terribly worried.
interrupts the flow when one is reading the code, which makes for a much less pleasant experience. Ruby may not be the only language that is like this, but it is relatively unique in this regard. Comments in other languages don't seem to cause the same interruption.
# That's all I've got. Time to clean up.
I'm not sure this means don't provide additional information to future readers that may be beneficial, but be discriminating in where you put it. Or do whatever you want. Who cares what someone else thinks?
The history of programming is full of that notion and it never really works out. See: COBOL, SQL, and so on.
I think we can all agree that code that is easy to read is better, but sometimes the 'why' needs spelling out.
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).
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.
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.
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.
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.
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.
Code without comments only gives half the story. It gives you the what, not the why.
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.
And to repeat: when debugging, train yourself to ignore the comments. They will absolutely lie to you.
[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.
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.
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.
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.is even less clear.
You at least know something is strange from the comment.
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.
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.”
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.
Comment review is as important as code review.
// 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.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!? :-)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).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.
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.
pi = 3You'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.
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 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.
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.
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.
That sounds like a nice story
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.
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.
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.
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.
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.
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.
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.The code comment in the GP is pithy, explanatory, and reads in plain English. Yours is ripe for misunderstanding.
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.
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
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!
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.
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.
The 5 programming languages with the least amount of bugs are:
Haskell
Ada
Scala
Rust
*Drum roll please* Ruby
Ruby is nothing like the other languages above in design, but that community has fantastic conventions around code clarity, code quality, testing, continuous integration, etc.Comments are for things like, `Todos`, Noting a specific algorithm, maybe a link to a white paper, noting a violation of a convention for speed, security, or some other performance reason.
Comments are for things that are __impossible__ to tell from the code.
You can tell everything with code, given enough time and resources. Nothing is "impossible". But there's a point where you hit diminishing returns. It's about efficiency.
Other devs, or your future self, will have to time trying to build the same "castle in your head" as you did. Can a comment shorten that time? If a one-line comment saves 15 minutes of investigation in aggregate, that's a no-brainer. You should add it. Conversely, a line that says "add 5 to x" is just wasting everyone's time.
As a general rule, once I have finally understood a particularly hairy piece of code, I don't want to do it again in 6 months. I have even done ASCII diagrams in the comments explaining how a particularly hairy piece of code worked, when I hated it enough.
It's something I wish was more common than it is. Sometimes you really want that ASCII pseudo graph explaining how minimizing this thing relates to that other thing that we actually care about.
Taken a step further, I really wish we had better systems for managing this type of information alongside a codebase. E.g. the whitepaper, or presentation, or figures, or whatever is often very necessary to understand the code, and ideally it would be under version control and live neatly alongside things. Nicely rendered docs definitely help with this (e.g. latex in comments), but I'm always surprised there aren't more people focusing on this aspect of information management.
I always assumed that behavior was dogmatic until, over many PRs, multiple members of the team commented that if I commented my code, it would be much easier to read. And comments of the above quality assuaged them.
- where the page is being read from
- what page numbers the function accepts
- what happens if an invalid page number is specified (or if that’s deliberately undefined, stating that fact)
- other possible error conditions, if any
(I’ll assume that PageData already documents what “page” refers to in that context, because for me it’s not “self explanatory” just from the function signature you provided.)
That's just not true.
There are infinite many ways to write the exact same thing.
Your code can never say why it's like it is, why this approach was chosen and not another.
> […] the comments explaining how a particularly hairy piece of code worked […]
This kind of comments are the bad ones actually.
Your code should be clear enough that it's easy to see how it works and what is happening.
The rule is actually very simple, and I don't get it why so many people have issues with following it.
"Code says what and how, comments say why."
Why does there have to be rules about when to comment? I comment frequently about whatever the hell I want. Don’t like it? Then don’t read the comments. Very simple, just like your rule.
If you think you're the smartest person on the planet so "rules" (or better said best practices) don't apply to anything you do I hope nobody ever needs to collaborate with you.
All the "rules" are there for a reason!
No, you're not free do to whatever you like in a professional setting. For example when you're operating machines you need to follow safety regulations. Otherwise you could even end up in jail quite quickly.
Except in this case, you've made up the rule. It is not an axiomatic rule like gravity. I want different rules. So unless we work together, your rules don't apply to me.
I agree with that. I don't think that makes things impossible. Only more difficult.
> Your code can never say why it's like it is, why this approach was chosen and not another.
If the why is important, given enough time and resources, someone will eventually complain that something is not working and someone will be tasked to "fix it". It may take them weeks, but they will eventually figure out the why.
> Code says what and how, comments say why.
If we are considering only quality vs quality, I agree. But there's also quantity.
When the how is complicated enough, it is indistinguishable from a why. You will hear the reviewers ask outloud: "But WHY is this done this way?". Even if the problem is merely algorithmic/technical and the code is doing exactly what it's supposed to do.
Then you have two options: spend a potentially significant time refactoring things (which is always the right choice, given enough time and resources) or spend 10 minutes writing a comment with what you learned, and moving on to the next problem.
db.insert(record); // save the record to the database
But when they write some crazy off-the-wall code (that's usually because they didn't understand the proper way to do something) I have to check the logs to see who wrote it and ask them why.
Just the other day I was debugging an application that had a 6 second sleep at the end of the main() function. I just figured it was some dumb thing left in for debugging and deleted it, because there's no good reason to do that. The next day, the dev who put it in messaged me and said he put it there because the application was exiting before it had logged it's completion to our logging system. So I explained that the proper way to do this is to flush the log, not just hang the application for 6 seconds so that the last messages just happen to go through.
If there was a comment explaining why there was a 6 second sleep, I could have just fixed it and educated the developer without causing any grief.
All why answers belong into the code, as comments.
Look up Chesterton’s Fence. :)
(I made similar errors more than once.)
I've seen people get stuck for months being afraid to change a complex piece of code because nobody understands how it works anymore. The best course of action was to admit that knowledge is lost forever and the fastest way to gain it again is to repeat past mistakes.
Of course, don't do this if your software is responsible for landing airplanes. But most of us are not landing airplanes here.
Of course, Chesterton’s Fence is just a guideline. You can weigh the risks against the benefits in each case. It’s just a reminder that there may well be very good reasons why some logic is in place. If it is at all possible to find out those reasons, then that would generally be preferable, in order to make an informed decision.
[0] https://en.wikipedia.org/wiki/G._K._Chesterton#Chesterton's_...
I know, and that's exactly why I don't like it. In my experience, lack of understanding bites you way harder than lack of a single fence.
I once worked at a company that had a very complicated patented (!) algorithm to calculate a certain value. Not a single person in the company knew why it was so complicated, and nobody ever questioned it. We would constantly struggle to introduce new rules to it, because they would conflict with the old rules, and it wasn't clear how to resolve those conflicts.
Since we didn't understand what value those magical rules provided, there was absolutely no way we could resolve conflicts in a way that retains the original value (if there was any).
Eventually I was able to convince everyone and just removed all the rules we didn't understand. Everyone sighed with a relief.
In hindsight, I believe the sole reason algorithm was so complicated was that having a patented algorithm would sound more sexy to investors, and you can't patent something stupidly simple.
Throwaway commenting often makes people feel as if they’re adding value, whilst fulfilling their obligations.
Of course such comments have no value and worse, can distract from what ought to be commented.
Perhaps ChatGPT has found a use, if it is asked to add comments to code, although I somehow doubt it…
> One should take care not to overestimate the impact of language on defects. While the observed relationships are statistically significant, the effects are quite small. Analysis of deviance reveals that language accounts for less than 1% of the total explained deviance
For my code? I agree
Code for others to participate in? The simplest possible way for the greatest number of developers to understand as quickly as possible. Not about my best practice or preference but for the greater good.
Coding standards for the elite devs are only so effective at growing that growing quick enough.
Comments are a critical way to more quickly re-grok the mental model of what's going on for your future self as well.
I think there was a post in the past few weeks about a single developer who maintained hundreds of his own tools, and for him it came down to process and documentation first so it was easy to come back to months or years later.
Many functions in the standard library behave subtly differently from there documentation or have behaviour that is not documented but depended on by applications, and I’ve certainly seen lots of concurrency bugs in both code and tests because the GVL makes it hard to provoke the worst case behaviour.
The unit tests are really useful for Ruby language implementations because they help give us confidence we’re replicating all the required behaviour, but from that point of view I wish the underlying things were better specified so those tests weren’t quite so necessary.
Don’t get me wrong. I love Ruby as a language and loved working on TruffleRuby, but I don’t think the community should be too smug about code quality and testing.
The python folks before me used this to avoid writing docstrings for modules/classes/methods, so code could only be understood by reading the entirety of it. Throw in some deep class hierarchies and it was very hard to onboard there.
If you're relying on comments to help with that, you'll have to share the same mindset as the person writing the comments, except there's probably multiple years of understanding gap between you and them.
if (theWhy()){ theWhat() }
In the simplest cases, sure you don’t need to write “getName returns a user’s first name and last name separated by a space character,” but I’m guessing the method requestPurchase will have a lot of nuance and I hope it’s documented (yes, even the “what happens”)
This would be actually a quite interesting comment as it indicates that the implementation of `getName` is buggy in regard to internalization.
Here's the classic post about this topic:
https://www.kalzumeus.com/2010/06/17/falsehoods-programmers-...
# this is going to loop 4x and call foo_bar on the 4th time because when you calculate this number it needs the 4th time to calculate the difference from the sales tax. weird, I know, but the business has special rules about how taxes work in California # Call foo_bar only on the 4th loop iteration to handle the weirdness of calculating taxes for California.
(I've just joined a company where everyone's constantly writing giant docs, and no one seems to grok the idea of a "living doc" that gets edited and refined. I think it's slowly making me allergic to verbosity.)# Call foo_bar only on the 4th loop iteration to handle the weirdness of calculating taxes for California
# Call foo_bar only on the 4th iteration because in California widget tax # (1st iteration) doesn't apply at all, foo tax (2nd iter.) only applies # for B2B transactions (this is not one), bar tax (3rd iter.) only applies # for alcohol and this subsystem is not called for alcohol sales. But VAT # (4th iteration) does apply.
for i in 0..<4 {
if i == 3 {
foo()
}
else {
foo_bar()
}
}
}I'm not sure I've seen all the "comment everything" advocates in this thread provide a single example of a good comment.
I think there's nearly always value to be added:
* Explaining required fields, if null/blank/0 is allowed, where an ID comes from (db vs app-generated), if string values are formatted or require formatting (credit card, phone numbers), max length or other restrictions
* If a class/method is thread-safe or not (when not obvious and misuse is dangerous), error conditions, timeouts.
* Any external or indirect dependencies for use (config, packages, etc)
* Links to other docs/wikis or tickets is hugely useful.
When you're writing/working on the code you already know all this stuff, and it takes only a couple minutes to document. When someone else (or you, 6 months later) comes along to use or modify it, figuring everything out from scratch can take hours -- or worse, bug reports from QA or customers. Docs shave this down to seconds and directly avoid bugs.
The other huge benefit I often experience is through trying to write docs for something I realize there's a better, more obvious name that makes it easier to use and requires less explanation (less docs). This happens on easily 5-10% of the things I write docs for.
For instance, this [1] is a clean implementation of quicksort, which I offer as an example of any non-trivial algorithm. You can't really write it in a way that would make the idea clear to anybody who wasn't already familiar with the algorithm, because the idea itself is non-trivial. So the way intent is made clear and documented is by making sure the function is called QuickSort. And that is indeed 'self documenting', but really in a way that has nothing to do with the code itself.
[1] - https://www.w3resource.com/csharp-exercises/searching-and-so...
Other times to comment include when there is some sort of dirty hack, TODO annotations, etc.
I'm honestly a bit torn by it. Yes, your code absolutely should be written in a way that keeps it tidy and easy to understand. But you've always got complex situations which arent always going to be easy or obvious for someone fresh to the codebase.
There should be a good middle ground. I dont need to see comments saying "this is a loop that gets all the users". If its got a variables called users, calling a methog called "getUsers()" then thats pretty damn obvious whats happening.
However if you then go on to do something weird like loop over each user and calculate a score based on the number of posts they've made then theres undoubtedly going to be some logic in there that even just a simple one sentence comment will help someone understand.
It's a fine line, and getting it right is a skill in itself.
Obviously, unclear code without comments is better then unclear code with comments.
I worked with some Rails folks a while back who
were utterly convinced that comments were to be
avoided because it meant your code was not clear.
One of the few things that makes me want to reach a management position is my burning desire to alter this widespread, toxic, and absolutely bizarre belief.As an IC, even a senior IC, it's difficult to effect this change.
Comment bit rot is inevitable, because comments don’t compile and can’t be tested. The only way to keep them in sync is by hand, which takes a lot of time and energy and is far from perfect. Of course,
> The first problem is that most developers are under great time pressure and don’t have the time to make the code so utterly clear that it requires no further comment.
So they don’t have time to write the code clearly, but they somehow magically have time to read and review all the comments and to keep them in sync with the code? And the reviewers too?
“If only developers worked harder…”. It’s nonsense.
Comments are great, they have an important place in software engineering, and I always regret when I forget to write some in a file or class. But they are not a silver bullet, and must be treated with suspicion, because there is no way to prove if they actually describe what’s going on. And that’s the same reason that they are hard to keep in sync.
If there have been major structural changes that make the comment useless- that’d be pretty easy to see, it’s very easy to delete comments
I'd argue you could do the same on methods and class you want more context on, removing the need for the majority of comments, and most companies will have the associated ticket numbers or design discussions attached to the MR/PR.
I think there will still be rare situations where comments are absolutely needed, but in these rare cases they should probably refer to an external resource (a bug report for a specific library, an incident that required a specific fix, etc.)
I don't want to write a comment, I'd rather write clean code that looks good, but when I run out of time to spend on a problem, and I don't think the code is clear enough, I think then it's acceptable to add a comment.
I just think too many devs have their egos wrapped up into their jobs, so hearing, "Commenting is failure!" evokes an emotional response. What these devs don't realize is you can make no mistakes and still "fail" to write clean code, and that's totally okay.
Uncle Bob is just saying that pulling out a comment before you've tried is premature. Try to avoid it first, if you have time to.
Exactly. I used to love writing comments, but they have become for me a last resort. I'd rather put the information I'm trying to convey almost anywhere else. Variable names, method names, improved interfaces, better object relationships, doc strings, test code, test names, commit comments, or my colleagues' heads.
Though I fully admit that automated tests cover nothing related to explanations / things that aren't inherently true or false.
Personally I've wanted a way to link code to comments, not just the reverse, so I can change code here and be notified that it affects comments over there, especially during review time (just show every related comment next to the change). It seems literally essential for reliable documentation, but I haven't yet seen it except maybe in WEB (the literate programming language) or similar.
but ... it's the explanations that are important.
I mean there are plenty of tools to check that a comment matches a function signature or otherwise describes the properties of a bit of code. But who needs that? At least in a strongly typed language, reproducing the signature or doing anything else that reflects existing code within a comment adds very little.
Anyway, I am not arguing against comments. I'm just arguing that they can't somehow magically reduce technical debt. Or that they have anything at all to do with technical debt. Or that the OP made any sense at all.
Often, yes! But you can also sometimes mechanically detect when what you're claiming might no longer be true, even if you can't assert the full content. E.g. "X does Y when you Z, so you should QWERTY periodically" -> check X,Y,Z in a slightly relevant way. Maybe have an example QWERTY call that does nothing but compile.
If a check like that fails, it means something has changed, which is an ideal time to check that documentation again. If it's not relevant, just fix the test. If it is, it shows why these systems are valuable.
(Yes, it's a change-detector test, which everyone hates for good reasons. They work great for things that are important but can't be sufficiently tested though, because the alternative is no automation at all)
Plus, the content that's truly hardest to check this way (high level conceptual docs, etc) is also generally the least likely to change in a meaningful way.
Maybe it’s because I’m old and stupid, but I think that simplicity, efficiency and correctness are virtues, and I find it difficult to see how this qualifies.
With enough interactions, and in the right areas, extra effort can pay for itself pretty quickly.
If your code is separated from comments explaining it so much thag this isn't visibly obvious on review, there’s probabky a bigger problem than “I don’t have a way to link commebts to distant code and vice versa.”
And fairly often that's significantly more useful information, or in a much more useful format, than the documentation of X on its own.
Not true in Rust
He has been trying to say profound things for a long time now. He was super active in the XP community in early 2k onwards and he was nearly always saying things that I felt were a bit "off". i.e. there was a gem of an idea, but the idea was turned into some principle or rule that lacked nuance and context. Reality is, there isn't any fundamental rules/principles... just ideas, some ideas seem more universal than others, but these ideas are just a bunch of strategies you can use when approaching software development and depending on context they may or may not be good strategies.
In terms of commenting, some of this weird "wisdom" around commenting was fundamentally rooted in the idea you can't fix bad code with comments. People noticed that a lot of times where there was comments in "poor" code it actually was a spot where you could do some kind of refactoring to make the code clearer. Eventually this morphed into "If you need to comment your code you have failed" type sayings. However, there was plenty of people advocating commenting to explain things the code can't tell you, but too many were swayed by "commenting is failure to write good code" that they threw out some of the reason why people like to put comments in. Many in their first 10 years of coding really want guidelines and rules and principles and argue strongly for things they have found effective compared to how they approached coding previously. But these things you learn are almost never universal, even if you can see/argue how you could apply it to all kinds of things, other approaches might actually work better, or might work better in different contexts.
One of such things is "screaming architecture". It is a good idea in theory, but only if you already know what the architecture should be. Most new projects don't know what they need up front, and discovery happens over time. Screaming architecture is bad for this process. It inhibits it, requiring a ton of refactoring because of early assumptions. One thing that is known up front is entry points. (CLI, requests, tests, bg jobs). They're a lot more likely to stay around forever. Custom architecture should emerge underneath them. I guess we can call it whispering architecture.
1. An odd business requirement (share the origin story)
2. It took research (summarize with links)
3. Multiple options were considered (justify decision)
4. Question in a code review (answer in a comment)
E.g. if the ide can't grok what a $var is you can do :
/** @var Some\Namespace\To\Class $var */
$var = ...
then when it reindexes things it has no problem tying everything together.Code is writing, would you write a technical book without sections and chapters?
For instance, it's great that code reviews have become standard practice at most organizations and for many projects, but the tooling for those reviews almost always rely on showing the few lines above and below a code diff. The reviewer has no convenient way of seeing how the changed code may conflict with any applicable comments unless the comments happen to be within those few nearby lines or the diff happens to include comment changes. Even then, the big picture is out of view and rot is still likely to seep in.
It would be nice if incoming developer-support AI could start tackling this, by surfacing impacted comments and even "linting" them for applicability and accuracy.
Documentation tooling should be able to make a good job of constructing a class/function DAG with scoped commentary. This is kind of a reversal of Literal documentation, but I suspect it may be more maintainable by teams.
Literal docs only seem to go in one direction, that is documentation->code, not the other way around. This I guess is more in-line with scientific hypotheses. Literal tests may be even more tricky as TDD doesn't gel well with Literal hypotheses.
I guess a Doc-driven dev process would be a novel approach here, and probably more usable than AI-supported systems. Copilot has been quite divisive on it's effectiveness.
DDD in that every eg. Class requires a comment and a test even if they are blank, to force at least a thought about them. Having a code manifest at the root of a repo can also be used to configure the envs the code runs in, and the integration tests that it needs to do both local and in-place.
Lastly, as mentioned elsewhere, logs are comments as well, and again would be well to be scoped in the language.
The other thing I wanted to mention: People don't do code review in their IDEs? Really?
Modern languages with type inference are not fun to analyze without an IDE… Also you can't navigate to related code without IDE features. Just looking at a diff can be very misleading!
I only recently started working in a big team again and when I'm doing Github code reviews I often find myself checking out the branch locally and reading the file in my IDE and then going back to the Github interface to write my review comments.
Not only is this often the only way to understand the context of a change but it also makes it much easier to spot refactoring opportunities. But it's cumbersome and slow.
That only applies to comments that address what the code is doing or how it does what the comment says. It does absolutely nothing for the most critical type of comments: the ones that say why the developer decided to do it a particular way. Maybe they tried it three other ways and this was the most efficient way. Maybe they chose this way because it matches up with a business requirement that things be done in a particular order (regardless of efficiency). Maybe it must be done that way for consistency with another part of the system that is only obvious from the comment.
It will be a long, long time before AI will be able to reasonably vet such comments for accuracy. Until then, comment your darn code!
6 months later I wont remember why the "easy" solution wasn't the path that was taken, or some complexity that needed special handling in a single case that was discovered through a few hours of debugging.
Sure you could write perfect code, but writing out your thought process helps tremendously with understanding a thought process and getting up to speed far faster.
My guiding principle is that I don't want someone to read my code years later, exclaim "Who the hell is this alyandon guy?!?!" and be motivated enough to create a time machine so they can go back in time and smash my keyboard to bits before I wrote said code.
Someone working on the code should know the language. If they stumble over something they don't know they should read the documentation of the language. Explaining the programming language you use in code comments is a terrible idea, imho. It's like writing comments of the form "adding the numbers" and than adding some numbers. Just useless noise.
The more important question would be, as always, why you used this feature? What would be e.g. the alternatives?
Just stating that you do something, just to do it than with code makes no sense. Nobody needs that redundancy.
If there are good reasons WHY this is still the best way to do things, this WHY should be explained.
But, of course, not the how. It's self evident that some "special" functionality was used.
If you read some scientific paper you would also not expect to find there basic explanations of the scientific topic. To read and understand a paper you need to know the subject.
The same goes for code: You need to know your tools. Otherwise you can't use them properly anyway.
Language documentation just does not belong in random code comments. The comments should be there to explain your special use case, not give some basic tutorial to people that don't know the tool used in the first place. That are completely different concerns, and should not be mixed therefore.
It is difficult for me to understand why the debate surrounding code comments is so heated. I had some strong opinions about these things when I was very new to engineering but I rarely see anyone senior doubt the effectiveness of code comments. I get the idea of self-documenting code, but very few things are self-documenting to a new person on the team that never worked with your massive proprietary codebase. They need a lot more context.
I would like to see some examples of self-documenting codebases. Sadly, people like Uncle Bob who loudly hate code comments tend to have codebases that are not very self-documenting. Perhaps not writing any code comments is an interesting exercise, but I think it might work much better in small siloed projects than in companies where hundreds of people have to collaborate on the same code and not introduce defects. I wonder if this is where the disagreement about things like code comments comes from - different circumstances of the programmers.
It's an interesting exercise very similar to the infamous Perl one-liners from the 2000s.
>but I think it might work much better in small siloed projects
The problem here is that those "small, siloed" projects frequently get out of their silos and become bigger and more important than originally envisioned. Then all the new people looking at it have no idea what it's doing.
Shouldn't that be expressed in a test? To me, "there's a special case that drives the code in a particular direction" is Exhibit A for "things that belong in tests".
As a kid, I somehow got the impression that Microsoft had a coding standard for 1:1 comments to code. So I thought I'd give it a try. (I had a lot of free time.)
For the 1.x to 2.x version bump of my text editor, I meticulously went thru and commented everything. (I also switched to 1 statement per line guideline.)
The outcome was awesome. By requiring a comment, any comment, for every statement, it evolved into a form of story telling. I wasn't just explaining obvious stuff. It helped tremendously with future maintenance.
Alas, I've never repeated that experience. I'm not entirely sure why.
It's a bit like Knuth style literate programming or TDD. Some kind of Platonic ideal. An esthetic ideal to strive for, but not very practical.
Comments aren’t milk, they don’t just go off, developers let them go out of date.
As others have said, comments should be used to add why, to give context.
They need to if the the way it works is significant. If it is not significant then the value of a comment becomes somewhat dubious anyway as the code is expendable and doesn't really matter. It is not necessary to understand the program and if it is flawed you're going to rewrite it. Comments can add a lot of value, but there is a line where the value quickly diminishes.
And no matter how clear and clean you write algorithm A, the code will never answer the question why this algo and not another was used.
That's the meaning of why here.
If the observation of a unit prompted a need for a specific algorithm – to reduce time complexity, for example – then you have something quite testable to document the choice, so it’s not clear what you are asserting.
How does a unit test distinguish different algorithm (with of course same big-O characteristics, as obviously otherwise this example would not make any sense in the first place)?
If two algorithms are functionally identical (same results, same space/time complexity, etc.), who cares why? What are you going to gain from knowing more about the choice?
I'll give an example. Let's say you need to add 1 to each integer in an array. You could use a for loop, a map function, etc. We'll assume the compiler optimizes each choice to the exact same machine code. What would you like to have documented about the choice?
I'm getting the impression, like it was stated by some people here, that this whole "no comments" / "everything should be a unit test" idea comes form inexperienced but idealistic developers mostly.
People with more experience seem to know already OTOH that good comments can save your ass in the middle of the night.
Nothing in this thread says "no comments" or "everything should be a unit test". But the reality is that most code doesn't matter. It is just a means to an end and if it no longer serves that means it's expendable. Explaining why something was chosen doesn't tell you anything meaningful most of the time. In fact, I expect the "why" 99% of the time is "I felt like it and it worked".
When a specific approach is essential in meeting certain application requirements, absolutely you need to comment that. But you also need tests, else how are you going to ensure that you stay within those requirements? Of an application of any meaningful size, you're going to have a hard time manually ensuring that some externality didn't break your assumption on every deploy. Even if it weren't hard, why put in the man hours when a machine can do it for you?
Erm, we're talking about professional software development here.
What someone is tinkering together in his hobby cellar is of no interest to me.
Code created by the principle "I felt like that" is garbage by definition. It makes no sense to even discuss such stuff.
> When a specific approach is essential in meeting certain application requirements, absolutely you need to comment that. But you also need tests, else how are you going to ensure that you stay within those requirements? Of an application of any meaningful size, you're going to have a hard time manually ensuring that some externality didn't break your assumption on every deploy. Even if it weren't hard, why put in the man hours when a machine can do it for you?
Here I actually agree fully.
What can be tested by the machine should be.
That's for example a reason to use statically languages, as in contrast to such thing as Ruby, the machine can give much better correctness guaranties with static type checking.
But the point is: Not everything can be expressed as meaningful test.
For example you proposed something that would result in a flaky test case…
Some other things can't be expressed as test either. And the experience shows that's this things are almost always related to the why question. In the end you put exactly this question front while discussing some imaginary implementation of something, which shows my point nicely. :-)
I think you are vastly overestimating not only how much people do work rationally, but how much it's even possible. E.g., System 2 thinking is just much more expensive. And programmers usually work in environments that are pretty data-poor with respect to important factors. And that's before we even get to both project-level and individual path-dependence.
As a person with "more" experience, I went through a phase of writing lots of comments. Obviously, given how much I comment here, I like writing. But as I said elsewhere in this discussion, comments have become for me a last resort. I'd rather put the information I'm trying to convey almost anywhere else. Variable names, method names, improved interfaces, better object relationships, doc strings, test code, test names, commit comments, or my colleagues' heads.
Furthermore, if that 5% optimization is truly critical to the application (despite not being measurable?), how are you going to ensure that some future change doesn't break that? Something as simple as a compiler update could change some optimization that breaks your assumptions. What do you do in the absence of tests to ensure that doesn't slip through?
> 5% difference in a tightly controlled environment,
A test suite usually doesn't run in tightly controlled environment. To get meaningful performance testing results you'll need to run it on dedicated hardware (no noisy neighbors) and don't run different tests in parallel (so one test will not be a noisy neighbor for another test). It is something not hard to do once in a while manually but would be quite expensive to do as part of a test suite which typically is running on each change.
Users won't notice, but they will notice...?
> A test suite usually doesn't run in tightly controlled environment.
What don't you have control over?
> but not significant enough to spend days to avoid adding a few lines of comments by embedding all knowledge into tests
Why would you avoid comments? Why would your tests have to take longer to write than your comments? Days to write a test or two to clarify your intent?
On the other hand, if it's performance critical code in a way that's important to the project, then running a manual benchmark once and hoping that nobody accidentally breaks it strikes me as poor practice.
Where is this—possibly wrong—assumption documented? Or do you think it makes no sense to document random assumptions, which may or may not hold in the future?
Another simple example: Almost all usable sorting algorithm have the same space / time complexity on paper. But as everybody knows they behave quite different in reality (otherwise we wouldn't have so many of them to choose form). Do you really think it makes no sense to document such design choice where it matters?
Also in this case unit tests won't help you. (But you given up already on this line of argumentation anyway, I see ;-))
Presumably in the compiler documentation. Although the assumption was made merely to ensure that we understood that each algorithm choice was functionally equivalent, to continue in the theme of discussion.
> which may or may not hold in the future?
Totally fair. Let's say your choice, which was fine at the time of choosing, with a later compiler update does get optimized in a new way that that longer satisfy your application's requirements. How do you plan to keep up with that if you don't have automated tests to prove whether or not your code still operates within your expectations?
> But you given up already on this line of argumentation anyway, I see ;-)
No, but I was still working on getting a concrete example in which we can build a test or two for to provide a demonstration. Unfortunately, the vague sorting suggestion still isn't concrete. What are you sorting? Which algorithm did you choose and why? I had hoped that if I rephrased the question you would feel more comfortable coming out of your shell, but I can see your worry remains. Back in my day education was something to get excited about so I struggle to understand, but recognizing your uncomfortableness now I'll not needle you further and apologize for not seeing it sooner.
> How does a test inform you why a function was implemented using algorithm A and not algorithm B which would also do the same?
You made up than a straw man saying something something that you assume that both algos get optimized to the same machine code. Which is completely irrelevant to the actual question.
I've only mentioned that both algos need to have the same big-O characteristic obviously as otherwise they wouldn't be interchangeable in the first place.
> What are you sorting? Which algorithm did you choose and why?
LOL, that's exactly the question a good code comments should answer.
Because code can't do that!
The example here is: Big-O is one thing, but "what are you sorting" matters, and some algo may be better suited for the task than the other.
If this isn't obvious it needs to be documented.
The best place to do that is right where the code is. As only this will make sure it will be read together with the code. (Otherwise someone could for example rewrite the code to something "more standard" and it's not a given that the people reviewing the change would know about the reasoning behind the original implementation; a comment would have prevented bugs and regressions in such a case).
Thanks for proving my point… :-)
We preach endlessly the idea of orthogonality and abstraction, but then we smash together plain English and Python/C++/Erlang/whatever?
We agree code should be split into multiple files, why do we suddenly not agree that English should be split as well? Nobody would try to write a file with 30% JS, 50% C++, and 20% Python.
> if it's a "why" doc, it shouldn't be specific to the code
Sometimes the "why" is directly connected to that specific part of the code and doesn't concern anything else, or anyone not working on that part of the code. Separating & moving the explanation to another place just makes it less visible exactly where it matters.
Comments should be less visible, as they distract the coder from understanding what the code actually does with potential lies about what the code ought to do, according to the flawed human who wrote the code.
Put the comments elsewhere. We don't put all our code in one file to solve "it needs to be visible!" problems, we shouldn't do it with our docs either, it is not consistent nor is it helpful.
In fact, there may be cases where the comment is correct (i.e. it describes what the code should do) but the code is wrong and doesn't actually do it correctly. Why should the comments take a back seat in that case?
In reality, comments and code are part of the whole system. There's nothing wrong with being suspicious of a comment's accuracy, but that doesn't mean comments aren't helpful. Part of development is keeping code and comments in sync. Yes, programming is hard.
As the code is, definitionally, the way the program works, it must be correct, necessarily. This is not true of the comments.
This is why comments are dangerous and bad, only to be used when you've run out of time and/or aren't smart enough to figure a problem out (happens to everyone).
In any case, even if the code is perfectly correct, comments can and should be used to describe why certain decisions were made, when they are not otherwise obvious from looking at the code. E.g. "You might think a bitfield would be more efficient for storing this data but we choose an array of long ints because in the near future we plan to update the code to pass this as an argument to foo() which assumes an array of long ints."
Comments are not limited to instances when you run out of time or are not smart enough to figure out a problem. The whole idea of comments is to save a future developer from the headache of figuring out the things you're writing comments about.
You make comparisons without considering the reasons. We split code up into multiple files because we cannot have 100% of the code on screen either way and huge files tend to be cumbersome. Whole IDE components are built just to show API docs and other parts of the code exactly where and when we need them. With that in mind it makes no sense to have important comments not be visible where and when we need them.
And even if those comments were in a separate file like you suggest you'd still need a comment in the code to make developers aware of the fact an important explanation of some obscure detail exists. If you don't then any change of that code might invalidate the documentation without anyone knowing, and then you're back at square one with lying comments/docs. Comment visibility also means it's visible when it needs to be updated.
There’s simply no need for inline comments anymore, and continuing to use them is admitting you’re not putting the kind of effort you’re capable of into building software.
Not sure why this was flagged...
Except being exactly where and when it's needed, with any modern editor being able to hide it for people who don't want it.
You seem to base everything on the assumption that comments are always the worst choice, and that people don't behave like people but always document things the right way no matter how cumbersome or complex that is compared to the obvious way. Seeing things in black and white is usually not the best solution.
> continuing to use them is admitting you’re not putting the kind of effort you’re capable of into building software.
No, and I hope that kind of thinking won't mislead you into believing you are at your peak because you don't write comments.
And all I’ve said is comments are a last resort. Nothing black/white about that, just tired of egos getting in the way of seeing how there are a million ways in practice to avoid comments that people who “like” comments refuse to learn about.
Besides, if you foster a culture of writing "why" docs, the problem of where to place these docs is one you solved early on, so people will know where to go.
Discoverability and context would not be nearly as useful, to start. Why you need to ask the question, as if there is no suitable answer, is suspect of a thoughtless conclusion.
In the late 80s, there was an idea floated that every file could have a sister file with comments, such that they would not need to be parsed/discarded by a parser. This would aid in generating documentation, among other tooling. When I was starting out, I expected this to take hold, but it never did.
> There are so many better ways to document design and implementation decisions that don't involve embedding English into source code files
I don't think that's been demonstrated.
This sounds a lot like the director's commentary tracks on DVDs. No one ever watched those, and the sister-comment-file would flop the same way if anyone really tried it. A separate file is fine for documenting overall design, but for detailing sections of code, the commentary needs to be close to it, where people will see it.
Not if it was integrated with an IDE such that you could expand it shrug
A simple comment every "paragraph" of code or so helps me narrow down the amount of code I need to mentally parse to get to the part that's actually relevant to what I'm trying to do.
So since we're supposed to be on the same team, explicitly saying "go fuck yourself, load a mental model of the entire codebase to find the part that's relevant to your task, I'm not going to help you" does indeed seem insane and crazy.
You see a function called, "getCustomer" you shouldn't have to dive into that function to understand what you're getting back. It's a customer, no need to figure out how it got the customer or what the format is, etc.
Whether or not you realize it, you've gotten to the point of arguing against a lot of really common and proven out design concepts (abstraction layers, orthogonality and the LoD, data types, etc.) without even realizing.
"How can I know how the program works without comments unless I load the entire thing into my brain all at once?" is not a question you ask if you understand these principles, because you know you won't need to.
"...team leads (and managers) allow comments to get out of sync with the code..."
reveal a fundamental misunderstanding of how software organizations generally work.
My personal solution has been to approach code documentation as programming in one’s native language, or as is often done, in English. Learning to comment is given the same importance as learning to code. Comment maintenance is given the same priority as code maintenance. Explaining the actual function and expectations by comment is the essential part of writing code that expresses the functionality.
Comments are given similar weight as code. Comment design is considered at an early stage. And comment maintenance is equally as important as code maintenance.
Why do we talk about coding rockstars but don’t we talk about commenting rockstars? This isn’t anti-agile or anti any methodology if it’s presented as an integral and essential part of the task.
Often, when mentoring such processes, the act of commenting liberates insights that may have only appeared during failed product testing.
Of course, learning to comment effectively is learning to communicate effectively. Metrics for effectiveness are often elusive and people are rarely paid for lines-of-comments, so this is always a hard sell, unless it’s understandable to be a core coding activity.
We see the same thing in related areas, like logging. Unless you need to solve a problem with the help of accurate logging data, you don’t see the need or utility of logging anything. As with comments and code, logging also needs consideration and maintenance.
Learn to code Learn to comment Learn to log
These mantra won’t come from above, so need to be learned and understood.
User manuals used to be pretty extensive, and filled with information not just on how the devices work, how they should be maintained, but also on what mindset these devices were built and the general context.
For instance I remember buying a vintage camera with the original manual, and it basically explained photography to beginners, including framing the subject, lighting, and shutter discipline.
Nowadays a smartphone comes with 2 pages of instructions on how to start the device.
Are we much worse because of that ? I'm not sure, something has been lost, but I also can't imagine a smartphone coming with 200 pages of explanations and addenda sent by mail on every OS revision.
A code that is regularly evolving in significant ways is to me way closer to a smartphone than a vintage camera.
Regular comments are subject to bit rot - they get less true with time. Unless actively maintained - eventually all comments lie.
Git commit messages maintain themselves. If a line of code was changed - the git blame annotation will change. So you know exactly what the context was and exactly which lines the comment relates to. It provides context (you can see in the commit what else changed with it), and if you include the JIRA task number and a short description - it provides the WHY.
IMHO the most important skill for writing understandable code is splitting the commits into sensible pieces and writing good commit messages.
I always check git blame before committing a new code, because I've had this exact experience several times:
- investigate a bug
- find the responsible line with obviously wrong code (often it's even nicely commented and the comments and the code are contradictory)
- fix the obviously wrong code
- commit
- 10 other bugs caused by your fix
- git blame
- turns out the "obviously wrong" line was there on purpose and your fix effectively removed a previous change
- which you would know if you checked the git blame for that line
- comments were lying because somebody did a refactor and didn't noticed 4 lines above there's a whole paragraph of what now became lies
This is Chesterton's Fence rule of programming. Before you change a line of code - be sure to understand why it was there. Git blame is the best tool for that.BTW there's a similar rule for comments - when you change a line of code in some function - you have to check all the callers of that function (and their callers, etc.) to see if there were any comments near the callers talking about the part that you changed. THAT is the thing that nobody does in practice, and THAT's the reason why comments eventually lie.
I can see you getProductCollection, I know what that does, but why do you do nothing with it? Oh it's because it needs to be loaded before presenting the cart, and there's a bug in the framework that fails to do so in this scenario.
Also business requirements can be reaaally asinine, a makeThisParticularButtonGreenSeeMeetingNotes20122023() would be pretty lame but that is often required information for a developer revisiting a feature and wondering if something was a bug or intended.
Stop being so dogmatic about comments and do what works for your team.
Such a flame war territory.
Sometimes things are just complicated and they require explaining the intent to help the reader understand the code. It also helps spot bugs or allows someone smarter than me to rewrite it in a better way (for different axes of better)
There are other situations where comments are useful that are covered elsewhere in the thread, too.
So, I've gotten some good ideas on how to improve my code comment etiquette!
First, the code needs to be fairly clear, but not "stupid" clear. I have had people tell me not to use idiomatic Swift, because "a JavaScript programmer can't understand it."
In some cases, this may be necessary, but not in mine.
The #1 consumer of my code, is Yours Truly. The wonkiness doesn't bother me, but sometimes, I may not be aware of why I did something (that may not be "idiomatic," at all).
That's why I may write a quick comment, like so:
showThrobber()
// The reason for this, is that we need to give the throbber time to show up.
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + DispatchTimeInterval.milliseconds(20)) {
That explains the awkward use of an "asyncAfter()" method.It was the result of me, wasting a good half hour, trying to figure out why the screen didn't change. I saved future me, a half hour (and also a signpost for "improvements needed").
I write about my approach to documentation, here: https://littlegreenviper.com/miscellany/leaving-a-legacy/
When reading this I didn't understand the comment at first, before I realized that it's meant to say something about the following line.
It would be better therefore to write it like:
showThrobber()
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + DispatchTimeInterval.milliseconds(20)) {
// The reason for this, is that we need to give the throbber time to show up.Thanks!
Thanks!
So maybe like so:
showThrobber()
// The reason for the asyncAfter(), is that we need to give the throbber time to show up.
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + DispatchTimeInterval.milliseconds(20)) {
I tend to like to put comments to the right of the lines, but not if they are long ones.I don’t usually like to put stuff just under opening braces, because I feel that it can sometimes obscure the fact that a new context was opened.
Indentation is important. Back when I programmed C++, I used Whitesmiths indentation, but I changed to K&R, when I started writing Swift. With Whitesmiths, you can put a long comment, just above the context opening, and the comment can apply to just the context, and not the opening statement. This established a habit of having comments apply to the line below.
Here's an example of the same kind of thing, in another part of the same codebase:
if userFallbackRaw == (inError! as NSError).code { // Fallback means that we will use the password, so we nuke the stored password.
#if DEBUG
print("Biometric fallback.")
#endif
// Wow. This is one hell of a kludge, but it works.
// There's a "feature" in iOS, where the Touch/FaceID callback is triggered out of sync with the main queue (slightly before the next run cycle, I guess).
// If we immediately set the password field as first responder in this callback, then it gets selected, but the keyboard doesn't come up.
// This 'orrible, 'orrible hack tells iOS to select the field after the handler for this Touch/FaceID has had time to wrap up.
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + DispatchTimeInterval.milliseconds(20)) {
self._bioHazard = true
self._selectedPassword = ""
self.emailAddressTextField?.text = self._selectedLogin
self.passwordTextField?.text = ""
self.isThrobberShown = false
self.passwordTextField?.becomeFirstResponder()
}Oh, an "argument" on the base of "We have always done it that way". So we don't have even an argument here.
And no, this nonsensical "convention" is not everywhere followed as people realized that code should be written in the most readable way possible.
I know a lot of human langues that are read form top to bottom. I don't know even one where you read bottom to top…
Jumping around mentality in code is a sure way to make the code hard to understand. Ever heard the reason behind why `goto` is considered bad?
Ever seen Python doc-strings?
Did you write your comment under my comment or did you write it above? Why is this so?
Also writing comments above leads very often to the kind of comments that describe what the following code does. Which is the most wrong type of comments, like it was said here not only once.
Comments below lead OTOH naturally to comments that describe why the code was written like it was written.
There may be exceptions for the rule and cases where it make sense to have something like a "heading" comment. But this cases are very rare.
If you actually think about it almost all (good!) comments make much more sense below the code that is commented as this is the natural way how to write. Just look how this site here is structured. And it's all about comments!
Bottom line: Use your own brain! Don't do things because someone told you "We have always done it that way"!
int strlen( char * s );
the following comment pretty much describes what it does:
- if passed a null-terminated string, returns the number of characters in the string, excluding the terminator
- if passed a null pointer, or an incorrectly terminated string, behaviour is undefined
these are the kind of comments i like to see
Comments are vital, but I prefer everything be refactored to make the code the comments, which only happens if you get naming right, the language, libraries and the frameworks don't fight you. Which is a lot of ifs. Even then you need the comments to label parts of code that are exceptions to normal practice, or to fix particularly subtle bugs so that you prevent regressions from happening. (If you want tests to do that, it doesn't obviate the need for comments - you probably want the comments in the code and the test, because you don't want it to be standard practice when you are editing code to discover a new all the failing test cases when you make a change)
The data they cite on TODO items isn’t relevant as the experiment lacks any controls and is thus non-scientific.
The best we can do given the dearth of data is consult the market for answers. There are successful software companies/projects/individuals that subscribe to either philosophy (sometimes simultaneously) and the market doesn’t seem to care as it does about how good the product actually is. Stuff like this is bike shedding at best, at worst it’s a kind of virtue signaling to some group in an attempt to appear as a blessed expert.
DatabaseConnection connnection; // Connection to the database.
// Write a log line when the system is intialized logger.info("The system was initialized successfully.");
When I see such comments I am severely tempted to conclude that if one is going to have a policy on comments forbidding them would do less harm then mandating them everywhere.
1. if it is important to explain WHY something is done in a way it is done
2. if there is some related or directly connected code far away that the person might miss or cannot know about and how this code influences it. Writing self-explanatory code nowadays is a standard. An era of newbie spaghetti code is long gone so no need to explain the code itself.
The team ended up expanding the codebase quite a bit before that technology stack was retired a couple years later. Not sure if it would have survived without that refactoring.
So? Good comments are valuable, even if they aren't always kept absolutely consistent with the code. Comments shouldn't restate what the code says, they should either say things the code can't say (like why), or (sometimes) summarize what the code does at a different level detail to make it easier to understand.
The trick is to read code and comments together, and dig into source history when something seems off.
The code can have comments or not, it's more of a preference.
Of course, it is impossible to infer from the code why something was done so this will always be needed.
I suspect they drag down engineers, and cause them to refactor, or burn out.
But what if something like chatgpt could explain the code to you. If you could ask questions
"does anyone call this function?"
"who calls it, and what do they do with the results?"
"can you call it a million times, fuzz the inputs and see if it crashes?"
"can you replace the bubble sort with qsort?"
there are also places where you might want to explain the “why” even if the code is clear.
relying on comments to understand the “how” has been a smell in every codebase i’ve seen.
* Comments are excuses
* They're used to validate the existence of crappy code
* They do nothing for you in production
Instead:
* we commit to writing log messages... which are sort of like comments, but they work in production
So-called "level of intent" comments as well as comments highlighting tradeoffs, gotchas, flaws, limits, exceptions, assumptions, and so on, are incredibly valuable if you preserve them alongside the code. Comments explaining why this function exists and what it's for can help you quickly come up to speed on a new code base - this is especially helpful when it comes to handing off code to a new owner or expanding the team of owners. The following code may or may not be well written (who can say??) but it's not exactly inviting new contributors: https://github.com/FFmpeg/FFmpeg/blob/master/libavcodec/moti...
Around the time of writing the code, comment-free code looks clear to the author because they have the benefit of all of the thinking that went into writing the code.
I'd argue that in production is when comments are often most valuable. The middle of a crisis is a terrible time to wonder what assumptions were made when writing code a specific way, or if a certain line of code that seems to be doing something weird really is weird or if it was based on something you're not considering. It's also the time when you want to maximize the number of people that can jump in and help.
Everybody has their own coding standards and there is certainly some subjectivity to those standards. Here's mine for people who work for me: if you don't document your code, you have no business touching anything that goes anywhere near production, you can't do anything that is critical path, and you should make a sincere effort to change or start looking for another job. :)
But I need to point out: The code sample is just hilarious!
Typical C code… Not even correctly indented. ;-)
I will never get those people creating all this write only code.
The C hackers seem to even think chars in symbols are scarce, so they still name them like `c`, `d`, `s`, `pp`, `me`, `mv`, `qpel`, `fx`, `bx`, etc.
Paired with zero abstraction (because C is not much more than a macro assembler) this creates the most horrible code I can imagine.
What the hell is that supposed to even mean? Then writing log messages are excuses too.
Version control, code style conventions, and testing have nothing to do with explaining how something works or writing about potential pitfalls of this function if some other core logic were to change etc.
Absolutely baffling you guys are arguing for never writing comments.
Comments are for things that are __impossible__ to tell from the code and the code alone.
Comments are subjective, code isn't.
90% of the companies I've worked at have had commits linked to actual tickets in a ticketing system. if i really need to understand what was going on, holistically, i could just git blame and go there. i look at tests, I look at the discussion around the code between the person who reviewed the PR and the person who raised the PR. Too often people use comment incorrectly or noisily.
No one is saying you shouldn't write comments. People are saying there are way better practices out there and you should really ask your self, why you are writing a comment to begin with and is there a better way to capture what it is your are trying to do so product managers, developers, engineering managers, QA people understand what the intent of that commit was.
So first of all, not everyone works with massive teams. I work in a three person team with two of us actually doing the coding, and really it's 90% myself.
Comments are generally put in to explain in very simple terms what the function is doing, so when we have to go back or we are upgrading functionality it's easy to remember. Second, comments are put into specific parts of functions to explain how/why something was done if it's not blatantly obvious. So later on when we are going back and don't remember exactly why it was done that way, we can see if it was done that way because of other specific assumptions.
>No one is saying you shouldn't write comments. People are saying there are way better practices out there
You literally contradict yourself. You are literally saying "there are way better practices out there (than writing comments)". But you also say no one is saying you shouldn't write comments?
And hey- I get we are talking about different workflows.. but that's my point. You are assuming that every commit is linked to a specific ticket in a system with an entire discussion around it. I mean ok, but do you really think that is how small agile teams work? I would get absolutely nothing done if I did that. And the point still remains, even if there are tickets to commits and discussion around it... if you are looking into some random function and wondering why it does X- you are arguing it's better to look into some commit history instead of reading a comment directly there to see why it is how it is? That seems like a bad argument on your part.
> You literally contradict yourself. You are literally saying "there are way better practices out there (than writing comments)". But you also say no one is saying you shouldn't write comments?
Comments used to be a catch all for everything that wasn't code. Comments are still useful, but they are often abused.
//-----------------
// <date> This is to work around a bug in the third party
// function foo() (filed bug report #foo234). This code does ...
//
// <date six months later> foo() still not fixed.
//
// <date one year later> foo() still broken. Bug report returned as
// WONT-FIX. Sigh.
//-----------------