Skip to main content

Software Documentation & Refactoring

Premise: Why Documentation Matters

Documentation is a key component in the maintainability, readability, and usability of software projects. It provides crucial context for future developers, stakeholders, and users.


Types of Documentation

  1. Internal Documentation

    • Written within the code as comments.
    • Includes inline documentation, function headers, and variable explanations.
  2. External Documentation

    • Includes manuals, design documents, user guides, and API documentation.
    • Typically maintained in separate files or documentation systems.

What Must We Document?

  • What is the data?
    • Data source/destination (e.g., database, API)
    • Transaction and input validation logic
  • What is the code doing to the data?
    • Logic behind variable names
    • Explanation of methods, functions, and procedures

Example: Poorly Documented vs Well Documented Code

Poorly Documented:

int foo(int n) {
if (n <= 1)
return 1;
else
return n * foo(n - 1);
}

Well Documented:

/**
* Calculates the factorial of a given integer using recursion.
* @param n The integer for which the factorial is to be calculated.
* @return The factorial of the given integer.
*/
int factorial(int n) {
if (n <= 1)
return 1;
else
return n * factorial(n - 1);
}

Self-Documenting Code

Writing code that explains itself is often more effective than lengthy comments.

Guidelines:

  • Descriptive Naming: Functions and variables should be named clearly (e.g., calculateAverage instead of calcAvg1).
  • Coding Style: Choose and consistently enforce a style guide.
  • Minimal Comments: Use comments only to explain why, not what.

Documentation Extraction Tools

Tools help convert code comments into structured documents:

  • JavaDoc for Java
  • Doxygen for C/C++
  • rdoc for Ruby

These tools use specially formatted comments to generate readable docs.


Your Organization Should Define and Enforce:

  • Naming conventions:
    • Variables: snake_case
    • Functions: camelCase
  • Avoid using numbers for variable differentiation
  • Use standard abbreviations (dept, cust)
  • Maintain modular code with consistent indentation and block structures

Code Structure and Style

Good structure includes:

  • Modular functions
  • Consistent use of braces
  • Clear separation of logic
  • Minimal global state

Fundamental Principles

  • The best documentation is the code itself.
  • Don't document bad code—refactor it instead.

Google Style Guide


Code Refactoring

Refactoring is the process of improving the internal structure of the code without changing its behavior.

Why Refactor?

  • Increase readability
  • Reduce complexity
  • Eliminate duplication

Refactoring Guru: Bloaters


Example: Poorly Written code vs Well Written Code

Poorly Written Code Example

#include<iostream>
using namespace std;

int main() {
int a, b;
cout << "Enter two numbers: ";
cin >> a >> b;
int sum = a+b, sub = a-b, mul = a*b, div = a/b, mod = a%b;
cout << "Sum: " << sum << endl << "Difference: " << sub << endl;
cout << "Product: " << mul << endl << "Division: " << div << endl;
cout << "Modulus: " << mod << endl;
return 0;
}

Refactored Version

#include<iostream>
using std::cout;
using std::cin;
using std::endl;

int add(int a, int b) {
return a + b;
}

int subtract(int a, int b) {
return a - b;
}

int multiply(int a, int b) {
return a * b;
}

double divide(int a, int b) {
if (b == 0) {
cout << "Error: Division by zero." << endl;
return 0;
}
return static_cast<double>(a) / b;
}

int modulus(int a, int b) {
return a % b;
}

int main() {
int num1, num2;

cout << "Enter two numbers: ";
cin >> num1 >> num2;

cout << "Sum: " << add(num1, num2) << endl;
cout << "Difference: " << subtract(num1, num2) << endl;
cout << "Product: " << multiply(num1, num2) << endl;
cout << "Division: " << divide(num1, num2) << endl;
cout << "Modulus: " << modulus(num1, num2) << endl;

return 0;
}


Technical Debt

Like financial debt, technical debt refers to short-term solutions in code that lead to long-term problems.

Causes:

  • Business pressure
  • Lack of documentation and testing
  • Poor collaboration
  • Long-lived development branches
  • Incompetent or rushed decisions

Clean Code Principles

  • Easy for other programmers to read
  • No duplication
  • Fully tested
  • Easy and cost-effective to maintain

When to Refactor

  • When adding new features
  • When fixing bugs
  • During code reviews

How to Refactor

  • Make the code cleaner
  • Avoid changing functionality
  • All tests must pass post-refactor

Reflection Questions

  • Why is version control critical for documentation?
  • What is the primary purpose of inline comments?
  • What kind of documentation serves end users?

Summary

  • Good documentation improves code maintainability by clarifying what the code does, how data is used, and why certain decisions were made—for both internal (comments, naming) and external (manuals, API docs) audiences
  • Self-documenting code and coding standards (clear naming, consistent formatting, modular design) reduce the need for excessive comments and make the code itself a primary source of truth
  • Refactoring and clean code practices help eliminate technical debt, ensuring code remains readable, testable, and easy to update—without adding new features during the cleanup process

Disclaimer: Generative AI was used in part to generate these lecture notes.