Write better comments

Outline

Documenting software is crucial to ongoing maintenance and personal sanity. Remember the last time you were asked to work on a piece of code written by another developer who wrote no comments? You likely spent the first 20-30 minutes figuring out what the code even did! In this article, we will delve into some basic practices to help keep your code organized and sane with better comments.

How often to add comments

A common question is how often should I add comments? And is there such a thing as too many comments? A good rule of thumb is at the beginning of every logical group, add a comment describing its' functionality. As you read through the comments, you should be able to get a good idea of what is happening regardless of the code's complexity.

At the beginning of every logical group, add a comment describing that group's functionality.

You definitely don't need to add a comment to every if statement, but if you have several in a row that determine factor X, then write a comment at the top of the if/else block. For example:

"""
 LOGIN PAGE:
    - GET and POST requests.
    - GET: Render the Login Page
    - POST: If successful login, redirect to the home page, else stay on Login Page
"""
@app.route("/login/", methods=["GET", "POST"])
def login():
    if request.method == "POST":
        # Get the username and password from the POST request
        username = request.form['username']
        password = request.form['password']

        # Check for valid username and password
        if not (username and password):
            flash("Username or Password cannot be empty.")
            return redirect(url_for('login'))
        else:
            username = username.strip()
            password = password.strip()

        # Get user from database
        possible_user = get_user__first(username)    

        # Check if the user was found and if the password is correct
        if possible_user and check_password_hash(possible_user.password, password):
            session[LOG_IN_STATUS] = username
            set_user__active_status(username, Active_Status.ACTIVE)

            # set privilege and redirect to the home page
            session[ACCESS_LEVEL] = possible_user.privilege
            return redirect(url_for("home"))
        else:
            flash("Invalid username or password.")

    # Render the login page (if GET or invalid login credentials)
    return render_template("login.html")

Style of comments

At the beginning of every file (aside from template files) write a block comment describing the functionality of the program. This doesn't have to be super long but should give a general understanding of the programs' functionality. NOTE: If this is the main file for a program, write out the steps to run it after your short description. For an example, check out the header in this C program here. Another example from by SQLITE DB Class is:

"""
A clean class to work with SQLITE3 Databases in Python
Note: iud = insert, update, and delete
Example usage (run.py file):
=================================================================================
    from DB import DB
    # Connect to DB
    myDB = DB("db-test/db.sqlite3")
    # Create a table
    dbCols = ["id integer PRIMARY KEY", "name text NOT NULL", "priority integer"]
    myDB.create_table("Users", dbCols)
    # Insert data
    myDB.iud("INSERT INTO Users (name) VALUES (?)", ("Joe",))
    # Query data
    for row in myDB.select("SELECT * FROM Users"):
        print(row)
    ---
    Console:
    IN:  $> python run.py
    OUT: $> {'id': 1, 'name': 'Joe', 'priority': None}
=================================================================================
BY: Isaac Lehman
"""

Block summary

At the top of every function, class, or large logical group, create a block comment describing the following functionality. Think of this as your code's cliff notes. It can be as long or concise as you like as long as it gives the reader an understanding of what follows.

I often like to add wide dividing lines to these comments so as you scroll through a large file, you can clearly see where a new logical group starts. Below are a two different examples:

""" ************************************************************************ """
"""                                APP SET UP                                """
""" ************************************************************************ """
def create_table(self, table_name, table_cols):
        """
        Create a table in the DB
        -> Name of table (String)
        -> Array of column statements (Array[String])
            ex. ["id integer PRIMARY KEY", "name text NOT NULL", ...]
        """

Line Comments

Lastly, we have line comments. These go in your functions, classes, etc., and summarize smaller logical groups. Below is an example showing an if/else statement:

# Check for valid username and password
if not (username and password):
    flash("Username or Password cannot be empty.")
    return redirect(url_for('login'))
else:
    username = username.strip()
    password = password.strip()

These should be short and concise so as to not distract from the code too much but still give insight into what is going on. These are especially helpful when complex logic or long ternary statements are involved. (i.e. would take more than 10 seconds to figure out what is going on)

Conclusion

Comments shouldn't be a burden to write. They don't have to be long or complex; they simply need to explain the purpose of your code and visually divide logical sections. Write comments as you code and your future self will greatly thank you!

Comments

Login to Add comments.