# Replace Temp with Query

> Move the expression behind a temporary variable into its own method so every method in the class can ask for the value.

- kind: technique
- category: composing-methods
- canonical: https://aipatterns.dev/refactoring/techniques/replace-temp-with-query
- inspired-by: https://refactoring.guru/replace-temp-with-query

## Problem

A method computes a value into a local variable and uses it later. Other methods in the class compute the same value their own way, and the local makes the long method hard to split because every fragment depends on it.

## Solution

**Extract the expression into a method (a query) with no side effects, and replace the variable with calls to it.** The value is now available anywhere in the class and does not tie fragments together.

## Before

```ts
class Shipment {
  constructor(private parcels: Parcel[], private zone: Zone) {}

  label(): string {
    const billableKg = Math.max(
      this.parcels.reduce((s, p) => s + p.weightKg, 0),
      this.parcels.reduce((s, p) => s + p.volumeCm3, 0) / 5000,
    );
    const fee = billableKg * this.zone.ratePerKg;
    return `${this.zone.code} ${billableKg.toFixed(1)}kg ${fee.toFixed(2)}`;
  }

  needsFreightCarrier(): boolean {
    const actualKg = this.parcels.reduce((s, p) => s + p.weightKg, 0);
    const volumetricKg = this.parcels.reduce((s, p) => s + p.volumeCm3, 0) / 5000;
    return Math.max(actualKg, volumetricKg) > 70;
  }
}
```

## After

```ts
class Shipment {
  constructor(private parcels: Parcel[], private zone: Zone) {}

  label(): string {
    return `${this.zone.code} ${this.billableKg().toFixed(1)}kg ${this.fee().toFixed(2)}`;
  }

  needsFreightCarrier(): boolean {
    return this.billableKg() > 70;
  }

  private billableKg(): number {
    const actualKg = this.parcels.reduce((s, p) => s + p.weightKg, 0);
    const volumetricKg = this.parcels.reduce((s, p) => s + p.volumeCm3, 0) / 5000;
    return Math.max(actualKg, volumetricKg);
  }

  private fee(): number {
    return this.billableKg() * this.zone.ratePerKg;
  }
}
```

## Why

- The billable-weight rule lives in one place. A change to the volumetric divisor touches one line.
- `label` lost its locals, so further extraction is trivial.
- Queries document themselves in IDE outlines and can be tested.

## Steps

1. Check the variable is assigned once. If it is assigned in several places, apply [Split Temporary Variable](https://aipatterns.dev/refactoring/techniques/split-temporary-variable.md) first.
2. Extract the right-hand side into a private method. Make sure the method does not modify state.
3. Run the tests.
4. Replace each read of the variable with a call to the new method, or apply [Inline Temp](https://aipatterns.dev/refactoring/techniques/inline-temp.md). Run the tests.
5. Replace duplicate computations elsewhere in the class with the query.

## Watch out

- Repeated calls repeat the computation. That is fine for cheap expressions. For costly ones (database reads, large reductions inside a loop), keep the variable or memoize, and measure first.
- Don't apply when the variable captures a snapshot that must not change, such as a timestamp taken at the start of a transaction.
- The query must be side-effect free. If the expression mutates anything, separate the mutation first.
- The opposite move is to keep or reintroduce a local with [Extract Variable](https://aipatterns.dev/refactoring/techniques/extract-variable.md) when the value is only meaningful in one method.

## Related

- Fixes [Long Method](https://aipatterns.dev/refactoring/smells/long-method.md) and [Duplicate Code](https://aipatterns.dev/refactoring/smells/duplicate-code.md).
- Usually the step before [Extract Method](https://aipatterns.dev/refactoring/techniques/extract-method.md).
- When locals are too entangled for queries, use [Replace Method with Method Object](https://aipatterns.dev/refactoring/techniques/replace-method-with-method-object.md).

## Agent checklist

- [ ] The variable was assigned once and the query has no side effects.
- [ ] The value cannot change between calls within the original method, or a change is acceptable.
- [ ] Performance of repeated calls was considered for non-trivial expressions.
- [ ] Duplicate computations elsewhere now use the query.
- [ ] Tests pass.
