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 sizex
,y
,z
for coordinatese
for an exception in a catch blockT
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
- Numbered Variables:
student1
,student2
→ use an array orstd::vector
- Hungarian Notation:
strName
,iCount
→ the type system handles these - Meaningless Distinctions:
ProductInfo
vs.ProductData
→ pick one - “Cute” Names:
whack()
instead ofkill()
→ be professional - Mental Gymnastics Required:
xsq
for “x squared” → just usexSquared
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.)