Lesson 31 of 54

Variables and State Management

Explanatory Variables

Complex expressions are hard to read. Breaking them into named parts makes them self-documenting.

An explanatory variable is exactly what it sounds like: a variable whose purpose is to explain what a piece of code means.

The Technique

Take a complex expression:

Javascript
if (employee.age >= 65 && employee.yearsOfService >= 20 && employee.healthPlan === 'FULL') {
  applyEarlyRetirement(employee);
}

And break it into named parts:

Javascript
const isRetirementAge = employee.age >= 65;
const hasLongTenure = employee.yearsOfService >= 20;
const hasFullHealthPlan = employee.healthPlan === 'FULL';

const isEligibleForEarlyRetirement = isRetirementAge && hasLongTenure && hasFullHealthPlan;

if (isEligibleForEarlyRetirement) {
  applyEarlyRetirement(employee);
}

Each variable name explains what that part of the expression means.

Why This Works

The Name Documents the Intent

In the first version, you have to figure out what employee.age >= 65 means in context. In the second version, the name isRetirementAge tells you directly.

Each Part Is Testable

You can check each condition independently:

Javascript
console.log('Retirement age?', isRetirementAge);
console.log('Long tenure?', hasLongTenure);
console.log('Full health plan?', hasFullHealthPlan);

Changes Are Localized

If the retirement age changes to 67, you update one line:

Javascript
const isRetirementAge = employee.age >= 67;  // Changed

The rest of the code is unchanged.

Common Applications

Complex Conditionals

Before:

Javascript
if (
  (order.total > 100 && order.customerTier === 'GOLD') ||
  (order.items.length > 10) ||
  (order.hasPromoCode && !order.promoCodeUsed)
) {
  applyDiscount(order);
}

After:

Javascript
const isHighValueGoldCustomer = order.total > 100 && order.customerTier === 'GOLD';
const isBulkOrder = order.items.length > 10;
const hasUnusedPromoCode = order.hasPromoCode && !order.promoCodeUsed;

const qualifiesForDiscount = isHighValueGoldCustomer || isBulkOrder || hasUnusedPromoCode;

if (qualifiesForDiscount) {
  applyDiscount(order);
}

Calculations

Before:

Javascript
const price = basePrice * (1 + taxRate) - (basePrice * discountRate * (isPremium ? 1.5 : 1));

After:

Javascript
const priceWithTax = basePrice * (1 + taxRate);
const discountMultiplier = isPremium ? 1.5 : 1;
const discountAmount = basePrice * discountRate * discountMultiplier;
const price = priceWithTax - discountAmount;

Now you can verify each step.

Array Operations

Before:

Javascript
const result = data
  .filter(x => x.active && x.createdAt > cutoff && !x.flagged)
  .map(x => ({ id: x.id, value: x.amount * x.multiplier }))
  .reduce((sum, x) => sum + x.value, 0);

After:

Javascript
const activeUnflaggedItems = data.filter(item => {
  const isActive = item.active;
  const isRecent = item.createdAt > cutoff;
  const isNotFlagged = !item.flagged;
  return isActive && isRecent && isNotFlagged;
});

const itemValues = activeUnflaggedItems.map(item => ({
  id: item.id,
  value: item.amount * item.multiplier,
}));

const totalValue = itemValues.reduce((sum, item) => sum + item.value, 0);

URL/String Construction

Before:

Javascript
const url = `${apiBase}/${version}/users/${userId}/orders?status=${status}&limit=${limit}${sort ? `&sort=${sort}` : ''}`;

After:

Javascript
const endpoint = `${apiBase}/${version}/users/${userId}/orders`;
const requiredParams = `status=${status}&limit=${limit}`;
const sortParam = sort ? `&sort=${sort}` : '';
const url = `${endpoint}?${requiredParams}${sortParam}`;

The Performance Myth

"But won't extra variables slow things down?"

No. Modern JavaScript engines optimize away local variables. The compiled code is essentially identical.

More importantly: code is read far more often than it runs. Optimize for reading speed first.

If you have genuine performance concerns in a hot path, profile first. You'll almost never find that explanatory variables are the bottleneck.

When to Extract

Extract when:

  • You find yourself re-reading an expression to understand it
  • The expression appears multiple times
  • The expression implements a business rule that deserves a name
  • You want to add a comment explaining the expression (use a variable name instead)

Don't extract when:

  • The expression is already clear: const doubled = x * 2; doesn't need const two = 2;
  • The variable would only be used once in an already-clear context
  • You're over-decomposing simple logic

The "Extract Variable" Refactoring

This is so common that IDEs have shortcuts for it.

  1. Select an expression
  2. Invoke "Extract Variable" (often Ctrl+Alt+V or Cmd+Option+V)
  3. Type the variable name
  4. IDE creates the variable and replaces the expression

Practice this until it's automatic. It's one of the most valuable refactoring moves.

Combining with Functions

Sometimes a variable should be a function:

Variable (Good for Single Use)

Javascript
const isEligible = age >= 18 && hasLicense && !isExpired;
if (isEligible) { }

Function (Good for Reuse and Testing)

Javascript
function isEligibleToDrive(person) {
  return person.age >= 18 && person.hasLicense && !person.licenseExpired;
}

if (isEligibleToDrive(user)) { }

Use functions when:

  • The logic is reused
  • You want to unit test it
  • It takes parameters

Use variables when:

  • It's used once in a local context
  • It's purely for readability

Levels of Extraction

You can extract at different levels:

Level 1: Name the Parts

Javascript
const isOverMinimumAge = user.age >= 18;
const hasValidLicense = user.license && !user.license.isExpired;
if (isOverMinimumAge && hasValidLicense) { }

Level 2: Name the Combination

Javascript
const isOverMinimumAge = user.age >= 18;
const hasValidLicense = user.license && !user.license.isExpired;
const canDrive = isOverMinimumAge && hasValidLicense;
if (canDrive) { }

Level 3: Extract to Function

Javascript
function canDrive(user) {
  const isOverMinimumAge = user.age >= 18;
  const hasValidLicense = user.license && !user.license.isExpired;
  return isOverMinimumAge && hasValidLicense;
}
if (canDrive(user)) { }

Choose the level that best balances clarity and locality.


Key insight: Explanatory variables turn code into documentation. They break complex expressions into named parts that reveal intent. There's no runtime cost, only readability gain. When you're about to write a comment explaining an expression, extract a variable instead.