Units, Context, and Encoding in Names
In 1999, NASA's Mars Climate Orbiter disintegrated in the Martian atmosphere. The cause: one team calculated thrust in pound-seconds, another expected newton-seconds. The variable was just called thrust.
If it had been called thrustPoundSeconds or thrustNewtonSeconds, someone would have noticed.
Units in names save missions. They also save production incidents.
Include Units in Names
When a variable represents a quantity, include the unit:
| Vague | Clear |
|---|---|
timeout | timeoutMs, timeoutSeconds |
delay | delayMs, retryDelaySeconds |
size | sizeBytes, sizeMB, sizeKB |
price | priceInCents, priceDollars |
distance | distanceMeters, distanceMiles, distanceKm |
weight | weightGrams, weightKg, weightPounds |
duration | durationMs, durationMinutes, durationDays |
This prevents unit conversion bugs—one of the most common and hard-to-catch bug categories.
Real Example
// Bug waiting to happen
function setSessionTimeout(timeout) {
this.timeoutId = setTimeout(expire, timeout);
}
// Called with seconds, but setTimeout expects milliseconds
setSessionTimeout(30); // Expires in 30ms, not 30s!
Fixed with unit-explicit naming:
function setSessionTimeoutSeconds(timeoutSeconds) {
const timeoutMs = timeoutSeconds * 1000;
this.timeoutId = setTimeout(expire, timeoutMs);
}
setSessionTimeoutSeconds(30); // Obviously 30 seconds
Now the name documents the expected unit, and the conversion is explicit.
State and Status Prefixes
Prefixes can encode important context about a value's state:
raw — Unprocessed, potentially unsafe
const rawUserInput = request.body.comment;
const sanitizedComment = sanitize(rawUserInput);
Anyone reading rawUserInput knows: this hasn't been validated or sanitized. Don't put it in the database or render it directly.
safe — Validated/sanitized
const safeHtml = sanitizeHtml(rawHtml);
document.innerHTML = safeHtml; // OK to use
cached — From cache, might be stale
const cachedUser = userCache.get(userId);
const freshUser = await fetchUser(userId);
validated — Passed validation
const validatedEmail = validateAndNormalizeEmail(rawEmail);
partial — Incomplete data
const partialOrder = { items: [...], /* missing shipping address */ };
Encoding Safety Information
Some of the worst bugs come from mixing safe and unsafe data. Names can prevent this.
SQL Injection Prevention
// Dangerous: Is this escaped?
const query = `SELECT * FROM users WHERE name = '${name}'`;
// Clear: The name tells you
const escapedName = escapeSQL(userProvidedName);
const query = `SELECT * FROM users WHERE name = '${escapedName}'`;
XSS Prevention
// Dangerous: Is this sanitized?
element.innerHTML = content;
// Clear: The name documents safety
const sanitizedContent = DOMPurify.sanitize(userContent);
element.innerHTML = sanitizedContent;
Encoding Conventions
Some teams use naming conventions for safety:
unsafeHtml— raw, potentially malicioussafeHtml— sanitized, safe to rendertrustedHtml— from trusted source, no sanitization needed
The convention doesn't matter. Consistency does.
Scope-Appropriate Length
Name length should match scope size.
Tiny Scope: Short Names OK
// 2-line loop: i is fine
for (let i = 0; i < items.length; i++) {
process(items[i]);
}
// Single-use lambda: short parameter OK
users.filter(u => u.isActive);
Medium Scope: Descriptive
function calculateTax(order) {
const subtotal = order.items.reduce((sum, item) => sum + item.price, 0);
const taxRate = getTaxRate(order.shippingAddress);
const taxAmount = subtotal * taxRate;
return taxAmount;
}
Large Scope: Very Explicit
class OrderProcessor {
private readonly maximumRetryAttempts = 3;
private readonly retryDelayMilliseconds = 1000;
private readonly connectionTimeoutSeconds = 30;
}
Module/Global Scope: Full Context
const DEFAULT_SESSION_TIMEOUT_MINUTES = 30;
const MAX_FILE_UPLOAD_SIZE_BYTES = 10 * 1024 * 1024;
const API_RATE_LIMIT_REQUESTS_PER_MINUTE = 100;
Encoding Important Constraints
Names can document constraints that would otherwise require comments:
// Instead of a comment
// Note: this is 1-indexed
const pageNumber = 1;
// Encode it in the name
const oneIndexedPageNumber = 1;
// Or use domain language
const humanPageNumber = 1; // As displayed to user (1-indexed)
const arrayIndex = humanPageNumber - 1; // For array access (0-indexed)
Context from Container
You don't need to repeat context that's already clear from the container:
// Redundant
class User {
userName: string;
userEmail: string;
userCreatedAt: Date;
}
// Better: context is provided by class
class User {
name: string;
email: string;
createdAt: Date;
}
But when the variable leaves its container, add context back:
// Inside User class: fine
this.email
// Outside User class: need context
const userEmail = user.email;
const orderEmail = order.contactEmail;
Key insight: Names can encode critical safety information. Units prevent conversion bugs. Prefixes like raw, safe, and cached prevent security bugs and stale data bugs. Make the name carry the warning.