Commenting

Though a pain to write, comments are absolutely vital to keeping our code
readable. The following rules describe what you should comment and where. But
remember: while comments are very important, the best code is
self-documenting. Giving sensible names to types and variables is much better
than using obscure names that you must then explain through comments.

When writing your comments, write for your audience: the next contributor who
will need to understand your code. Be generous — the next one may be you!

—[Google C++ Style Guide][google-c++]

Portions of this section borrow heavily from the Google
[C++][google-c++-comments] and [Python][google-python-comments] style guides.

File/class-level comments

Every class definition should have an accompanying comment that describes what
it is for and how it should be used.

A file that contains zero classes or more than one class should have a comment
at the top describing its contents.

  1. # Automatic conversion of one locale to another where it is possible, like
  2. # American to British English.
  3. module Translation
  4. # Class for converting between text between similar locales.
  5. # Right now only conversion between American English -> British, Canadian,
  6. # Australian, New Zealand variations is provided.
  7. class PrimAndProper
  8. def initialize
  9. @converters = { :en => { :"en-AU" => AmericanToAustralian.new,
  10. :"en-CA" => AmericanToCanadian.new,
  11. :"en-GB" => AmericanToBritish.new,
  12. :"en-NZ" => AmericanToKiwi.new,
  13. } }
  14. end
  15. ...
  16. # Applies transforms to American English that are common to
  17. # variants of all other English colonies.
  18. class AmericanToColonial
  19. ...
  20. end
  21. # Converts American to British English.
  22. # In addition to general Colonial English variations, changes "apartment"
  23. # to "flat".
  24. class AmericanToBritish < AmericanToColonial
  25. ...
  26. end

All files, including data and config files, should have file-level comments.

  1. # List of American-to-British spelling variants.
  2. #
  3. # This list is made with
  4. # lib/tasks/list_american_to_british_spelling_variants.rake.
  5. #
  6. # It contains words with general spelling variation patterns:
  7. # [trave]led/lled, [real]ize/ise, [flav]or/our, [cent]er/re, plus
  8. # and these extras:
  9. # learned/learnt, practices/practises, airplane/aeroplane, ...
  10. sectarianizes: sectarianises
  11. neutralization: neutralisation
  12. ...

Function comments

Every function declaration should have comments immediately preceding it that
describe what the function does and how to use it. These comments should be
descriptive (“Opens the file”) rather than imperative (“Open the file”); the
comment describes the function, it does not tell the function what to do. In
general, these comments do not describe how the function performs its task.
Instead, that should be left to comments interspersed in the function’s code.

Every function should mention what the inputs and outputs are, unless it meets
all of the following criteria:

  • not externally visible
  • very short
  • obvious

You may use whatever format you wish. In Ruby, two popular function
documentation schemes are TomDoc and
YARD. You can also
just write things out concisely:

  1. # Returns the fallback locales for the_locale.
  2. # If opts[:exclude_default] is set, the default locale, which is otherwise
  3. # always the last one in the returned list, will be excluded.
  4. #
  5. # For example:
  6. # fallbacks_for(:"pt-BR")
  7. # => [:"pt-BR", :pt, :en]
  8. # fallbacks_for(:"pt-BR", :exclude_default => true)
  9. # => [:"pt-BR", :pt]
  10. def fallbacks_for(the_locale, opts = {})
  11. ...
  12. end

Block and inline comments

The final place to have comments is in tricky parts of the code. If you’re
going to have to explain it at the next code review, you should comment it now.
Complicated operations get a few lines of comments before the operations
commence. Non-obvious ones get comments at the end of the line.

  1. def fallbacks_for(the_locale, opts = {})
  2. # dup() to produce an array that we can mutate.
  3. ret = @fallbacks[the_locale].dup
  4. # We make two assumptions here:
  5. # 1) There is only one default locale (that is, it has no less-specific
  6. # children).
  7. # 2) The default locale is just a language. (Like :en, and not :"en-US".)
  8. if opts[:exclude_default] &&
  9. ret.last == default_locale &&
  10. ret.last != language_from_locale(the_locale)
  11. ret.pop
  12. end
  13. ret
  14. end

On the other hand, never describe the code. Assume the person reading the code
knows the language (though not what you’re trying to do) better than you do.

Related: do not use block comments. They cannot
be preceded by whitespace and are not as easy to spot as regular comments.
[link]

  1. # bad
  2. =begin
  3. comment line
  4. another comment line
  5. =end
  6. # good
  7. # comment line
  8. # another comment line

Punctuation, spelling and grammar

Pay attention to punctuation, spelling, and grammar; it is easier to read
well-written comments than badly written ones.

Comments should be as readable as narrative text, with proper capitalization
and punctuation. In many cases, complete sentences are more readable than
sentence fragments. Shorter comments, such as comments at the end of a line of
code, can sometimes be less formal, but you should be consistent with your
style.

Although it can be frustrating to have a code reviewer point out that you are
using a comma when you should be using a semicolon, it is very important that
source code maintain a high level of clarity and readability. Proper
punctuation, spelling, and grammar help with that goal.

TODO comments

Use TODO comments for code that is temporary, a short-term solution, or
good-enough but not perfect.

TODOs should include the string TODO in all caps, followed by the full name
of the person who can best provide context about the problem referenced by the
TODO, in parentheses. A colon is optional. A comment explaining what there is
to do is required. The main purpose is to have a consistent TODO format that
can be searched to find the person who can provide more details upon request.
A TODO is not a commitment that the person referenced will fix the problem.
Thus when you create a TODO, it is almost always your name that is given.

  1. # bad
  2. # TODO(RS): Use proper namespacing for this constant.
  3. # bad
  4. # TODO(drumm3rz4lyfe): Use proper namespacing for this constant.
  5. # good
  6. # TODO(Ringo Starr): Use proper namespacing for this constant.

Commented-out code

  • Never leave commented-out code in our codebase.
    [link]