CS 70

The Art of Choosing Good Names

The Mechanical Rules (Style Conventions)

First, let's establish our consistent style conventions.

Thing Format Examples
Local Variables and Functions camelCase studentCount
calculateGrade()
Class Data Members camelCase_
(with trailing underscore)
size_
currentCapacity_
Class Names PascalCase StudentRecord
BinarySearchTree
Constants ALL_CAPS_WITH_UNDERSCORES MAX_BUFFER_SIZE
PI

The Art of Good Naming

Principle 1: Match Name Length to Scope

The broader the scope, the more descriptive the name should be.

// GOOD: Short name for short scope
for (size_t i = 0; i < values.size(); ++i) {
    std::cout << values[i] << std::endl;
}

// GOOD: Descriptive name for broader scope
class GradeCalculator {
private:
    double homeworkWeight_;  // Clear across entire class
    double examWeight_;
};

// BAD: Too verbose for tiny scope
for (size_t indexIntoTheValuesArray = 0; indexIntoTheValuesArray < values.size(); ++indexIntoTheValuesArray) {
    std::cout << values[indexIntoTheValuesArray] << std::endl;
}

// BAD: Too cryptic for broad scope
double hw_;  // What's "hw"? Seen across entire class

Principle 2: Names Should Express Intent, Not Implementation

Tell the reader what something represents, not how it's stored.

// GOOD: Says what it represents
size_t numStudentsEnrolled;
bool isValidInput;

// BAD: Describes the type, not the purpose
int intValue;
std::vector<string> stringVector;

// Exception: When the type IS the point (e.g., in generic code)
template<typename T>
void swap(T& first, T& second);  // "first" and "second" are fine here

Principle 3: Use Domain Conventions Where They Exist

Some single letters have strong conventional meanings:

  • i, j, k for loop indices (especially nested loops)
  • n for a count or size
  • x, y, z for coordinates
  • e for an exception in a catch block
  • T for a template type parameter
// GOOD: Using conventions
for (size_t i = 0; i < rows; ++i) {
    for (size_t j = 0; j < cols; ++j) {
        matrix[i][j] = 0;
    }
}

// UNNECESSARY: Fighting convention
for (size_t rowIndex = 0; rowIndex < rows; ++rowIndex) {
    for (size_t colIndex = 0; colIndex < cols; ++colIndex) {
        matrix[rowIndex][colIndex] = 0;
    }
}

Principle 4: Be Precise, Not Just Descriptive

Avoid vague words such as “data”, “info”,“temp”, or “result” without qualification.

// VAGUE
string data;
int result;
double temp;

// PRECISE
string studentName;
int examScore;
double temporarySum;  // or just "sum" if the temporary nature is obvious

Principle 5: Avoid Ambiguity

Names should have one clear interpretation.

// AMBIGUOUS: Is filter keeping or removing the premium users?
std::vector<User> filterPremiumUsers(std::vector<User> users);

// CLEAR
std::vector<User> keepOnlyPremiumUsers(std::vector<User> users);
std::vector<User> removePremiumUsers(std::vector<User> users);

// AMBIGUOUS: Number of students? Student ID number?
int studentNumber;

// CLEAR
int studentCount;
int studentId;

Principle 6: Use Searchable Names

Single letters and numbers are hard to search for in code.

// HARD TO SEARCH: What does 7 mean?
if (daysSinceLastLogin > 7) {
    markAsInactive();
}

// SEARCHABLE
constexpr int DAYS_UNTIL_INACTIVE = 7;
if (daysSinceLastLogin > DAYS_UNTIL_INACTIVE) {
    markAsInactive();
}

Principle 7: Don't Use Mental Mapping

Readers shouldn't have to mentally translate your names.

// BAD: Reader must remember "d" means days
int d = getDaysSinceModified();

// GOOD: Self-documenting
int daysSinceModified = getDaysSinceModified();

Exception: If we used d in the very next line and then we didn't use it again, Principle 1 would apply and it would be fine to use a short name.

Principle 8: Consistency Trumps Personal Preference

If the codebase uses size for container sizes, don't switch to length or count.

// If the codebase uses this pattern:
size_t getSize() const;

// Don't introduce:
size_t getLength() const;  // Same concept, different name

Common Naming Patterns

Boolean Names

Start with is, has, can, or similar; for example,

  • isEmpty, hasChildren, canWrite, shouldUpdate

Function Names

Use strong verbs for actions, nouns/adjectives for queries.

  • Actions: calculateTotal(), sendEmail(), validateInput()
  • Queries: size(), isEmpty(), student()

Paired Concepts

Use symmetric names.

  • begin/end, first/last, open/close, show/hide
  • Not begin/last, open/destroy

Red Flags to Avoid

  1. Numbered Variables: student1, student2 → use an array or std::vector
  2. Hungarian Notation: strName, iCount → the type system handles these
  3. Meaningless Distinctions: ProductInfo vs. ProductData → pick one
  4. “Cute” Names: whack() instead of kill() → be professional
  5. Mental Gymnastics Required: xsq for “x squared” → just use xSquared

The Golden Rule

A good name allows a reader to understand the code's purpose without reading its implementation.

When in doubt, imagine you're explaining your code to a classmate over the phone. The names you'd naturally use in that explanation are probably the right ones for your code.

(When logged in, completion status appears here.)