Code Comments: How to Write Clean and Maintainable Code
Discover the benefits of good code comments and learn best practices for writing effective documentation. Improve code quality, readability, and collaboration. By Roberto Machorro.
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Contents
Code Comments: How to Write Clean and Maintainable Code
20 mins
- What Are Code Comments?
- A Brief History of the Comment
- Code Without Comments
- Good Comments
- Useless Comments
- Bad Comments
- Beyond Annotations
- LICENSE Comments
- TEMPORARY CODE-OUT Comments
- DECORATIVE Comments
- LOGIC Comments
- Advanced Forms of Comments
- Flag Comments
- TASK Comments
- DOCUMENT GENERATION Comments
- CDATA Comments
- Having Fun With Comments
- Key Takeaways
- Where to Go From Here?
- About the Author
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 -*-
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.