I've seen this claim a number of times and it's always so odd to me. One of my most common activities each day - certainly more common than the activity of writing new code - is reading the commit history for different files. It's always surprising to me to hear that this is an uncommon thing to do.
Edit to add: But I also think comments and documentation of all kinds are good. I don't advocate good commit messages instead of comments, but rather in addition to comments. The more documentation the better.
At the directory level, I look at the history of commit messages to get a sense for how the module(s) under that directory have evolved over time. At the file level, I look at the history of commit messages and often dig into the associated diff in order to see how the API and/or implementation have evolved. I'll often follow the file-level diff to the full commit to see what the entire change entailed. This gives me tons of context on the what and the why of a codebase's evolution, and it's all aided by good commit messages.
Line level blame/annotate is sometimes useful when I'm trying to trace how some particular implementation came to be, but it is easy to lose the thread across deletions and renames, which I find file and directory level history to be much more resilient to.
- right click on the line number, click Annotate; this gives you the commit date and author in the gutter
- hover over the date/author name; this gives you the commit hash and message
- click on the hash itself in the popover; this shows the git commit graph on the Version Control tab
- right click on the date/author name, click Annotate Revision; this opens up the version committed then, with its git blame in the gutter.
Today I just had this example. I placed a little sleep in a loop. But there is absolutely no way to know why it is there. So I inserted a comment to explain the loop is DOSing a server by constantly requesting it and the sleep will reduce the load on that server.
Those comments are not only for others but also for yourself. Even weeks from now it is easy to lose track on why you did things the way you did.
Comments on why are very helpful.
Why is a lot more important that what.
Here's an example I use (Verbatim from here[0]):
-
Why Vs. What
I’ve come to realize that the most important inline documentation concerns WHY we are doing something; not WHAT we are doing. For example, no one wants to read “// Set the value of b to 3,” for a line of code that looks like let b = 3. That’s just dumb.
let b = 3 // Set the value of b to 3
However, they may want to know “// Set the value of b to the number of iterations we'll be making.”
let b = 3 // Set the value of b to the number of iterations we'll be making
-
[0] https://medium.com/chrismarshallny/leaving-a-legacy-1c2ddb0c...
let iterations = 3 // We need to iterate 3 times for the value to stabilize
-
With a good name, we could probably do away with the comment entirely:
let numberOfIterations = 3
-
It’s a fairly exhaustive article (but kind of a long read).
Documentation is an important topic.
https://medium.com/chrismarshallny/leaving-a-legacy-1c2ddb0c...
My job description is not "developer" at the moment, so when I was asked to comment my code in order to turn it over to the developers, I looked for some standards. The document I found said, more or less, that you should write comments such that if the code was removed, someone could use the comments to completely reconstruct it.
An obvious problem is that you can write about the "why" of anything on a micro or macro level or in between.
I think this is an "archaic" concept in line with heavily structured methodologies, where everything is first documented in meticulous detail and then the code will map to documentation 1:1. Anyone heard of/still remembers SSADM?
Anyway, that approach has turned out to be less than practical, to say the least, and was one of the reasons the agile methodologies were invented in the first place.
The point today is that the documentation should supplement the code to make the other developers/readers of the code aware of the hidden intricacies of the code. Lately, we are focusing on the "why" because it is turning out to be the most useful. As you say, there are still questions on the level of detail of the "why" we need to capture. Mostly, people just go with their gut feeling and that's fine, as long as we take care to calibrate the feeling through feedback and improve it with time.
Maybe there could be a formal way of knowing what needs more clarification but I doubt it. We still lack a way of mapping our human level understanding of the system to a formal machine analyzable system, so a computer analyzing our program cannot know what step in the program would be surprising to a human reader.
I understand that this is just a rule of thumb, but it's so far from anything I could expect to happen in reality that it serves as no justification at all. A codebase is a living entity that grows and changes over time. Without sound justification that butresses both when and when not to comment, advice like this can lead to exactly the brittle comments that disillusion people from commenting as a whole.
Comments are just a part of a healthy breakfast. You want the code to be as clear as possible, both in the small (algorithmically) and in the large (architecturally). When the code must necessarily fall short, comments must fill that gap -- and only that gap. (Other forms of documentation serve other needs.)
It's like unit tests and integration tests: you want as many unit tests as possible, to give you assurance that the pieces from which you assemble your system are correct. Where unit tests cannot speak, other kinds of tests fill the gaps. But if you try to build your test suite out of integration tests, you'll end up pretty miserable.
As I turn this over in my head, it doesn't sound that convincing because the whole "code should be self-explanatory" ethos seems to me just as susceptible to encouraging bad behavior. Saying something is clear allows you to elevate yourself and blame others if they don't follow. Expecting people to judge their own communication is a definite conflict of interest. Exaggerated commenting requirements as I described are at least a reminder that you should try to err on the other side.
Also, for context, the agency I work for is responsible for an accounting system that affects a lot of people and is very much not a "move fast and break things" place. The most exciting thing that happens year after year is reducing the scheduled downtime window(s). Even that obviously must have diminishing returns.
The other thing is that in my particular case, the code I wrote is not directly applicable to the accounting system and is written in a different language, so anyone trying to modify it will probably be relatively inexperienced and there is zero chance of anyone being hired to work on it.
I hope it's clear from what I wrote that I don't think code can be perfectly self-explanatory. I don't think it's all-or-nothing in either direction. I do, however, think that direct clarity is the first line of defense, followed by comments and other documentation artifacts to capture what the code cannot.
> Expecting people to judge their own communication is a definite conflict of interest.
I don't disagree: while I think it's possible to train your communications so that you meet a minimum bar by default, that training necessarily comes by testing your communication against others. We have peer review processes in part to help account for this: if something isn't clear, that's the first forum of opportunity to address it.
The (only) good thing about pithy quotes like "you should be able to rewrite it from the comments" and "code should be self-explanatory" is that they stake out concrete, extreme positions that can be judged on their merits. The space of practice is much wider than the ideologically pure boundary.
I'm sure that, for your situation, commenting everything such that it could be rewritten from scratch makes sense. If you needed to pass ownership of a codebase more or less instantaneously, it may make sense as a kind of snapshot of the intent behind the codebase at that point in time.
I also work with some critical, ancient software. I wish I had more documentation of all kinds, but mostly because it would help me decipher the codebase itself. I wish the codebase didn't need the degree of deciphering that it does. It makes even minor changes take longer just to make sure I'm not breaking something else along the way -- to say nothing of major changes, which while relatively rare do come along. Again: my biggest need is to decipher the codebase itself, and I would rather it inherently require less effort to do so. There are straightforward principles, like "avoid globals", that are violated left and right in this software by no real necessity. Commenting these aspects is a simply a band-aid on something that should have been engineered better from the beginning.
Well you can also look at it from another angle: unnecessary comments are a distraction and make code less readable.
You are not writing comments just to comment. You write them to make things clear.
Sometimes I also write comments to explain what, but most of the time those are written in large peaces of logic with multiple steps that cannot (or should not) split into multiple functions. But even then those comments tend to be in the form of 'why'.
For example: "// First we do this // Then we do this because.. // And as last step we do this because..."
My personal rule for comments:
If I come back in half a year, would I still understand what is going on here? No? -> Comment!
Take your own advice then: don't hire such people. Why would you insist on maintaining documentation and not maintaining a reasonable change log in your commits, if knowing "why" is important to you?
(I make the advice tongue-in-cheek btw. Better to educate and lift developers up wherever you can than just freeze them out. Not everyone has the experience with these things that we do.)
There's not a one-size-fits-all solution here. Different orgs handle their code history different ways, but having tasted the power Git gives you over certain other VCSes to make the commit log really useful as a record of change, and having taken advantage of that feature several times myself, I wouldn't want to go back.
This follows another comment I just made on the topic: https://news.ycombinator.com/item?id=23743973
That's like saying articles don't need summary.
We actually rarely use comments in code. The best way to reflect the corner cases are tests. It is the comments codified.
> but it can never say why
Usually people don't need to know why on small piece of code unless it's a high-level stuff. For high-level stuff we have architecture decision records (ADR) which records the motivations and situations. But we also keep it very short or people would never read those.
> "Nobody ever updates comments, so they're always out of date" - don't hire such people.
That's a really high standards. It's almost like "We have bugs", "Well, then don't hire people writing bugs"...
There are many ways of breaking comments. For example, someone changed module A, then the properties on module B changed because of A. If it's a test it will reflects on CI, but if it's a comment there's almost no way for people to realize that.
Consider it another tool in the toolbox. I've gone spelunking through git history to decipher the reasoning of something still in use, though comments had been deleted and no one had documented it before me.
which is to say, the comments should be kept concise and current too.
"Clear code shouldn't need comments" - clear code can make it easy to see what but it can never say why. Let me know what corner cases you thought about when you wrote this.
"The comments are in the commit messages" - almost nobody ever goes looking for them there, they're effectively invisible from `git blame` when they remove lines, people rarely make fine grained enough commits to be able to target specific lines or blocks sufficiently with context.
"Nobody ever updates comments, so they're always out of date" - don't hire such people. It is an crucial task resolving the meaning of comments to make sure everything still makes cohesive sense. Neglecting to do this will often lead to commits that don't quite grok any subtleties of the original design. Don't make the reader of the code do the job of trying to piece together the scattered history of 5 different people's intentions. Of course, it's also useful to try to keep comments as close to the code in question as possible so that references which need updating are obvious to see.