Vasu Patel logoVasu Patel
← Clean by Default: Coding Standards
All chapters in this track
  1. 01Chapter 1: Why Coding Standards Matter: Readability, Onboarding, Defects, Consistency at Scale
  2. 02Chapter 2: Naming Conventions
  3. 03Chapter 3: Formatting and Style
  4. 04Chapter 4: Comments and Self-Documenting Code
  5. 05Chapter 5: Error Handling Conventions
  6. 06Chapter 6: Code and Project Organization (Files, Modules, Packages)
  7. 07Chapter 7: Writing Testable Code
  8. 08Chapter 8: Commit Hygiene: Atomic Commits, Messages, PR-Sized Changes
  9. 09Chapter 9: Language-Specific Idioms and Anti-Patterns Across TypeScript and Python
  10. 10Chapter 10: Security-Conscious Basics: Input Validation, Secrets Handling, Injection Risks
  11. 11Chapter 11: Enforcing Standards Automatically: Linters, Formatters, CI Gates
  12. 12Chapter 12: Creating, Documenting, and Evolving a Team Style Guide (Exceptions and Legacy Code)
  13. 13Chapter 13: Worked Example: Refactoring a Messy Function to Standard
  14. 14Chapter 14: Worked Example: Drafting a Style Guide Section From Scratch
  15. 15Chapter 15: Common Interview Questions About Coding Standards and Code Quality

Chapter 2 of 15

Chapter 2: Naming Conventions

Why this matters

A name is the single smallest unit of documentation in any codebase, and it's also the most frequently encountered — every variable, function, and class name is read far more often than any comment near it. Getting naming right has an outsized effect on readability precisely because of this sheer frequency: a slightly-too-long-but-clear name costs a reader nothing extra, while a short-but-ambiguous name costs a small amount of confusion multiplied by every single read.

The core concept: a name should answer its own questions

[BEGINNER] A good name answers, without needing a comment: what does this hold, or what does this do, and (for booleans and functions with side effects) what condition or effect does it represent. A name that requires a comment to explain what it means is a sign the name itself has failed at its one job.

Before — names that raise more questions than they answer:

function proc(d: Data[], f: boolean): Data[] {
  const r = d.filter(x => x.s === 1);
  return f ? r.reverse() : r;
}

After — names that make the comment unnecessary:

function filterActiveRecords(records: Record[], shouldReverseOrder: boolean): Record[] {
  const activeRecords = records.filter(record => record.status === Status.Active);
  return shouldReverseOrder ? activeRecords.reverse() : activeRecords;
}

Nothing about the logic changed between these two versions — only the names. The second version tells a reader what's happening without requiring them to trace through the function body and reverse-engineer what s === 1 means or what f controls.

# Before
def proc(d, f):
    r = [x for x in d if x.s == 1]
    return list(reversed(r)) if f else r

# After
def filter_active_records(records, should_reverse_order):
    active_records = [record for record in records if record.status == Status.ACTIVE]
    return list(reversed(active_records)) if should_reverse_order else active_records

Specific naming conventions worth standardizing

[BEGINNER]

ElementConventionExample
BooleansPrefix with is, has, should, canisActive, hasPermission, shouldRetry
FunctionsVerb phrases describing the actioncalculateTotal, validateInput, fetchUser
CollectionsPlural nounsusers, activeOrders (not userList, which is redundant with the type)
ConstantsLanguage-idiomatic (TypeScript: UPPER_SNAKE_CASE for true constants; Python: UPPER_SNAKE_CASE)MAX_RETRY_COUNT, DEFAULT_TIMEOUT_MS
ClassesNoun phrasesOrderProcessor, UserRepository

[IN PRACTICE] The boolean-prefix convention (is/has/should/can) deserves special emphasis because its payoff is so immediate: if (active) requires the reader to infer this is a boolean and guess what "active" being true or false means; if (isActive) requires zero inference — the name itself states both the type and the meaning.

Naming's biggest trap: names that lie

[SENIOR INSIGHT] A misleading name is worse than a vague one — a vague name (data, result) signals "I don't know what this is," prompting a reader to investigate; a misleading name (userList that's actually a Set, or getUser that has a side effect of also creating a session) actively lies to the reader, who will trust it and reason incorrectly as a result. Whenever a name and the code's actual behavior diverge, fix the name or the code — never leave the mismatch, since a reader has no way to detect it without already knowing the bug exists.

// A name that LIES: "get" implies a pure read, but this function mutates state.
function getUser(id: string): User {
  logAccessAttempt(id);   // a SIDE EFFECT hidden behind a "get" name
  incrementAccessCount(id); // ANOTHER side effect
  return db.find(id);
}

// Either the name should reflect the side effects, or the side effects should be removed:
function getUserAndRecordAccess(id: string): User {
  logAccessAttempt(id);
  incrementAccessCount(id);
  return db.find(id);
}
// OR, better: separate the pure read from the side effects entirely, letting
// the caller decide whether recording access is actually wanted in this context.

Naming length: the "scope size" heuristic

[SENIOR INSIGHT] A useful, often-overlooked rule: a name's appropriate length correlates with the size of its scope. A loop index used only within three lines (for (let i = 0; i < 10; i++)) doesn't need a descriptive name — i is fine, because its entire lifetime and meaning is visible in three lines. A field on a class, visible and used throughout a large file (or, if public, throughout an entire codebase), deserves a fully descriptive name, because a reader encountering a use of it far from its declaration has no nearby context to lean on.

// Fine: `i`'s entire scope is visible in one glance.
for (let i = 0; i < items.length; i++) {
  process(items[i]);
}

// NOT fine: a class field named `x` used throughout a 500-line file forces
// every reader, at every use site far from the declaration, to scroll back
// to remember what `x` means.
class OrderProcessor {
  private x: number;  // should be `retryCount`, `pendingOrderCount`, or similar
}

Common mistakes

  1. Using abbreviations to save typing (calcTot, usrRepo) — modern editors autocomplete, so the typing savings are negligible, while the readability cost is paid by every future reader, indefinitely.
  2. Letting a name become a lie over time — a function named validateAndSave that later has its validation logic removed, but keeps its old name, actively misleads every caller into believing validation still happens.
  3. Using a short, cryptic name for something with a large scope ("it's just a local variable" reasoning applied to a class field or module-level constant, where the "local" scope is actually the whole file or codebase).
  4. Inconsistent naming for the same concept across a codebase (userId in one file, user_id in another, uid in a third, all referring to the same thing) — this is exactly what a documented, enforced naming convention (Chapters 11-12) exists to prevent.

Checklist: naming well

  1. Ask "does this name need a comment to explain it?" If yes, improve the name first — a comment explaining what a name means is a strong signal the name itself failed.
  2. Use the is/has/should/can prefix convention for booleans, consistently, across the whole codebase.
  3. Scale name length to scope size — short names for tiny, immediately-visible scopes; fully descriptive names for anything with a scope larger than a few lines.
  4. Whenever a name and the code's actual behavior diverge, fix one or the other immediately — never leave a name that lies about what the code does.
  5. Establish and enforce (via linting where possible, Chapter 11) a single, consistent naming convention per concept across the entire codebase.

Discussion / interview questions

  1. "Why does naming matter as much as it does for code quality?" Strong answer: A name is the smallest, most frequently-encountered unit of documentation in a codebase — a good name eliminates the need for a comment and reduces cognitive load on every single read, and since code is read far more than written (Chapter 1), this small, repeated saving compounds significantly over a codebase's lifetime.

  2. "What's worse: a vague variable name, or a misleading one? Why?" Strong answer: A misleading name is worse — a vague name signals uncertainty, prompting a reader to investigate further; a misleading name actively lies, causing a reader to reason incorrectly with false confidence, since they have no signal that the name doesn't match the actual behavior.

  3. "How would you decide how descriptive a variable's name needs to be?" Strong answer: Scale name length/descriptiveness to the size of the variable's scope — a name used and fully visible within a few lines needs minimal description; a name used across a large scope (a class field, a module-level value) needs to be fully self-explanatory, since readers encountering distant use sites have no nearby context.

  4. "You find a function named getUser that has side effects (like logging or mutating state). What would you do?" Strong answer: Flag the mismatch and propose a fix — either rename the function to reflect its actual side effects, or (preferably) refactor to separate the pure read from the side effects entirely, since a "get"-named function that silently mutates state is exactly the kind of misleading name that causes real bugs when callers trust the name's implied contract.

Chapter summary / cheat sheet

  • Code is read far more than written — a name is the smallest, most frequent unit of documentation, so getting it right has an outsized, compounding effect.
  • Use is/has/should/can prefixes for booleans, verb phrases for functions, plural nouns for collections, and consistent casing conventions for constants — apply these consistently across the whole codebase.
  • A misleading name (one that doesn't match actual behavior) is worse than a vague one — fix the mismatch immediately, in either direction.
  • Scale name descriptiveness to scope size — short names for tiny, fully-visible scopes; fully descriptive names for anything with a wider scope.
  • If a name needs a comment to explain it, improve the name first.