Skip to content

Semantics-Preserving Refactoring

Human refactoring workflow / process — instantiates Equivalence-Preserving Rewrite Optimization

A disciplined, human-driven workflow that restructures a system's internals in small reversible steps while holding its externally observable behavior fixed.

The automated rewriters in this archetype reshape code no human could track. Semantics-Preserving Refactoring is the counterpart a person actually performs: a disciplined workflow of changing a system's internal structure — splitting a tangled function, introducing an interface, replacing an algorithm — to make it cheaper to maintain, safer to change, or faster, while its externally observable behavior stays exactly as it was. What defines it is where it draws the line: the external contract (public API, outputs, error behavior, side effects a client can see) is the invariant; everything behind that line is fair to move. And because a human is doing it, its discipline is procedural — small, individually behavior-preserving steps, each reviewable and each reversible — rather than a machine-checked proof.

Example

An order-fulfilment service has a 600-line processOrder() that has accreted for years: inventory checks, tax rules, fraud heuristics, and notification logic all interleaved. It works, and its callers must not notice any change. A refactoring workflow restructures it behind the unchanged public method: extract the fraud heuristics into a FraudCheck collaborator, pull tax logic into a strategy, replace a hand-rolled retry loop with a library one.

Each step is small and separately verified. Before starting, the team pins current behavior with a characterization suite over real order fixtures; after each extraction they re-run it and require it green before the next. Every step lands behind code review — a second pair of eyes on whether the move truly preserved behavior — and behind a feature flag, so any step that slipped through can be reverted with one switch rather than a redeploy. The external behavior — same responses, same emitted events, same error codes — never moves; the internals become modular, testable, and safe to extend.

How it works

The workflow rests on three commitments. First, an explicit behavior boundary: name what external observers can see (API shape, outputs, ordering, error and side-effect behavior) and treat only that as sacred. Second, small reversible steps: prefer many tiny, individually behavior-preserving moves (extract, rename, inline, substitute) over one big rewrite, each pinned by a characterization test run before and after. Third, human review and staged rollout: a reviewer judges the behavior-preservation no test fully covers, and each step ships reversibly so a mistake costs a toggle, not an incident. The ceremony exists because equivalence here is asserted and guarded by process, not proven by a compiler — so the process is the safety.

Tuning parameters

  • Step size — how much each move changes at once. Smaller steps are safer and easier to review and revert but slower; larger steps move faster and risk hiding a behavior change.
  • Behavior-boundary breadth — how much counts as "observable" and thus frozen (just the API, or also timing, ordering, side effects, error text). Too narrow and you break a client relying on the unlisted; too broad and nothing can move.
  • Pre-refactor coverage — how thoroughly current behavior is pinned by a characterization suite first. Thin coverage means refactoring blind; building it costs time up front.
  • Review depth — lightweight peer review versus deep sign-off per step. Heavier review catches subtle behavior changes but slows the work.
  • Rollout reversibility — all-at-once versus behind a flag with a fast backout. More reversibility shrinks the blast radius at the cost of flag machinery and later cleanup.

When it helps, and when it misleads

Its strength is that it is how living systems get better without a risky rewrite: modularity, testability, and performance improve incrementally, each step small enough to review and cheap enough to undo, so improvement never requires betting the whole system on a big-bang change.

Its invariant is easy to claim and hard to hold. The signature failure is a silent boundary violation — a "pure refactor" that changes an error message, an ordering, a timing, or an undocumented side effect some client depended on (with enough users, every observable behavior ends up depended on by someone).[n1] The classic misuse is smuggling a behavior change inside a refactoring commit, where review is primed to wave it through as "just restructuring." The disciplines that guard against it are exactly the workflow's: pin behavior with a characterization test first, keep steps small and separately reviewed, never mix a behavior change into a refactoring step, and keep every step reversible.

How it implements the components

Semantics-Preserving Refactoring fills the components a human, behavior-preserving workflow owns:

  • observable_behavior_boundary — it names the external contract (API, outputs, ordering, visible side effects) that must not move and treats everything inside as free to restructure; drawing that line is the workflow's first act.
  • rollback_or_backtranslation_path — every step ships reversibly (small revertible commits, feature flags, backout paths), so a step that broke behavior costs a toggle rather than an outage.
  • human_review_boundary — a reviewer judges the behavior-preservation automated checks cannot fully cover and decides which steps need deeper sign-off.

It does not automate the rewriting or select transforms by a cost model (Compiler Optimization Pass), and it does not by itself verify behavior was preserved — it leans on a characterization suite to do that (Golden-Output Regression Test).

Editorial Notes

Form Classification

Form family: Intervention, Treatment & Transformation

Rationale: Semantics Preserving Refactoring operates by directly transforms internal structure through small reversible edits while preserving observable behavior. That concrete deployed or enacted form is Intervention, Treatment & Transformation under the frozen taxonomy.

Nearest alternative: Protocol, Workflow & Routine — Although Protocol, Workflow & Routine can support this mechanism, the frozen evidence makes its operative form the act that directly transforms internal structure through small reversible edits while preserving observable behavior; the alternative is therefore secondary rather than defining.

Review outcome: Adjudicated after independent review; high confidence.

Origin Attribution

Primary origin: Computer Science & Software Engineering

Origin pattern: Single lineage

Present-day reach: Multi-domain

Rationale: Small internal restructurings that preserve observable behavior are the defining discipline of software refactoring.

Related originating lineages:

  • Engineering & Design — Modular redesign and verification generalize behavior-preserving internal change to engineered systems.
  • Mathematics — Equivalence-preserving transformation supplies the formal ideal behind refactoring correctness.

Review resolution: The blind reviewers agree that computer_science is the primary origin and differ only on alternate origin disagreement, domain reach disagreement. I preserve every independently explained alternate from both records rather than imposing a numeric cap. I retain single_lineage because the combined record shows one traceable formative lineage. The broader reach of multi_domain records portability separately from historical provenance, and encyclopedia_synthesis=false preserves the affirmative synthesis judgment where either reviewer identified one.

Review outcome: Reconciled after independent review; high confidence.

Notes

This is the archetype's only human-paced rewriter, and that is exactly why its safeguards are procedural rather than formal. Where a Compiler Optimization Pass proves legality mechanically and re-runs on every build, refactoring substitutes small steps, tests, review, and reversibility for a proof it cannot get. The two are the automated and manual poles of the same idea: improve the form, hold the behavior.

[n1] Hyrum's Law — the observation that with enough users, every observable behavior of a system (even one nobody promised) comes to be depended on — is why the observable-behavior boundary is so hard to hold in practice: clients rely on incidental behavior the refactorer never listed as part of the contract.