skip to content

Where does an automated rename stop guaranteeing that behaviour is preserved?

level: middleimportance: nice to knowfreq 24%

answer

  1. Symbolic resolution, not text matching
  2. Only what the analyser indexes
  3. Strings, configuration, templates, generated sources
  4. Ask who else reads this name
  5. A consumer-visible name is a contract

basics

~20 s

The guarantee covers references the tool's analyser can resolve in the sources it indexes. Names reached from strings, configuration, templates, generated code, stored data or another repository are outside it, and a rename silently breaks them.

solid answer

~50 s

A tool-driven rename is safer than a hand edit because it resolves each reference symbolically instead of matching text, so it updates exactly the uses of that one symbol and misses none it can see — no near-miss identifiers, no shadowed names. Its guarantee ends at the edge of what it analyses. Anything that reaches the name at run time rather than through a resolved reference is invisible to it: keys in configuration, names embedded in query or template text, dynamic lookups by string, code generated during the build, and names that have escaped the codebase entirely into stored data, a wire payload, a dashboard query or another team's repository. So I use the tool for the move, then run the suite, and I treat any rename that can cross a boundary as a contract change rather than a refactoring.

code

pseudocode · 11 lines
pseudocode
# updated by the tool - a resolved reference
price = seat.unitPrice

# NOT updated - the name is a run-time string
value = lookup_field(seat, config.get("seatmap.price.field"))

# NOT updated - the name is embedded in query text
rows = query("select unitPrice from seat_inventory")

# NOT updated anywhere - the name already left the codebase
# consumers read "unitPrice" from the published payload

go deeper

for a junior

Know that a rename from the tool is safer than a text replace because it follows real references, and that you still run the tests afterwards.

for a middle

Be able to list where the guarantee stops — string lookups, configuration keys, query and template text, generated sources, other repositories — and why each is outside the analyser's index.

for a senior

Show the judgement call: ask who reads the name, and treat any consumer-visible one as a coordinated contract change with an old-name-usage check rather than a free move.

for a principal

Own the structural fix: keep externally visible names decoupled from internal ones at the boundary, so internal renaming stays cheap and never becomes a cross-team migration.

## What the tool actually promises An automated rename works on the resolved program, not on text. It knows which declaration a given use refers to, so it can update every reference to *that* symbol and leave alone an identically spelled name that belongs to something else. That is the whole reason it beats a find-and-replace across the tree: text matching has no idea that two occurrences of the same word are different things, and it cannot see that a third is a substring of a longer identifier. Within its index, the rename is exhaustive and mechanical, which is why it counts as one safe move in the refactor step rather than a dozen risky edits. ## Where the promise ends The promise is scoped to *references the analyser resolves in the sources it indexes*. Five families sit outside it. **Names reached through strings.** Anything that looks the name up at run time from a literal, a configuration key, a property file, a mapping table or an injected identifier is, to the analyser, just text. It will not be renamed, and it will fail at run time rather than at build time. **Names in non-source artefacts.** Query text, template markup, serialized documents, migration scripts, build configuration and infrastructure definitions can all embed a name the tool never parses as code. Some tools offer to rename inside comments and string literals; that option is text matching again, and it will happily rewrite an unrelated word that merely spells the same. **Generated and excluded code.** Sources produced during the build, or directories excluded from the analysis scope, are not in the index. The rename compiles until the generator runs. **Names that have left the codebase.** A field name that a name-derived serializer writes onto the wire, a column that already exists in stored data, a metric or log key that dashboards and alerts query, an identifier another repository imports — these are consumer-visible contracts. Renaming them is not a refactoring at all, because observable behaviour changes for someone; it is a contract change and needs the corresponding coordination. **Names in different languages or repositories.** Cross-boundary references are outside a single project's index by construction. ## Worked example In an airline seat-map service, a field holding the per-seat price carries an awkward internal name. The rename is a two-second tool operation, it updates 63 references, the suite of 47 tests stays green, and it looks like a textbook refactor step. It is not, because the boundary mapper derives payload field names from the code's own names: the outgoing document now carries the new name, the seat-selection client still reads the old one, and you have a schema-drift mismatch in production that no local check could see. The same rename would also have orphaned an alert that queries a metric by the old key. The tell is not the rename — it is the name's *audience*. Before renaming, ask who reads this name: only this codebase, or someone outside it? For the first, the tool's guarantee plus a suite run is enough. For the second, you are changing a contract, and the safe route is the expand-then-contract shape: publish both names, migrate consumers, remove the old one — sequenced, not atomic. ## Practical habits Run the suite after the rename even though the move was mechanical; the run is what covers the references the tool could not. Grep the tree for the old name as text afterwards, including non-source files, and read every hit rather than replacing it blindly. Keep the rename as its own commit so it can be reverted cleanly if a run-time lookup surfaces later. And be wary of the tool's "also rename in comments and strings" checkbox: it turns a symbolic move into a textual one, which is the exact property that made the tool trustworthy in the first place. ## Why this is worth knowing Rename is the cheapest and most-used move in the refactor step, and its cheapness is what makes the failure mode surprising. Understanding precisely which references are covered is what lets you tell a free move from a coordinated migration wearing the same button.

  • What makes a tool-driven rename safer than a find-and-replace across the tree?
    The tool resolves each occurrence to a declaration, so it updates exactly the uses of that one symbol: it will not touch a different thing with the same spelling, a shadowed local, or a longer identifier that happens to contain the word. Find-and-replace matches characters and has none of that context, so it both over-reaches and, when a reference is spelled differently, misses.
  • How do you rename a name that consumers outside the codebase already read?
    Treat it as a contract change, not a refactoring. Publish both the old and the new name from the same source of truth, give consumers a window to migrate, verify nobody reads the old one, and only then remove it. The rename inside your code can be a single tool move; the externally visible part has to be sequenced, and it needs a way to observe who is still using the old name.

Change of address forwarding covers the letters routed through the postal system; it does nothing about the address a friend has written in their own notebook.

saying these in an interview costs you the question

  • Assumes an automated rename cannot break anything
  • Skips the test run because the move was mechanical
  • Enables rename-in-strings and calls it thorough
  • Forgets names embedded in configuration or query text
  • Renames a consumer-visible field as a refactoring

context