Choose names that fully and accurately describe what the variable represents
The most important consideration in naming a variable is that the name fully and accurately describes the entity the variable represents.
Core principle: A variable and its name are essentially the same thing. The goodness or badness of a variable is largely determined by its name.
Name quality = Design quality. If you struggle to name something well, that's a warning sign about the design.
Always use when:
Warning signs you need better names:
x, x1, x2, temp, data, info, valProblem-oriented (what it represents) not solution-oriented (how it's implemented):
β
Good: employeeData, printerReady, totalRevenue
β Bad: inputRec, bitFlag, calcVal
The bad names describe computing concepts (input, record, bit, calculation). Good names describe the problem domain (employee, printer, revenue).
Optimal: 10-16 characters average
| Too Long | Too Short | Just Right |
|---|---|---|
numberOfPeopleOnTheUsOlympicTeam |
n, np, ntm |
numTeamMembers, teamMemberCount |
numberOfSeatsInTheStadium |
n, ns, nsisd |
numSeatsInStadium, seatCount |
maximumNumberOfPointsInModernOlympics |
m, mp, max |
teamPointsMax, pointsRecord |
Exception: Short names OK for very limited scope (loop index i in 3-line loop)
i, j acceptableShort name says: "I'm a scratch value with limited scope, don't look for me elsewhere"
Effective technique: state in words what the variable represents. Often that statement IS the best name.
Example:
runningTotal or checkTotalvelocity, trainVelocity, velocityInMphcurrentDate, todaysDatePut qualifiers like Total, Sum, Average, Max, Min, Count at the END:
β
Good: revenueTotal, expenseAverage, pointsMax, customerCount
β Bad: totalRevenue mixed with revenueTotal (inconsistent)
Why:
revenueTotal, revenueAverage, revenueMaxtotalRevenue vs revenueTotal - pick one convention)Exception: Num is ambiguous
numCustomers (count of all customers)customerNum (specific customer number)Count for total, Index for specific: customerCount, customerIndexDon't be clever. Use the ordinary, obvious words:
β
currentDate, employeeName, accountBalance
β cd, empNm, acctBal
Programmers sometimes overlook using ordinary words, which is often the easiest solution.
Names that are too general can be used for anything = not informative:
β Bad: x, temp, data, info, value, variable
β
Good: discriminant, oldRoot, errorMessage, customerInfo, totalRevenue
Generic names acceptable ONLY for very limited scope.
Standard patterns for consistency and clarity:
Place qualifiers at the end of the name:
β
Good: userCount, revenueTotal, temperatureMax, priceAverage, itemsMin
β Bad: totalRevenue mixed with revenueTotal (inconsistent)
Why at end:
revenueTotal, revenueAverage, revenueMaxtotalRevenue and revenueTotalCommon qualifiers: Total, Sum, Average, Max, Min, Count, Index
Use plural names:
β
Good: users, activeCustomers, recentOrders, errorMessages
β Bad: userList, customerArray, orderSet (exposes implementation)
Exception: When type disambiguation helps: userMap, userSet (if you have both in same scope)
Use question form (prefix with is, has, can, should):
β
Good: isValid, hasPermission, canEdit, shouldRetry, wasProcessed
β Bad: valid, permission, edit, retry (not obviously boolean)
Avoid negative booleans: isNotValid is confusing. Use isValid and check !isValid.
Use SCREAMING_SNAKE_CASE for truly constant values:
β
Good: MAX_RETRY_COUNT, DEFAULT_TIMEOUT_MS, API_BASE_URL
Modern alternative: const with regular camelCase (TypeScript, modern JavaScript):
β
Also good: const maxRetryCount = 3
Pick one convention per project, stay consistent.
Distinguish clearly:
userCount, itemTotaluserIndex, currentItemβ Confusing: userNum (is it count or index?)
β
Clear: userCount (total), userIndex (specific)
Minimize or make semantic:
β Bad: temp, tmp, t
β
Good: oldValue, swapBuffer, previousState
If truly temporary and tiny scope (2-3 lines), short is OK. Otherwise, give it semantic meaning.
user_count = 0 # count
current_user_index = 0 # index
is_valid = True # boolean
active_users = [] # collection
MAX_RETRY_COUNT = 3 # constant
const userCount = 0; // count
let currentUserIndex = 0; // index
const isValid = true; // boolean
const activeUsers = []; // collection
const MAX_RETRY_COUNT = 3; // constant
userCount := 0 // count
currentUserIndex := 0 // index
isValid := true // boolean
activeUsers := []User{} // collection
const MaxRetryCount = 3 // exported constant
Principle applies across languages: Name describes what it represents, adapt casing to language conventions.
Use opposites precisely for consistency:
| Opposite Pairs |
|---|
begin / end |
first / last |
locked / unlocked |
min / max |
next / previous |
old / new |
opened / closed |
source / target |
source / destination |
start / stop |
up / down |
get / set |
add / remove |
insert / delete |
show / hide |
create / destroy |
increment / decrement |
Departing from common opposites (like begin/finish instead of begin/end) is confusing.
Never use unless you have explicit, documented reason:
β x, x1, x2 - Always bad (represents unknown quantity)
β temp - What kind of temporary value?
β data - What data?
β val, value - What value?
β foo, bar, baz - Placeholder nonsense
β Single letters except i, j, k for very short loops
β Misspellings or weird abbreviations
β Names with numbers: file1, file2 (use array instead)
β Names differing by only one character: acctNum vs acctNo
Never reuse a variable for multiple purposes:
β Bad:
# temp used for two unrelated purposes
temp = sqrt(b*b - 4*a*c)
root[0] = (-b + temp) / (2 * a)
...
temp = root[0] # Now reused for swapping
root[0] = root[1]
root[1] = temp
β Good:
discriminant = sqrt(b*b - 4*a*c)
root[0] = (-b + discriminant) / (2 * a)
...
old_root = root[0]
root[0] = root[1]
root[1] = old_root
Avoid hidden meanings:
pageCount = number of pages, UNLESS it equals -1, then it means error occurred βcustomerId = customer number, UNLESS > 500000, then subtract 500000 for delinquent account βUse separate variables. Don't overload meaning.
If naming is hard = design is unclear:
| Symptom | Diagnosis | Fix |
|---|---|---|
| Vague name seems OK | Routine does too many things | Break into smaller routines |
| Multiple equally-vague names | Unclear purpose | Clarify requirements |
| Name is long and complicated | Routine is too complex | Simplify design |
| Can't decide between 2 names | Routine has dual purpose | Split into two routines |
| Name keeps changing | Design keeps changing | Stabilize design first |
Don't just accept a bad name. Treat it as a red flag about code quality.
Before accepting a name:
temp, data)?Total, Max, Count)?If any answer is no: improve the name.
From Code Complete research:
x1, x2 prevent understanding relationships between variablesKey insight: "You can't give a variable a name the way you give a dog a nameβbecause it's cute or it has a good sound. A variable and a variable's name are essentially the same thing."
β Before (Bad Names):
x = x - xx
xxx = fido + sales_tax(fido)
x = x + late_fee(x1, x) + xxx
x = x + interest(x1, x)
What does this do? What is x, xx, xxx, fido, x1?
β After (Good Names):
balance = balance - last_payment
monthly_total = new_purchases + sales_tax(new_purchases)
balance = balance + late_fee(customer_id, balance) + monthly_total
balance = balance + interest(customer_id, balance)
Now it's obvious: computing customer bill from balance and new purchases.
Same code, different names, completely different understandability.
For domain-focused naming: See skills/naming-by-domain for architectural naming principles (avoid temporal context like "New"/"Improved", avoid implementation details like "ZodValidator", avoid unnecessary pattern names)
For comment guidelines: See skills/writing-evergreen-comments for keeping comments evergreen