Code comments convention
Introduction
Programs must be written for people to read and only incidentally for machines to execute. --Hal Abelson--
Sample
Functions
Each function in your code should have a docstring that explains what the function does, how to use it, and what it returns. The docstring should be written in a clear and concise way.
Python
The comment should be formatted according to the PEP 8 style guide
Example:
# ✅ Do
def factorial(n):
"""Calculates the factorial of a number.
Args:
n: An integer.
Returns:
The factorial of n.
Raises:
ValueError: If n is negative.
"""
if n < 0:
raise ValueError("n must be a non-negative integer")
if n == 0:
return 1
else:
return n * factorial(n - 1)
Javascript
The comment should be formatted according to the following conventions:
- Start the docstring with a one-line summary of what the function does.
- Follow the summary with a more detailed explanation of the function, including its parameters, return value, and any side effects.
- Use JavaScriptDoc syntax to document the function's parameters and return value.
- Wrap the docstring to 72 characters or less per line.
Example:
// ✅ Do
/**
* Calculates the factorial of a number.
*
* @param {number} n The number to calculate the factorial of.
* @returns {number} The factorial of n.
*/
function factorial(n) {
if (n < 0) {
throw new Error("n must be a non-negative integer");
}
if (n === 0) {
return 1;
} else {
return n * factorial(n - 1);
}
}
Classes
Each class in your code should have a docstring that explains what the class does and how to use it
The docstring should also document the class's attributes and methods.
Python
Example
# ✅ Do
class User:
"""
A class that represents a user.
Attributes:
name: The user's name.
email: The user's email address.
Methods:
get_name(): Gets the user's name.
get_email(): Gets the user's email address.
"""
def __init__(self, name, email):
self.name = name
self.email = email
def get_name(self):
return self.name
def get_email(self):
return self.email
Javascript
Example
// ✅ Do
/**
* A class that represents a user.
*/
class User {
/**
* Constructs a new User object.
*
* @param {string} name The user's name.
* @param {string} email The user's email address.
*/
constructor(name, email) {
this.name = name;
this.email = email;
}
/**
* Gets the user's name.
*
* @returns {string} The user's name.
*/
getName() {
return this.name;
}
/**
* Gets the user's email address.
*
* @returns {string} The user's email address.
*/
getEmail() {
return this.email;
}
}
Rules
Comments should not duplicate the code
Comments that add no information have negative value because they:
- Add visual clutter
- Take time to write and read
- Can become out-of-date
# 🚩 Don't
i = i + 1; // Add one to i
Good comments do not excuse unclear code
Another misuse of comments is to provide information that should have been in the code. A simple example is when someone names a variable with a single letter and then adds a comment describing its purpose:
// 🚩 Don't
private static Node getBestChildNode(Node node) {
Node n; // best child node candidate
for (Node node: node.getChildren()) {
// update n if the current state is better
if (n == null || utility(node) > utility(n)) {
n = node;
}
}
return n;
}
The need for comments could be eliminated with better variable naming:
// ✅ Do
private static Node getBestChildNode(Node node) {
Node bestNode;
for (Node currentNode: node.getChildren()) {
if (bestNode == null || utility(currentNode) > utility(bestNode)) {
bestNode = currentNode;
}
}
return bestNode;
}
If you can't write a clear comment, there may be a problem with the code
This brings to mind Kernighan's Law:
Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it.
Rewrite the code to something you understand well enough to explain or, better yet, that is straightforward.
Comments should dispel confusion, not cause it
If your comment causes confusion instead of dispelling it, remove it.
Explain unidiomatic code in comments
It's a good idea to comment code that someone else might consider unneeded or redundant, such as this code from App Inventor (the source of all of my positive examples):
// ✅ Do
final Object value = (new JSONTokener(jsonString)).nextValue();
// Note that JSONTokener.nextValue() may return
// a value equals() to null.
if (value == null || value.equals(null)) {
return null;
}
Without the comment, someone might "simplify" the code or view it as a mysterious but essential incantation. Save future readers time and anxiety by writing down why the code is needed.
Provide links to the original source of copied code
If you're like most programmers, you sometimes use code that you find online. Including a reference to the source enables future readers to get the full context, such as:
- What problem was being solved
- Who provided the code
- Why the solution is recommended
- What commenters thought of it
- Whether it still works
- How it can be improved
For example, consider this comment:
// ✅ Do
/** Converts a Drawable to Bitmap. via https://stackoverflow.com/a/46018816/2219998. */
Include links to external references where they will be most helpful
Of course, not all references are to Stack Overflow. Consider:
// ✅ Do
// http://tools.ietf.org/html/rfc4180 suggests that CSV lines
// should be terminated by CRLF, hence the \r\n.
csvStringBuilder.append("\r\n");
Links to standards and other documentation can help readers understand the problem your code is solving. While this information may be somewhere in a design document, a well-placed comment gives readers the pointer when and where it is most needed. In this case, following the link indicates that RFC 4180 has been updated by RFC 7111—useful information.
Add comments when fixing bugs
Comments should be added not just when initially writing code but also when modifying it, especially fixing bugs.
Not only does the comment help the reader understand the code in the current and referenced methods, it is helpful for determining whether the code is still needed and how to test it.
It can also be helpful to reference issue trackers:
// ✅ Do
// Use the name as the title if the properties did not include one (issue #1425)
Use comments to mark incomplete implementations
Sometimes it's necessary to check in code even though it has known limitations. While it can be tempting not to share known deficiencies in one's code, it is better to make these explicit, such as with a TODO comment:
// ✅ Do
// TODO(hal): We are making the decimal separator be a period,
// regardless of the locale of the phone. We need to think about
// how to allow comma as decimal separator, which will require
// updating number parsing and other places that transform numbers
// to strings, such as FormatAsDecimal
Using a standard format for such comments helps with measuring and addressing technical debt. Better yet, add an issue to your tracker, and reference the issue in your comment.