# Extract Variable

> Name a hard-to-read expression or sub-expression by assigning it to a well-named local variable.

- kind: technique
- category: composing-methods
- aliases: Introduce Explaining Variable
- canonical: https://aipatterns.dev/refactoring/techniques/extract-variable
- inspired-by: https://refactoring.guru/extract-variable

## Problem

A condition or calculation packs several ideas into one expression. You have to evaluate it in your head to learn what it checks.

## Solution

**Assign each meaningful part of the expression to a local variable whose name says what that part means.** Then build the original expression from those names.

## Before

```ts
function canBookRoom(user: User, room: Room, slot: Slot, now: Date): boolean {
  return (
    (user.role === "admin" || user.teamId === room.ownerTeamId) &&
    slot.start.getTime() - now.getTime() >= 15 * 60_000 &&
    slot.end.getTime() - slot.start.getTime() <= room.maxBookingMinutes * 60_000 &&
    !room.maintenanceWindows.some((w) => w.start < slot.end && slot.start < w.end)
  );
}
```

## After

```ts
function canBookRoom(user: User, room: Room, slot: Slot, now: Date): boolean {
  const hasAccess = user.role === "admin" || user.teamId === room.ownerTeamId;
  const leadTimeMs = slot.start.getTime() - now.getTime();
  const bookedFarEnoughAhead = leadTimeMs >= 15 * 60_000;
  const durationMs = slot.end.getTime() - slot.start.getTime();
  const withinMaxDuration = durationMs <= room.maxBookingMinutes * 60_000;
  const clashesWithMaintenance = room.maintenanceWindows.some(
    (w) => w.start < slot.end && slot.start < w.end,
  );

  return hasAccess && bookedFarEnoughAhead && withinMaxDuration && !clashesWithMaintenance;
}
```

## Why

- The return line now reads as the business rule.
- Debuggers and log statements can inspect each named part.
- It is a cheap first step. If a name proves useful beyond this function, promote it to a method later.

## Steps

1. Pick a sub-expression that has a clear meaning and no side effects.
2. Declare a `const` with a descriptive name and assign the sub-expression to it, placed before the first use.
3. Replace the sub-expression with the variable. Run the tests.
4. Repeat for other parts, working from the innermost meaningful pieces outward.

## Watch out

- Short-circuit evaluation changes. In the original, `!room.maintenanceWindows.some(...)` never ran if access failed. Hoisting it into a variable runs it every time. That is harmless for pure checks but wrong if a part throws, is expensive, or has side effects. Keep such parts inline or extract them as functions.
- If the same name would help in other functions, prefer [Extract Method](https://aipatterns.dev/refactoring/techniques/extract-method.md) or [Replace Temp with Query](https://aipatterns.dev/refactoring/techniques/replace-temp-with-query.md) so the logic is shared.
- Don't name things that are already obvious (`const sum = a + b`).
- The inverse is [Inline Temp](https://aipatterns.dev/refactoring/techniques/inline-temp.md).

## Related

- Fixes [Comments](https://aipatterns.dev/refactoring/smells/comments.md) that explain an expression and part of [Long Method](https://aipatterns.dev/refactoring/smells/long-method.md).
- Inverse: [Inline Temp](https://aipatterns.dev/refactoring/techniques/inline-temp.md).
- Escalate to [Extract Method](https://aipatterns.dev/refactoring/techniques/extract-method.md) when a name is needed in more than one place.

## Agent checklist

- [ ] Each extracted part has no side effects, or its evaluation order and count are unchanged.
- [ ] Short-circuit guards that protected a later part (null checks, expensive calls) still protect it.
- [ ] Variables are `const` and named for meaning, not for type.
- [ ] Tests pass with identical results.
