Replace Temp with Query: A Refactoring Technique

Replace Temp with Query: A Refactoring Technique for Cleaner, More Testable Code

Temporary variables are among the most common sources of unnecessary complexity in software code. They accumulate in long methods, give vague names to computed values, and make it harder to extract, test, or reuse the logic they hold. The Replace Temp with Query refactoring, cataloged by Martin Fowler in Refactoring: Improving the Design of Existing Code, addresses this directly: instead of storing a computed value in a local variable, you extract the computation into a named method, a query, and call it wherever the value is needed.

The result is code that communicates intent instead of hiding it. The computation is no longer buried in a variable assignment at the top of a long method; it has a name, a location, and the ability to be tested in isolation. This article covers the complete technique, what temp variables are, when they become problems, how to perform the refactoring step by step in Java, Python, and TypeScript, when to apply it and when not to, and how it connects to related techniques in the refactoring catalog.

Refactor Your Code with Confidence

SMART TS XL traces where temporary variables, duplicated computations, and extracted query methods are used.

Learn MORE

What Is a Temporary Variable (Temp) in Programming?

A temporary variable, commonly called a temp, is a local variable inside a function or method that stores an intermediate result for use within that same scope. It is calculated once, held in a named variable, and then referenced later in the same function. The variable exists only for the lifetime of the function call; it is not accessible outside it and is not stored in the object’s state.

python

# Python: base_price is a temp variable
def calculate_total(quantity, item_price):
    base_price = quantity * item_price   # temp: computed once, used below
    if base_price > 1000:
        return base_price * 0.95
    return base_price * 0.98

java

// Java: basePrice is a temp variable
double basePrice = quantity * itemPrice;   // temp
if (basePrice > 1000) {
    return basePrice * 0.95;
}
return basePrice * 0.98;

typescript

// TypeScript: basePrice is a temp variable
const basePrice = quantity * itemPrice;    // temp
if (basePrice > 1000) return basePrice * 0.95;
return basePrice * 0.98;

Temps are not inherently bad. They have legitimate uses: capturing the result of an expensive operation that would be wasteful to repeat, breaking a complex multi-step calculation into readable stages, or holding values that accumulate across loop iterations. The problem arises when temps are used reflexively for simple derived values that would be clearer as named methods, or when they accumulate across a long method and force readers to track multiple simultaneously active intermediate values.

What Is Refactoring in Software Engineering?

Refactoring is the process of restructuring existing code without changing its observable behavior. The goal is to improve the internal quality of the code: its readability, testability, maintainability, and modularity. A refactoring does not add features and does not fix bugs; it changes the structure of the code while preserving what it does.

Replace Temp with Query is one refactoring in a catalog of several dozen techniques described by Martin Fowler. It belongs to a family of techniques that deal with methods that have grown too long or too complex:

Refactoring TechniqueWhat It Does
Replace Temp with QueryExtracts a temporary variable’s computation into a named method
Extract MethodExtracts a block of code into a new named method
Inline TempReplaces a simple temp with its expression directly
Split Temporary VariableSeparates a temp that is reused for different purposes into distinct variables
Replace Loop with PipelineReplaces an imperative loop with a functional pipeline (map, filter, reduce)
Introduce Explaining VariableIntroduces a named temp to clarify a complex expression

These techniques are not used in isolation. Replace Temp with Query is described by Fowler as a vital step before Extract Method: if a method has temp variables, extracting a portion of it into a new method becomes difficult because those temps may be used both before and after the extracted section. Eliminating the temps first by turning them into queries clears the path for the extraction.

What Is Replace Temp with Query?

Replace Temp with Query is a refactoring technique that transforms a local temporary variable into a method call. Instead of computing a value and assigning it to a local variable, you extract the computation into a private method, the query, which returns the computed value when called. Wherever the temp was used, you replace the reference with a call to the query method.

The canonical example from Fowler’s Refactoring:

Before:

java

double basePrice = _quantity * _itemPrice;
if (basePrice > 1000)
    return basePrice * 0.95;
else
    return basePrice * 0.98;

After:

java

if (basePrice() > 1000)
    return basePrice() * 0.95;
else
    return basePrice() * 0.98;

private double basePrice() {
    return _quantity * _itemPrice;
}

The query method basePrice() is now a named, self-contained computation. It can be called from any other method in the class, tested independently, overridden in subclasses, and understood without reading the calling method first.

The Problem with Temporary Variables

They Fragment Logic Across a Method

A temporary variable splits a computation into two separated pieces: the assignment (where the value is calculated) and the usage (where it is read). In a short method, this split is harmless. In a method that has grown to thirty or fifty lines, the assignment and the usage may be separated by many lines of other logic. The reader must scroll up to find the assignment, hold the meaning in working memory, and scroll back to the usage. Each additional temp compounds this cognitive overhead.

They Block Extract Method

The most significant practical problem with temps is that they block other refactorings. Consider a method with a complex conditional branch that would benefit from being extracted into its own method. If the branch uses a temp that was assigned earlier in the method, the extraction requires either passing the temp as a parameter, making the temp an instance variable, or calculating its value again inside the extracted method. None of these options is clean. Eliminating the temp first by replacing it with a query removes this obstacle entirely.

They Invite Reuse and Mutation

Temporary variables are sometimes reused for different purposes within the same method, a practice Fowler calls the “temporary variable tangle.” A variable named temp or result that is reassigned multiple times provides no semantic information and actively misleads readers about what it represents at any given point. Even single-purpose temps can accumulate until the scope of a method is cluttered with intermediate values that readers must track simultaneously.

Step-by-Step: How to Apply Replace Temp with Query

The transformation follows four steps that can be applied safely in any language:

Step 1: Confirm the temp is assigned exactly once and is never mutated. If the temp is reassigned later in the method, split it first using Split Temporary Variable.

Step 2: Extract the right-hand side of the assignment into a private method. Give the method a name that describes what it computes, not how. basePrice() is better than calculateQuantityTimesPrice().

Step 3: Replace every reference to the temp with a call to the new method. Most IDEs can do this automatically: right-click the temp → Refactor → Inline Variable, then Extract Method on the inlined expression.

Step 4: Delete the temp variable declaration. If the extraction is complete, the temp should now have no references and can be removed.

Java: Full Working Example

java

// Before: Order class with temporary variables
public class Order {
    private int quantity;
    private double itemPrice;

    public double getPrice() {
        double basePrice    = quantity * itemPrice;        // temp 1
        double discountFactor;                             // temp 2
        if (basePrice > 1000)
            discountFactor = 0.95;
        else
            discountFactor = 0.98;
        return basePrice * discountFactor;
    }
}

java

// After: temps extracted to query methods
public class Order {
    private int quantity;
    private double itemPrice;

    public double getPrice() {
        return basePrice() * discountFactor();
    }

    private double basePrice() {
        return quantity * itemPrice;
    }

    private double discountFactor() {
        return basePrice() > 1000 ? 0.95 : 0.98;
    }
}

The method getPrice() now reads as a single expression that clearly communicates the computation. Each extracted query can be read, tested, and extended independently. Note that discountFactor() calls basePrice(), this is correct because basePrice() is a pure computation with no side effects, so calling it twice introduces no risk.

Python: Replace Temp with Property

In Python, the natural equivalent of a query method is a @property, which allows the method to be called without parentheses and reads identically to an attribute access:

python

# Before: temporary variables in a method
class Order:
    def __init__(self, quantity, item_price):
        self.quantity   = quantity
        self.item_price = item_price

    def get_price(self):
        base_price     = self.quantity * self.item_price  # temp
        discount       = 0.95 if base_price > 1000 else 0.98  # temp
        return base_price * discount

python

# After: temps replaced with properties (query methods in Python)
class Order:
    def __init__(self, quantity, item_price):
        self.quantity   = quantity
        self.item_price = item_price

    def get_price(self):
        return self.base_price * self.discount_factor

    @property
    def base_price(self):
        return self.quantity * self.item_price

    @property
    def discount_factor(self):
        return 0.95 if self.base_price > 1000 else 0.98

Using @property means self.base_price reads identically to an instance variable, making the calling code self.base_price * self.discount_factor completely natural. Each property is independently testable:

python

def test_base_price():
    order = Order(10, 150)
    assert order.base_price == 1500

def test_discount_factor_high_value():
    order = Order(10, 150)   # base_price = 1500 > 1000
    assert order.discount_factor == 0.95

def test_get_price():
    order = Order(10, 150)
    assert order.get_price() == 1500 * 0.95

This level of testability is impossible with the temp-based version: the internal computations base_price and discount_factor are not accessible from outside the method.

TypeScript: Query Methods and Getters

TypeScript supports both method-based queries and property getters, matching the patterns available in Java and Python respectively:

typescript

// Before: temporary variables
class Order {
    constructor(private quantity: number, private itemPrice: number) {}

    getPrice(): number {
        const basePrice = this.quantity * this.itemPrice;  // temp
        const discount  = basePrice > 1000 ? 0.95 : 0.98; // temp
        return basePrice * discount;
    }
}

typescript

// After: TypeScript getters replace temps
class Order {
    constructor(private quantity: number, private itemPrice: number) {}

    getPrice(): number {
        return this.basePrice * this.discountFactor;
    }

    private get basePrice(): number {
        return this.quantity * this.itemPrice;
    }

    private get discountFactor(): number {
        return this.basePrice > 1000 ? 0.95 : 0.98;
    }
}

Naming Query Methods Well

The query method’s name is doing the most important work. A poorly named extraction is worse than the temp it replaced, because it creates an opaque indirection: callers must navigate to the method definition to understand what it does, defeating the purpose.

Good query method names follow these principles:

Name what it represents, not how it is computed. basePrice() communicates the business concept. getQuantityTimesItemPrice() describes the calculation, not the concept. The distinction matters when the calculation changes, the concept name basePrice() remains stable even if the formula changes.

Use noun phrases for values. Query methods return values; they are not commands. discountFactor(), totalAmount(), isEligible() follow the convention of naming what is returned. calculateDiscount(), processAmount() follow the imperative convention of commands, which is confusing for methods that purely compute and return.

Boolean queries should read as questions. isHighValue(), hasDiscount(), meetsThreshold() communicate that the return is a boolean and that the caller is asking a yes/no question. bool 変数名 (boolean variable naming, a query in the Search Console data) reflects exactly this concern: boolean variables and methods need names that make their meaning clear at the point of use.

Keep names stable across related methods. If basePrice() is used by discountFactor(), the naming consistency tells readers that discountFactor depends on basePrice. Inconsistent naming breaks this implicit documentation.

When to Apply Replace Temp with Query

Apply this refactoring when:

  • The temp is assigned exactly once and never reassigned
  • The computation is a pure expression: it reads from fields or parameters but does not modify external state, call network services, or depend on time or randomness
  • The computation is complex enough that naming it would aid readability, or simple enough that the temp is just clutter
  • You are about to apply Extract Method to a block that uses the temp

The most common ideal scenario is a derived value: a price, a total, a discount, a formatted string, a conditional classification. These are values derived entirely from the object’s fields, with no side effects, that naturally belong as properties of the object rather than as intermediate computations inside a method.

When Not to Apply Replace Temp with Query

Performance-sensitive operations. If the computation is expensive, a database query, a network call, an O(n²) loop, calling the query method twice introduces double the cost. The temp exists precisely to avoid this. In these cases, either leave the temp in place or memoize the query method (cache the result after the first call):

python

# Memoized property: computed once, cached
from functools import cached_property

class Order:
    @cached_property
    def expensive_validation(self):
        return self.external_service.validate(self.data)  # called once, cached

Side-effectful operations. If the temp holds the result of an operation that should only run once (generating a unique ID, logging, writing to a file), turning it into a query would run the operation on every call. This changes the behavior of the program, not just its structure. Do not apply this refactoring to side-effectful temps.

Temps that accumulate across loop iterations. A temp that is the accumulator in a for loop, total += item.price, is not a candidate for Replace Temp with Query. It is not a derived value; it is state that builds up across iterations. Consider Replace Loop with Pipeline instead if the loop is the problem.

Related Refactoring Techniques

Replace Temp with Query belongs to a family of techniques that collectively eliminate unnecessary complexity in methods. Understanding the family helps developers choose the right technique for the problem at hand:

Extract Method is the most common companion. Replace Temp with Query often makes Extract Method possible by clearing variables that would otherwise require awkward parameter passing between the extracted portion and the remainder of the method.

Inline Temp is the reverse of introducing a temp: it replaces a temp with its expression directly in the code. Use Inline Temp when the temp adds no clarity and its expression is already readable.

Split Temporary Variable applies when a single temp is reused for multiple purposes in the same method. Split it into separate variables with names reflecting each purpose, then apply Replace Temp with Query to any of the resulting single-use temps.

Introduce Explaining Variable is the opposite direction: if a complex expression is hard to read, introducing a temp with a descriptive name can improve clarity. This technique and Replace Temp with Query are in tension and the developer must judge which direction improves the specific code in question.

Replace Loop with Pipeline addresses a common pattern where a loop with a temp accumulator can be replaced by a chained pipeline operation (map, filter, reduce), which is more declarative and easier to read.

How SMART TS XL Supports Refactoring at Scale

Replace Temp with Query is a local refactoring: it transforms one variable in one method. In a codebase of any significant size, the more useful question is not “how do I apply this refactoring?” but “where across the entire codebase should I apply it, and what will be affected when I do?”

SMART TS XL provides the cross-codebase structural analysis that makes answering this question systematic. It identifies where the same computation is performed as a temp variable in multiple locations, the pattern that Replace Temp with Query is designed to consolidate into a single named query method. It traces how a refactored query method is used once it is extracted, making the scope of the refactoring visible before it is made. And it works across languages: for enterprise systems where COBOL programs, Java services, and Python pipelines all operate on the same data, static code analysis and impact analysis identify where the same logical computation appears in different forms across different languages, the deeper form of the problem that Replace Temp with Query addresses at the single-language level.

For teams working on legacy modernization, SMART TS XL’s dependency visualization makes it possible to see where refactored components are used before changing them, ensuring that extracting a computation into a query method does not break callers that expected the original structure.

Temporary Variables and Self-Documenting Code

The decision to replace a temp with a query is ultimately a decision about what the code should communicate. Temporary variables communicate implementation: this is the calculation I performed to get this value. Query methods communicate domain: this is what this value means. In an Order class, basePrice() tells the reader that this concept exists in the domain. double x = quantity * itemPrice tells the reader about an arithmetic operation.

As code evolves, domain concepts need stable homes. A computation embedded in a temp can change, be duplicated in multiple methods, or be misunderstood by the next developer who reads it. A named query method can be found, tested, documented, and evolved intentionally. That stability, across all the places the computation is needed and across all the developers who will work with it, is what makes Replace Temp with Query more than a syntax change. It is a decision about how the codebase communicates the problem it solves.