Advertisement

Best Way To Comment Code Without Cluttering

Started by August 04, 2016 12:14 AM
15 comments, last by Chris Hatch 8 years, 3 months ago

Best way to comment large code may seem like a stupid question, because you can say "just do it, write what it does next to the class/function/variable".

But I've always found too much comments being counter productive in that the code gets cluttered and becomes less readable. So I tend minimise comments, believing that good descriptive class/method/variable names and good code structuring would do most of the self commenting. So I only add one or two comments. Other times i think- this so simple I don't really have to comment and many times this is correct. And other times i add comments when only when i'm going over a part of the code I haven't seen for a while and it starts to confuse me. At the time of coding it, it mostly never seems i could get lost on the current algorithms, but as the code keeps getting larger by the weeks/months/ (and now a couple of years), getting lost on my past code is happening more and more. ... made much worse because I tend to write really compact algorithms/code and commenting compact algorithms to the line is really impractical as it breaks the flow and gets very difficult to read.

Linking different parts has not been trivial and is even more difficult to comment without cluttering the code. But continuation helps me a lot, I try to hold all the strands and code mechanics well in my head and get fully immersed as long as I don't long breaks lasting weeks.

I'm still fine with most of my code and the overview is still clear to me, but some fine detailed stuff are really getting on my nerves and I really wished I had commented these parts better. I need to re-work this parts of the code so I can do some debug analysis without breaking anything. I need to get fully immersed , .. but tracking some of the really fine details of these algorithms remains the problem,

"Old habits die hard", I probably would only add just a brief comment in addition... just enough to satisfy the actual issue that got me lost in the first place

So I would like to know how people here find the right balance. Do you just automatically write a whole lot of stuff after every thing you declare without bothering about cluttering? Is there a standard way? Or do you do minimal commenting but good code structure ensures you never get lost?

can't help being grumpy...

Just need to let some steam out, so my head doesn't explode...

I do minimal commenting like youself. I found too much comments makes the code harder to read. I found also any workaround code for tricky bugs is *very* hard to understand later on after you've forgotten about the bug, so I make sure I document those bits very well.

Advertisement

I almost never comment on the "how" of things, but I occasionally comment on the "why" of things. Most of the times this means a single line of code where needed, about 2% of my lines consist of comments. If you ever get back to your code after a while and you don't remember a thing, the code will still tell you how it works eventually, but it might not always make clear why you chose to do some thing in some particular way.

What I try to follow for my own code:

Write code that, for the most part, does not require comments. This includes proper names for things, keeping functions small & contained, dealing with as little code as it makes sense to do, keeping with the style of surrounding code, etc.

For algorithms or math heavy stuff I sometimes add a link in a comment, or copy the formula and information directly in comments if it doesn't take too much space.

Comment things that are out of the ordinary, or where the intuitive solution is not the correct solution.

Hello to all my stalkers.

One type of comment I find very useful is to link any code to bugs (jira, github issues, whatever), including for FIXMEs and known problems. More generally, links to a page on the company wiki or anything like that are also good; you can have huge amounts of documentation and archived conversation on the code without cluttering up the source file itself.

The bugs are generally durable (e.g., the link is valid even after the bug is closed), so it lets developers go and find any discussion that occurred relating to the code. Sometimes just seeing the title of the bug (or feature request) is enough to explain the "why" of some code, or provides important context (e.g. "this feature is stupid and complicates everything, why ffs did anyone... oh, an executive asked for it personally").

The further advantage is that if you are investigating a bug but either can't fix it immediately or need to hand it off to another developer, it lets them find relevant parts of the code you investigated very easily and quickly. I just yesterday had a case where I got assigned a months-old bug, searched the codebase for the jira ticket name, and found 6-month-old comments from myself of the form: // [ABC-1234] I think this logic is inverted but I need content to test

Sean Middleditch – Game Systems Engineer – Join my team!

What I try to follow for my own code:

Write code that, for the most part, does not require comments. This includes proper names for things, keeping functions small & contained, dealing with as little code as it makes sense to do, keeping with the style of surrounding code, etc.

For algorithms or math heavy stuff I sometimes add a link in a comment, or copy the formula and information directly in comments if it doesn't take too much space.

Comment things that are out of the ordinary, or where the intuitive solution is not the correct solution.

This is more or less what I strive for as well.

Comments and documentation aren't the end-goal -- an understandable code-base is. To that end, reducing the need for comment or documentation is every bit as good and useful as writing comments or documentation; in fact, its often better because the code cannot diverge from itself, as comments often do from the code they purport to represent. Documentation that diverges from its code is a bug-in-waiting.

Code should never be more complicated than there is reason for it to be. There's no reason to be clever or flexible or fast where its not certain to become a necessity. I'm not saying we shouldn't ever do these things, but that we spend altogether too much time in pursuit of these facets for their own sake, or for valuing them against their imagined benefit rather than their actual utility. Avoiding such frivolities shrinks and simplifies code bases, resulting not only in fewer lines to comment, but also less pressure to comment the lines that remain*.

Strive to make your code self-explanatory at every scope it could be reasonably dissected into. The best loops are those I can understand without looking to the rest of the function. The best functions are those I can understand without looking to the surrounding class or file, or to the functions it calls or that call it. The best classes are those I can understand without looking to the member functions it carries, the base(s) it inherits from, or the rest of the module it lives in. If I can look at units of code at all of these levels and understand what I see without insider information, that code might not need to be documented at all. Likewise, where I lack the information to understand this unit of code tells me precisely what comments I need and are appropriate for this scope.

Document the complexity that you can't avoid, and document the rationale behind not avoiding it. You might introduce complexity to fix a bug (unless the bug was the result of a typo, there is complexity here by definition -- you missed it the first time), to make things flexible or extensible (open-endedness is always introduces complexity), or to make things go fast (going fast sometimes requires specialized code, and specialized code makes assumptions, is complicated, or both -- almost always). Documenting why you did something is every bit as important and illuminating as documenting what you did.

Where appropriate, reference or link to relevant artifacts. Sean mentions bugs, Lactose mentions algorithms. Absolutely do that, and add your specific context to comments or to the artifact itself if it makes sense. Make sure that artifacts are long-lived and if you cannot control or trust that they are, pull the artifact down, check it into your project's source control, and reference the copy you control. It shouldn't be anathema, for instance, to have a folder full of white-papers in your source code repository**.

* Caveat: One way to simplify is by making simplifying assumptions (e.g. "The list will never be empty") -- non-standard assumptions, and especially assumptions against the prevailing mindset should always be documented. In general, all violations of the "principle of least-surprise" should be documented if you choose to make them willfully.

** Caveat: If your repo is public you need to be respectful of copyright and abide by any licensing terms granted, get permission, or be covered by fair-use scenarios.

throw table_exception("(? ???)? ? ???");

Advertisement

As you get more experience ... you need less commenting ... but then you start working on bigger teams, where other programmers need you to comment.

I find that I only FORCE myself to comment in 3 cases:

1. When I'm defining an interface (pure virtual class for c++ peeps), and/or virtual base class method ... so people know what the contract is supposed to be ... not just exactly how its used today.

2. When I had to google something hard or unexpected to solve the problem ... or fix a non-obvious bug.

3. When I couldn't find good enough method names or variable names, so a comment was the only was I could read my own code from top to bottom.

I'm a big fan of long names and short methods ... but sometimes a name like "UpdatePhysicalDamageWithoutResistence" is just a silly method (and also usually a sign your code design / organization isn't great ... but at the end of the day sometimes you just need to write some more code).

Never write comments targeted for beginners or people who've never seen the codebase at all. Write comments targeted at average intermediate programmers who've worked on the project for a short while ... that way you won't need to repeat the standard idioms over and over ... but you will point out the new and interesting stuff.

I almost never comment on the "how" of things, but I occasionally comment on the "why" of things. Most of the times this means a single line of code where needed, about 2% of my lines consist of comments. If you ever get back to your code after a while and you don't remember a thing, the code will still tell you how it works eventually, but it might not always make clear why you chose to do some thing in some particular way.

QFE.

I generally try to pretend that I'm picking up a project that I was pair programming on a few days before, and I write comments to the other programmer. If the "what" of my code is not obvious then there's a problem with the code and I mark it as needing a rewrite. I leave "why" comments wherever they're useful, which usually happens at the top of a function definition (because madness should be encapsulated). In some cases I comment declarations, and will sometimes include information about guarantees if relevant.

It makes me mad when I have to wade through worthless comments to find code, and it irritates me to maintain comments when changing code, so I try not to inflict those kinds of problems on myself or on other people.

void hurrrrrrrr() {__asm sub [ebp+4],5;}

There are ten kinds of people in this world: those who understand binary and those who don't.
When I leave comments, they're generally there to clarify intent - as written above, mainly the "why" of the code. Sometimes I even add them to pre-existing code so I (and my successors) will understand what's going on.

For example, hypothetically somewhere in a codebase:
if (object1.KnowsAbout(object2) &&
    object1.state == ReadyToDoTheThing &&
    // needed because we have to verify that the other system won't explode if we do this
    unrelatedCrap == ShitEnum::Shit && 
    // sometimes ThingThatWillBlowUpIfWeAreNotCarefuls will blow up if we aren't careful about when we access them - 
    (object1.TypeId != ObjectTypes::ThingThatWillBlowUpIfWeAreNotCareful && BlowupyThingSystem.HasNotUpdatedYet()))
{
    // ...
}
The above looks a bit hacky, but sometimes legacy codebases are riddled with this kind of thing, and if I'm going to deal with code like this I'd like to it have comments explaining why a simple check looks like this.

edit: formatting.

There are two ways I have found that I like to comment code. One way is to describe what the previous or following code does:

https://github.com/TutorialDoctor/Scripts-for-Kids/blob/master/Python/velveeta.py

Another way is to translate the code (I like this way best):

https://github.com/TutorialDoctor/Pythonista-Projects/blob/master/Projects/Apps/Basic%20Bible/Basic%20Bible.py

Lines 132-157 and 198-237 demonstrate this best.

They call me the Tutorial Doctor.

This topic is closed to new replies.

Advertisement