Developers comment their code? This article is a joke, right?
Commenting code is a practice that is not always taken seriously. With generative AI, however, entire code bases can be commented by an LLM. This approach removes challenges such as time constraints and the need to have the developer who wrote the code be involved. The question then becomes how to go about it and what standardizations to implement. Standarization alone makes it a pattern.
The Explainer
Pattern Considerations
Good commenting is driven by consistent patterns. Effective commenting patterns address defined needs at the file, section, functional, and line levels.
In traditional development, well-crafted comments enhance readability and make code easier to maintain. In an AI-enabled world, comments also serve as structured context that can assist automated tools in understanding the intent and purpose of code, making clear, readable comments more valuable than ever.
When defining comment requirements for your projects, keep the following in mind:
• Create well-structured About sections at the top of each file, and don’t hesitate to include detailed information such as file purpose, usage examples, and platform-specific instructions.
• Use section headers to clearly convey “The What”—what the section or block of code is doing.
• Reserve “The Why” for function and line-level comments, where the reasoning behind the code’s logic and implementation choices is most critical.
Code Example
package main
import (
"fmt"
"math/rand"
"strings"
"sync"
"time"
)
/*
* ===================================================================================
* ABOUT: Random Password Generator
* ===================================================================================
*
* Version: <version>
* Date: <current date>
* Author: <author>
*
* Description:
* This Go program generates 4 random passwords of 10 characters in length each.
* The passwords are composed of numbers, uppercase letters, lowercase letters,
* and punctuation marks. Each password is generated in a separate goroutine to
* demonstrate how to scale concurrent password generation using Go's goroutines
* and WaitGroup.
*
* ===================================================================================
* Usage:
*
* 1. Compile and run the program:
* go run password_generator.go
*
* 2. Each generated password will be printed out from a separate thread:
* Password from thread 1: Wq9@u!f4Hz
* Password from thread 2: t8*Jd#a7Ll
* Password from thread 3: Mv&9Ep2oZ#
* Password from thread 4: Pk6%AnbV3!
* ===================================================================================
*/
// ===================================================================================
// FUNCTION DEFINITIONS
// ===================================================================================
// GeneratePassword generates a random password of 10 characters consisting of numbers,
// letters (both uppercase and lowercase), and punctuation marks.
func GeneratePassword() string {
rand.Seed(time.Now().UnixNano())
// Define the characters allowed in the password.
characters := "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
digits := "0123456789"
punctuation := "!@#$%^&*()-_=+[]{};:,.<>/?"
allChars := characters + digits + punctuation
length := 10
var password strings.Builder
// Loop 10 times to construct a password of 10 characters.
for i := 0; i < length; i++ {
randomChar := allChars[rand.Intn(len(allChars))]
password.WriteByte(randomChar)
}
// Return the generated password as a string.
return password.String()
}
// generatePasswordInThread generates a password in a separate goroutine and prints the result.
func generatePasswordInThread(wg *sync.WaitGroup, id int) {
defer wg.Done()
// Generate the password and print it with the thread ID.
password := GeneratePassword()
fmt.Printf("Password from thread %d: %s\n", id, password)
}
func main() {
var wg sync.WaitGroup
// Number of passwords to generate.
numPasswords := 4
wg.Add(numPasswords)
// Start 4 goroutines to generate passwords concurrently.
for i := 1; i <= numPasswords; i++ {
go generatePasswordInThread(&wg, i)
}
// Wait for all goroutines to finish.
wg.Wait()
}
History
Commenting computer software code dates back to the early days of programming in the 1950s and 1960s when languages like Assembly, Fortran, and COBOL were first developed. As code became more complex, comments were used to explain algorithms and provide guidance for future developers. Early programming practices often had minimal documentation, as software was primarily developed for specific hardware or limited in scope. With the rise of larger projects and more collaborative environments in the 1980s, comments became more structured, focusing on readability and maintainability to support teams working together.
In the 1990s and 2000s, the introduction of object-oriented programming and open-source development further emphasized the importance of commenting. Tools like Javadoc, PHPDoc, and Doxygen emerged to generate documentation directly from code comments, making them even more integral to the development process. Alongside this, inline comments, block comments, and documentation comments became standard practices for describing functions, classes, and methods. Today, comments are essential for ensuring that code is understandable, maintainable, and reusable, especially in larger systems and collaborative environments.
Section Strategy
About Section
About sections offer a valuable opportunity to document key details about your code directly within source files. While centralized documentation, like a project wiki, is great for maintaining comprehensive, project-wide information, it’s crucial to keep the developer’s workflow in mind. When developers are working in the code, easy access to file structure, function arguments, usage examples (such as cURL commands), and platform-specific compile instructions in a well-organized About section can significantly streamline their work and save time.
A comprehensive About section provides an easily accessible reference for crucial information, eliminating the need to switch between the code and external documentation. When your code is well-structured and thoroughly documented in these sections, it reduces the need for frequent clarification or additional references. This contributes to smoother, more efficient development cycles by allowing developers to quickly grasp the code’s structure and intent without unnecessary interruptions.
/*
* ===================================================================================
* ABOUT: Random Password Generator
* ===================================================================================
*
* Version: <version>
* Date: <current date>
* Author: <author>
*
* Description:
* This Go program generates 4 random passwords of 10 characters in length each.
* The passwords are composed of numbers, uppercase letters, lowercase letters,
* and punctuation marks. Each password is generated in a separate goroutine to
* demonstrate how to scale concurrent password generation using Go's goroutines
* and WaitGroup.
*
* ===================================================================================
* Project Structure:
*
* ├── main.go // Entry point for the application
* ├── output.go // Handles output formatting and display
* ├── config.json // Configuration file for the project settings
* ├── common/ // Package for shared utilities and components
* │ ├── config.go // Logic for loading and handling configuration
* ├── utils/ // Utility functions used across the project
* │ └── cli-client.go // Command-line client for interacting with the system
*
* ===================================================================================
* Compilation Options:
*
* 1. Ubuntu (64-bit):
* GOOS=linux GOARCH=amd64 go build -o passwordgen main.go
*
* 2. Raspberry Pi (ARM architecture):
* GOOS=linux GOARCH=arm GOARM=7 go build -o passwordgen main.go
*
* 3. macOS M1, M3 (Apple Silicon):
* GOOS=darwin GOARCH=arm64 go build -o passwordgen main.go
*
* ===================================================================================
* Usage Examples:
*
* 1. Compile and run the program:
* go run main.go
*
* 2. Generate and display passwords in table format:
* ./passwordgen --format table
*
* 3. Generate and display passwords in CSV format:
* ./passwordgen --format csv
*
* 4. Generate and display passwords in JSON format:
* ./passwordgen --format json
*
* ===================================================================================
* config.json Example:
*
* {
* "password_length": 10
* }
* ===================================================================================
*/
Section Headers
Section headers play a critical role in explaining The What of a particular block of code, offering developers a clear, high-level understanding of the purpose and functionality of that section. By using concise, descriptive headers, you provide context at a glance, allowing anyone reading the code to quickly grasp what the upcoming section is intended to do. Well-written section headers improve code readability, making it easier to navigate through larger files and understand the overarching structure without needing to dive into the specifics of each function or line. This practice enhances both collaboration and maintainability by making the code more approachable and easier to comprehend.
Function and Line Level Comments
Function and line-level comments are essential for explaining The Why behind specific code decisions, offering deeper insight into the reasoning and logic of the implementation. While the code itself may show how something is being done, these comments clarify why certain approaches or algorithms were chosen, helping others understand the intent behind the code. By providing context at the function and line level, you ensure that future developers, or even your future self, can quickly grasp the purpose of each decision, making the code easier to modify, debug, and maintain. These comments serve as a critical tool for bridging the gap between code functionality and developer intent.
Prompting Considerations
Consider collaborating with team members on the exact prompts structure to use for About, Section, and Function/Line commenting strategies. LLM’s are deterministic and without consistent prompting code comments could greatly vary across projects and files. Other considerations include:
- For greenfield code, write code first and comment at the end to reduce load on LLM output. For existing code, have the LLM add comments as a part of its analysis and understanding. This not only helps the LLM but it also helps the developer manually verify if the LLM understood the code
- When code is in its final stages, all About sections can be re-run through an LLM using your official About section prompting instructions. Treat this like a final stage for consistency and clean-up
- Manually review about sections and ASCII file diagrams. Don’t be afraid to paste actual Git directories from the file system and have the LLM compare it to About section commenting
As software development tools improve their adoption of generative AI, much of this guidance will hopefully become automated in your development pipelines. No matter how advanced your development environment becomes, manual verification across some or all source files is always recommended.