PushBackLog

Meaningful Names

Soft enforcement Complete by PushBackLog team
Topic: quality Topic: supportability Skillset: any Technology: generic Stage: execution Stage: review

Meaningful Names

Status: Complete
Category: Clean Code
Default enforcement: Soft
Author: PushBackLog team


Tags

  • Topic: quality, supportability
  • Skillset: any
  • Technology: generic
  • Stage: execution, review

Summary

Names for variables, functions, classes, and modules should clearly reveal their intent. A reader should be able to understand what something is and what it does from its name alone, without reading its implementation.


Rationale

Code is read far more than it is written

A well-cited estimate is that for every line of code written, it is read ten times or more — during review, debugging, refactoring, and onboarding. Naming is the primary mechanism by which intent is communicated across time and between people. A good name is documentation that cannot go stale, because it is the code.

Robert C. Martin puts it bluntly in Clean Code: “The name of a variable, function, or class should answer all the big questions. It should tell you why it exists, what it does, and how it is used. If a name requires a comment, then the name does not reveal its intent.”

Cognitive load and naming

Poor names force the reader to maintain a mental substitution table while reading: “whenever I see x, I must remember it means cartItemCount.” Every such substitution consumes working memory that should be spent understanding the logic. Well-named code is low-density cognitive labour: the name does the work of explanation.

Naming as design feedback

Difficulty naming a function is a signal about the function itself. If you can’t find a single, clear name, the function is probably doing more than one thing. Awkward names — processAndValidateAndSave, handleThings — are design feedback: split the function until each piece can be named cleanly.


Guidance

Rules for variable names

PrincipleBadGood
Reveal intentddaysUntilExpiry
Avoid disinformationaccountsList (if it’s a Map)accountsById
Avoid encodingsstrName, iCountname, count
Distinguish meaningfullydata1, data2sourceUser, targetUser
PronounceablegenymdhmsgeneratedTimestamp

Rules for function names

  • Verbs for actions: createUser, calculateDiscount, sendNotification
  • Questions return booleans: isExpired(), hasPermission(), canCheckout()
  • Say what, not how: getActiveUsers() not queryDatabaseForUsersWhereActiveTrue()
  • Avoid context repetition: if the class is UserService, UserService.getUser() is redundant — UserService.findById() is cleaner

Rules for class and module names

  • Nouns for entities: Order, PaymentGateway, UserProfile
  • Avoid Manager, Processor, Handler, Helper, Util — these names signal missing design; what specifically does it manage?
  • One concept per name: if a class needs “and” in its description (“validates and sends emails”), split it

Length guidelines

Name length should be proportional to scope. A loop variable i is acceptable in a three-line loop where i is never re-used. A class-level field holding a business concept should be descriptive. Variables in tight algorithms can be shorter; variables in business logic should be explicit.


Examples

Before: cryptic

function proc(d: any[], f: boolean): any[] {
  return d.filter(x => f ? x.a : !x.a);
}

What is d? What is f? What is a? What does proc do?

After: self-documenting

function filterOrdersByActiveStatus(
  orders: Order[],
  includeActive: boolean
): Order[] {
  return orders.filter(order =>
    includeActive ? order.isActive : !order.isActive
  );
}

The same logic, but the name, parameter names, and type reveal intent entirely without a comment.

Boolean flag trap

// What does true mean? Only the implementation can tell you.
render(user, true, false, true);

// Better: use an options object or named constants
render(user, { showAvatar: true, isAdmin: false, canEdit: true });

Anti-patterns

1. Single-character names outside tight loops

u, d, t for user, data, and token are acceptable for 2-line functions but deadly in multi-page methods where they make reading impossible.

2. Abbreviations that save keystrokes, cost comprehension

usrMgr, acctLst, genDt — saves nothing; forces constant mental decryption.

3. Implementation names rather than intent names

sendHttpPostToEmailEndpoint describes how; sendWelcomeEmail describes what. The what name is always better.

4. Container filler words

theUser, aList, tempData, myString — the prefix adds nothing. user, items, payload.

5. Lying names

A variable named userList that is actually a Map, or a function named isValid that also fixes invalid data. Names that misrepresent are worse than cryptic names: they actively mislead.

6. Context-free names in a broader scope

id, name, value, data as class fields or module-level exports. Outside a tight local scope, these names carry no information about what they represent.



Part of the PushBackLog Best Practices Library. Suggest improvements →