--- ---

Code Commenting Guidance

Protocols and styles for commenting code in DocOps Lab projects.

Employing good code commenting practices is more important than ever in the age of LLM-assisted programming. Existing comments are a model for future comments, and poor commenting hygiene is contagious.

In order to maximize the usefulness of code comments for both human and AI readers, DocOps Lab projects follow specific commenting conventions, including purpose and style constraints.

LLM-backed tools and linters are used to review comments and enforce adherence to these conventions, but developer attention is critical. Comments are unlikely to be improved upon after initially merged.

Code Comments Orientation

To begin, we will standardize our understanding of what types of comments are applied to what kinds of code.

Kinds of Comments

Code comments come in several distinct types.

documentation

Code comments used to build downstream-facing reference docs for methods, classes, functions, data objects, and so forth.

Docstrings are specifically comments used in the generation of rich-text reference docs. That they also happen to “document” the code to which they are adjacent is secondary.

expository

Code comments that explain the purpose or function of code blocks, algorithms, or complex logic, strictly in natural language. Also called “inline comments”, these arbitrary remarks are mainly what is governed by this protocol guide.

rationale

Comments that explain the reasoning behind a particular implementation choice, design pattern, or data structure.

status

Stability and lifecycle markers: DEPRECATED:, EXPERIMENTAL:, INTERNAL:, UNSTABLE:. May also include planned removal dates, version gates, feature flags.

admonition

Developer-facing warnings, notes, or tips embedded in code. Use WARNING:, NOTE:, and TIP: prefixes to mark these comments distinctly.

task

Comments like TODO: and FIXME: are used to mark code that needs further work.

instructional

Code comments left in template, stub, or sample files for interactive use. These comments tend to be intended for a downstream user who will interact directly with the file or one based on it.

label

Comments that simply annotate sections of code by category or general purpose, to help with demarcation and navigation. These comments are usually brief and may use special formatting to stand out.

directive

In some languages, we use special character patterns to signify that a comment has a special purpose, other than for generating reference docs. These comments may mark code for special parsing, content transclusion, or other operations.

In AsciiDoc, comments like // tag::example[] and // end::example[] are used to mark content for inclusion elsewhere.

The popular linter Vale recognizes HTML comments like <!-- vale off -→ and <!-- vale on -→ to disable and re-enable content linting.

sequential/collection

Comments that number or order logical stages in a complex or lengthy process or members of a set. Usually something like # STEP 1:, # PHASE 1:, and so forth, or else # GROUP A:, # SECTION 1:, etc. Always use uppercase for these markers (ex: # STEP: not # Step:).

Flavors of Code

Ruby

The most robust environment for code comments, Ruby supports RDoc/YARD-style documentation comments that can be used to generate reference documentation. See Ruby Commenting Protocols for more.

Bash

We make extensive use of comments in Bash scripts, but Bash has no standard for documentation comments or structured comments.

AsciiDoc

Comments in .adoc files tend to be labels, tasks, and directives (AsciiDoc tags). AsciiDoc files tend not to have expository comments, since the content is already documentation.

YAML/SGYML

YAML files use copious label and instructional comments to help downstream users navigate and understand large or complex data structures. Comments can also be used to annotate nesting depth. See YAML Commenting Protocols for more.

Liquid

Our use of Liquid comments is inconsistent at best. Part of the problem is their terrible format with explicit {% comment %} and {% endcomment %} tags. While Liquid 5 has greatly improved that, DocOps Lab tooling is standardized on Liquid 4 at this time.

HTML

We don’t code much HTML directly. It is mostly either converted from lightweight markup or rendered by Liquid templates (or JavaScript). Comments are usually to mark nested objects for convenience, to label major structures or to highlight/clarify obscure asset references, or as directives such as <!-- vale off -→, which disables content linting.

JavaScript

We are not a JavaScript shop, but we do write a good bit of vanilla JavaScript. Comments are used mainly to establish our bearings in the code and therefor are sometimes heavier than with other languages.

CSS/SCSS

We mainly write CSS as SCSS, and commenting is mainly to express the intent upon compiling.

General Style Rules

  • Do not use em dashes or en dashes or (` - `).

    • Use colons (`: `) to prefix a comment with a classification.

    • Use semicolons (`; `) to break up clauses.

  • Use sentence-style capitalization.

  • Do not use terminal punctuation (periods, exclamation points, question marks) unless the comment is multiple sentences.

  • Hard wrap comments around 110-120 characters.

    • Use one-sentence per line.

    • Try not to wrap anything except full sentences.

    • When wrapping multi-line sentences, indent subsequent lines by an additional space.

Expository Comments: Use and Abuse

Arbitrary inline comments used to explain code should be used consistently and only when they add value.

Arbitrary comments can often add value, under an array of conditions that may be more art than science. We must be forgiving and understanding of occasional or even frequent misfires in various developers' subjective takes on what is useful.

This guide exists to help with comment evaluation.

Principles

Expository comments (and their authors) should adhere to these principles:

1) Express purpose, not implementation.

Comments should explain why code exists or what it is intended to do, rather than how it does it. (Rationale comments are available for explaining design/engineering choices, if necessary.)

2) Summarize peculiar or complex implementation (without violating #1).

Expository comments may include a brief reference to an explicit design choice. Still not a rationale comment (too brief, in passing) nor a task comment (no further action prescribed), just a nod to an unusual or non-obvious implementation detail.

3) Use natural, imperative language.

Comments should not contain code, and they should be formatted as English clauses or sentences. Comments should be phrased as commands or instructions, focusing on the action being performed, from the perspective of what the code is to do.

4) Be concise.

Comments should be as brief as possible. Multi-sentence comments should be the exception. In fact, comments should not typically be complete sentences.

5) Maintain relevance and accuracy.

Comments should be reviewed and updated as code changes to ensure they remain accurate and relevant.

6) Never cover straightforward code (except…​).

Not all blocks need comments at all. The main criterion is whether the code’s purpose or function would not be immediately clear from the code itself to a newcomer with beginner or intermediate knowledge of the language and little familiarity with the application architecture.

Exception: Sometimes an oddity or pivotal point needs to be highlighted even in otherwise straightforward code.

7} Do not use comments as notes to reviewers.

Temporary comments intended to guide code reviewers should be avoided. Code used to help with flag logical points or communicate during pair programming or pre-commit review should be denoted as admonitions (such as `# LOGIC: ` or `# REVIEW: `) or `# TEMP: ` and removed before merging.

General Examples

Unnecessary Comments

# Create destination directory if needed
FileUtils.mkdir_p(File.dirname(target_path))

This code does exactly and only what the English comment says. In fact, the comment is muddier than the code. The code will create any necessary parent directories, whereas the comment only mentions the destination directory itself and does not explain if needed. In mkdor_p, the if needed means if the ancestor directories do not exist.

# Determine if we should copy the file
file_existed_before_copy = File.exist?(target_path)

This comment is trying to explain the purpose of the line it precedes, but this is unnecessary. The code itself merely sets a variable to a Boolean value. Not only is the direct purpose of the variable clear from its name and the code making up its value, but the purpose of the variable is only relevant in the context of later code that uses it.

Comments that Add Value

end

# Public helper methods accessible to LogIssue class

def normalize_source_path source_file
  normalized = source_file.gsub(/#excerpt$/, '').gsub(%r{/$}, '')
  normalized.gsub(%r{^\./}, '')
end

def normalize_problem_path reported_path, source_file

A comment preceded and followed by blank lines indicates that it references or labels multiple subsequent blocks. (Or it is be part of a series of such comments that tend to and in its own case may yet still cover multiple blocks each.)

This categorizes sections for user convenience. It also helps LLM-backed tools to find relevant sections more easily.

# Try to convert absolute path back to relative path
if missing_path =~ %r{/home/[^/]+/[^/]+/work/[^/]+/(.+)$} ||
    missing_path =~ %r{/([^/]+/[^/]+\.adoc)$}
  @path = Regexp.last_match(1)
end

Summarizing a complex Regex pattern is vital. Conveying the intent of the pattern is far more important than explaining its mechanics.

Style

Expository comments have a subject: the code they refer to, typically in the form of a line or block. In nearly all cases, comments should immediately precede the subject code.

Example of comment preceding subject code
# Validate all inputs individually
inputs.each do |input|
  # ...
end

In some languages, comments can be placed inline. This should be used sparingly.

We most commonly do this in YAML files.

Example of inline comment in YAML
inputs: # List of inputs to validate
  - input1
  - input2

We also do this in JavaScript files.

Example of inline comment in JavaScript
let count = calculated; // Start with the dynamic value

Examples

Good comment examples
# Calculate the factorial of a number using recursion

# Handle the base case

# Never call factorial with a negative number

# Validate all inputs individually

Good comments are descriptive and purely abstract. They express an instruction and/or a principle to be adhered to or enforced within the subject block.

Bad comment examples (too simple/unnecessary)
# Initialize the result to 1

# Loop through numbers from 1 to n

# Return the result
Bad comment examples (non-imperative form)
# Calculates the factorial of a number

Comment Protocols by Language

Ruby Commenting Protocols

All public-facing methods and classes should be documented with YARD documentation comments.

For expository comments, follow the Principles outlined above.

API Documentation Comments

Many of our Ruby gems provide public APIs that are documented using YARD.

Private methods and classes may also be documented, but this is not required.

Never describe a method just by what it returns or what parameters it takes. Describe what the method does behind the scenes or what its summarized purpose.

When documenting Ruby classes and methods with YARD, follow these patterns:

class descriptions

Keep class descriptions focused on the class’s primary responsibility and role within the system. Avoid overselling capabilities or implementation details.

method descriptions

Lead with what the method accomplishes, not just its signature. Example: "Processes the provided attributes to populate Change properties" rather than "Initializes a new Change object."

capitalization consistency

When referring to class objects conceptually or as an instance (not variable names), use CamelCase names. Use lowercase for most instances where the term refers to a real-world object or concept.

voice consistency

Use descriptive, present-tense “voice” for API documentation and YARD comments.

Exceptions

On rare occasions, comments are used to denote deep nesting in large files.

Annotating end keywords that wrap up large blocks/statements
        end # method my_method
      end # class MyClass
    end # module MyModule
  end # module SuperModule
end # module OurCoolGem

Whenever possible, even when deep nesting is warranted, keep files small enough that such labels won’t be need, all else being equal.

YAML Commenting Protocols

YAML files often contain extensive comments to help users understand the structure and purpose of the data.

Comments should be used to label sections, explain complex structures, and provide hints or assistance for downstream/later users populating data fields.

Examples of YAML comments
# General data
inputs:
  - name: input1 # required
  - name: input2 # optional
config: # Settings for the application itself
  setting1: value1 # Enable feature X (which is not called setting1 and thus needs translation)
body: | # Use AsciiDoc format
  This is content for the body of something.

We sometimes use comments to categorize a large Array or Map for navigation, even if the data is included in all members of the Array.

Example of YAML section label
# POSTS
- slug: first-post
  title: My First Post
  type: post

- slug: second-post
  title: My Second Post
  type: post

# - etc

# PAGES
- slug: about
  title: About Me
  type: page

# - etc

This is used when it makes no sense to nest data under parent keys like posts: and pages:, yet users will still need to navigate through large collections.