Zephyrnet Logo

Code Comments: How to Write Clean and Maintainable Code

Date:

If you spend a reasonable amount of time programming, you’re sure to encounter code comments. You may have even written some yourself. These tiny pieces of text are embedded within the program, but they’re ignored by the compiler or interpreter. They’re intended for the humans who work with the code, and they have many applications. They may even reshape your code or create documentation for others automatically. Want to know how to use them properly? Then you’re in the right place!

Time to explore comments, how to use them and also how not to use them.

What You’ll Learn:
By reading this article, you’ll learn:

  • What a comment is, types and how to use them.
  • Where they began and where they are now.
  • The difference between good and bad comments.
  • Practical applications from the past and present.

By the end of the article, you’ll know why code comments are important, best practices for writing effective comments, some common pitfalls and mistakes to avoid and the tools and resources you can use to optimize your code commenting process, including automated documentation generators, comment linters and code review platforms.

You’ll start with an in-depth look at what code comments are.

What Are Code Comments?

Comments within a software program are human-readable annotations that programmers add to provide information about what the code is doing. Comments take many forms, depending on the programming language and the intent of the comment.

They’re categorized into two types: block comments and line comments.

  • Block comments delimit a region within the code by using a sequence of characters at the start of the comment and another character sequence at the end. For example, some use /* at the start and */ at the end.
  • Line comments use a sequence of characters to ask the compiler to ignore everything from the start of the comment until the end of the line. For example: #, or //. How to indicate line comments depends on the programming language you’re using.

Here’s an example of how each kind of comment looks in Swift:

struct EventList: View { // THIS IS A LINE COMMENT @EnvironmentObject var userData: UserData @EnvironmentObject var eventData: EventData /* THIS IS A BLOCK COMMENT @State private var isAddingNewEvent = false @State private var newEvent = Event() */ var body: some View { ... }
}

Some programming languages only support one type of comment sequence, and some require workarounds to make a sequence work. Here’s how some languages handle comments:

Comment Sequences Table in Multiple Languages
Comment Sequences Table in Multiple Languages

Think about how you’d use a sticky note. For programmers, a comment is a sticky note with unlimited uses.

Comments have taken on more importance over time as their uses have expanded and standardized. You’ll learn about many of these uses in this article.

A Brief History of the Comment

Not so long ago, computers weren’t programmed using a screen and a keyboard. They were programmed using punch cards: small pieces of stiff paper with holes punched in a sequence to indicate instructions for a computer. These would become giant stacks that were fed into a reader, and the computer would run the program.

It was hard to know at a glance what each card or a set of cards did. To solve this, programmers would write notes on them. These notes were ignored by the machine reader because it only read the holes on the card. Here’s an example:

A punch card with a comment written on it

Today, most comments serve the same purpose: to assist in understanding what code does.

Code Without Comments

A common saying among programmers is, “Good code doesn’t need an explanation”. This is true to a certain extent, and some programmers don’t write comments in their code.

But what happens when that code gets really big? Or it incorporates several business rules and logic? Or other people need to use it? It would be possible to decipher the uncommented code, but at what cost in time and effort?

When our focus is constantly on writing code, we forget that a few months — even a few weeks — after writing said code, a lot of the logic has left our memory. Why did we make certain choices? Why did we use certain conventions. Without comments, we will have to go through the expensive exercise of figuring out what we were thinking.

Comments are incredibly useful, and good developers should use them. However, all comments are not created equal. Here’s a look at what makes comments good, useless or even counterproductive.

Good Comments

Good comments are simple and easy to read. They clarify or indicate a train of thought as opposed to how the code works.

They take many forms, such as annotations, links and citations to sources, licenses, flags, tasks, commands, documentation, etc.

Useless Comments

Comments are good, but you don’t need to use them everywhere. A common pitfall is using comments to describe what code is doing, when that’s already clear.

For example, if you have code that’s iterating through an array and incrementing each value, there’s no need to explain that — it should be obvious to the programmer who’s reviewing the code. What isn’t obvious, though, is why you’re doing that. And that’s what a good comment will explain.

Describing the obvious is a common pitfall… and comments that do this are just taking up space and potentially causing confusion.

Bad Comments

Bad comments are more destructive than useless. They cause confusion, or worse, try to excuse convoluted or badly written code. Don’t try to use comments as a substitute for good code. For example:

var n = 0 // Line number

Instead, do:

var lineNumber = 0

Abusing comments, such as cluttering code with TODO, BUG and FIXME comments, is bad practice. The best solution is to resolve these prior to committing code when working on a team — or simply create an issue in a ticketing system.

Since comments are free-form, it’s helpful to have some conventions or templates to determine what a comment should look like, but mixing conventions falls into the category of bad comments.

Did you comment on code during development? Don’t commit it — resolve the problem and take out the comment before you confuse others in the team.

Beyond Annotations

Up to this point, you’ve learned about using comments as annotations. However, since comments have no predefined format, you can extend their use by transforming your humble comment annotation into a data file or specialized document. Here are some good examples.

LICENSE Comments

LICENSE is a type of comment that indicates terms and conditions for the code. You’ll see these especially often in open-source code. Here’s an example from the MIT LICENSE:

/*
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

Since comments are free-form, the way the comment is typed can take many shapes. Here’s an example from Apple:

//===---------------------------------------------------------------===//
//
// This source file is part of the Swift open source project
//
// Copyright (c) 2015-2016 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===---------------------------------------------------------------===//

TEMPORARY CODE-OUT Comments

Programmers use the TEMPORARY CODE-OUT comment as a tool for debugging. By taking a block or line of code out of the compile process, you can alter which code executes and which doesn’t. This method is commonly used when doing a process-of-elimination debug. For example (only building for iOS):

let package = Package( name: "CommentOut", platforms: [ .iOS(.v14), /* .tvOS(.v14), .watchOS(.v7), .macOS(.v11) */ ], products: [ .library(name: "CommentOut", targets: ["CommentOut"]) ], targets: [ .target(name: "CommentOut") ]
)

DECORATIVE Comments

A DECORATIVE or SEPARATOR comment can separate a file or blocks of code by some category or function. This helps users find code more easily. Here’s an example:

/************************************************** * Huffman Implementation Helpers * **************************************************/

LOGIC Comments

LOGIC comments document the rationale you chose when creating the code. This goes beyond what the code shows, like “What was that value assigned?”

For example (from swift-package-manager/Sources/Commands/SwiftRunTool.swift, lines 287-288):

private func execute(path: String, args: [String]) throws -> Never { #if !os(Windows) // On platforms other than Windows, signal(SIGINT, SIG_IGN) is used for handling SIGINT by DispatchSourceSignal, // but this process is about to be replaced by exec, so SIG_IGN must be returned to default. signal(SIGINT, SIG_DFL) #endif try TSCBasic.exec(path: path, args: args)
}

In this case, the execute function contains compile conditional instructions that will either include or skip the signal call. The comment contains the explanation as to why it does this.

Advanced Forms of Comments

Comments can hold specialized content, typically formatted just like a data file would be: a file within the code. They can also be simple flags, which source code parser tools can respond to in different ways.

Flag Comments

Flag comments are typically used by linters; they enable or disable features. Here’s how SwiftLint disables features using flag comments:

struct GitHubUserInfo: Content { let name: String // swiftlint:disable identifier_name let avatar_url: String? // swiftlint:enable identifier_name
}

Compilers themselves also use flag comments as a form of setup. In the example below, you see a Python script run as a CLI script and in UTF-8 format:

#!/usr/bin/env python3
# -*- coding: UTF-8 -*-

Note: The first comment line in scripts has a formal name: the shebang. Its purpose is to indicate which interpreter the operating system should use when it executes the script. It always starts with a #!.

TASK Comments

Integrated development environments (IDEs), text editors and some CLI tools are able to read TASK comments left by programmers in a format that indicates an action to be performed by the programmer in the future, such as TODO:

// TODO: Switch Model permissions // FIXME: Convert strings to Enum

DOCUMENT GENERATION Comments

DOCUMENT GENERATION comments allow a tool to parse the source code and output a formatted document — typically HTML — that end users can use to browse classes, methods, etc. Here’s an example from JavaDoc:

/** * @param string the string to be converted * @param type the type to convert the string to * @param <T> the type of the element * @param <V> the value of the element */
<T, V extends T> V convert(String string, Class<T> type) {
}

Other tools can generate documentation that’s seen by IDEs and shown to the user within the code. One such tool is Documentation Markup (DocC). This is particularly useful for APIs Apple uses with its own libraries. Here’s an example from the open-source SwiftGD project:

/// Exports the image as `Data` object in specified raster format.
///
/// - Parameter format: The raster format of the returning image data (e.g. as jpg, png, ...). Defaults to `.png`
/// - Returns: The image data
/// - Throws: `Error` if the export of `self` in specified raster format failed.
public func export(as format: ExportableFormat = .png) throws -> Data { return try format.data(of: internalImage)
}

CDATA Comments

CDATA comments embed formatted data within XML and XHTML files. You can use several different types with these comments, such as images, code, XML within XML, etc.:

<![CDATA[<sender>John Smith</sender>]]>

From Wikipedia’s article on Computer Programming Comments, you have the RESOURCE inclusion type of comment: “Logos, diagrams, and flowcharts consisting of ASCII art constructions can be inserted into source code formatted as a comment”. For example:

<resource id="ProcessDiagram000">
<![CDATA[ HostApp (Main_process) | V
script.wsf (app_cmd) --> ClientApp (async_run, batch_process) | | V mru.ini (mru_history) ]]>
</resource>

Having Fun With Comments

Just because comments aren’t included with an app doesn’t mean you can’t have fun with them. Life lessons, jokes, poetry, tic-tac-toe games and some coworker banter have all made it into code comments. Here’s an example from py_easter_egg_zen.py:

import this # The Zen of Python, by Tim Peters # Beautiful is better than ugly.
# Explicit is better than implicit.
# Simple is better than complex.
# Complex is better than complicated.
# Flat is better than nested.
# Sparse is better than dense.
# Readability counts.
# Special cases aren't special enough to break the rules.
# Although practicality beats purity.
# Errors should never pass silently.
# Unless explicitly silenced.
# In the face of ambiguity, refuse the temptation to guess.
# There should be one-- and preferably only one --obvious way to do it.
# Although that way may not be obvious at first unless you're Dutch.
# Now is better than never.
# Although never is often better than *right* now.
# If the implementation is hard to explain, it's a bad idea.
# If the implementation is easy to explain, it may be a good idea.

Important: Easter egg comments aren’t welcome in all source codes. Please refer to the project or repository policy or your employee handbook before doing any of these.

Key Takeaways

Today, you learned that there’s more to comments than it seems. Once considered an afterthought, they’re now recognized an invaluable communication tool for programming.

  • They help document and preserve knowledge for future code maintenance.
  • There are good comments and bad comments.
  • Comments can help create automated documentation.

Now, it’s time to practice! The only way to get good at comments is by jumping in and adding them.

By making comments part of your programming thought process, they no longer become an extra step to perform. Here are some ways to practice:

  • Document your current projects and be mindful of any standards set for the project or repository.
  • Use a linter on all your projects to keep your formatting and conventions in check.
  • Find a document generator and publish your work.

You can practice and contribute while supporting an open-source project that needs help with comments and documentation.

Where to Go From Here?

If you’d like to learn more about commenting, check out these articles and resources. Many of them were consulted in the writing of this article.

We hope you’ve enjoyed this look at commenting! Do you have questions, suggestions or tips to share? Join us in the forum for this article. You can all learn from each other.

About the Author

Roberto Machorro has been programming professionally for over 25 years, and commenting code just as long. He has championed documenting in-house, third-party and open source code out of frustration for having to maintain badly written code or struggle with unavailable documentation. He got started with library documents using HeaderDoc, JavaDoc and now enjoying DocC.

spot_img

Latest Intelligence

spot_img