Give concrete situations where you should deliberately NOT tidy code you're touching, and leave it exactly as you found it.
answer
- Hotfix: minimal, revertable, no tidying
- Don't polish code you're about to delete
- In-flight branch = merge-conflict tax
- Regulated code: every line re-validated
- Not a refactoring if behaviour changes
basics
~20 sDuring an urgent production hotfix, in code about to be deleted or replaced, in files with big in-flight branches, in frozen or audited code, in areas you don't understand, and when the "cleanup" would actually change behaviour.
solid answer
~50 sThe rule is a default, not an obligation. Skip cleanup when: (1) it's an incident hotfix — the diff must be minimal and trivially revertable; (2) the code is scheduled for deletion or strangulation, so tidying is wasted and creates sunk-cost attachment; (3) someone has a large open branch in the same file and your churn buys them a painful merge; (4) the code is under change control — regulated, audited, certified, or safety-critical — where every change needs re-validation and the cost of touching a line is enormous; (5) you don't actually understand the code and can't prove your "simplification" is behaviour-preserving, especially with no tests; (6) the improvement isn't a refactoring at all but a silent behaviour change; (7) generated code, vendored dependencies, or files whose formatting is tool-owned. In several of these, the right Boy Scout act is to *record* the problem — a ticket, a marker with an id — rather than fix it.
go deeper
Name the obvious cases — urgent hotfix, code you don't understand, code about to be deleted — and say you'd record the problem in a ticket instead.
Add in-flight branches and merge cost, generated/vendored files, and the rule that cleanup must be behaviour-preserving or it isn't cleanup.
Bring in regulated/change-controlled code and re-validation cost, public API blast radius and deprecation cycles, diff-budget heuristics, and the traps in 'obviously redundant' code (races, deliberate duplication, evaluation order).
Frame it as expected-cost reasoning and talk about removing the judgement burden: automated formatting, new-code-only gates, a debt register reviewed in planning, and incident-review follow-ups so deferred cleanup actually gets funded.
## Why this question is asked Anyone can recite "leave it cleaner than you found it". The signal an interviewer wants is **judgement about cost**: cleanup is not free, and there are situations where its expected cost clearly exceeds its expected benefit. A candidate who applies the rule unconditionally is a liability during incidents and migrations. ## The exceptions, with mechanisms ### 1. Incident / hotfix path During an outage, the operating goals are *minimum time to mitigation* and *maximum confidence in revert*. A mixed commit cannot be cleanly reverted or cherry-picked onto a release branch, and every extra changed line is another thing the on-call reviewer must verify at 3 a.m. under stress. **Fix only; open a follow-up ticket.** ### 2. Code that is about to disappear If a module is scheduled for deletion, or is the legacy side of a Strangler Fig migration that will retire it in weeks, cleanup produces no return. Worse, effort invested creates **sunk-cost attachment** — people argue to keep code they just polished. Spend the effort on the code that will survive. ### 3. Heavy in-flight work in the same file Restructuring a file that a colleague has open on a two-week branch converts your five-minute tidy into their multi-hour merge conflict — and conflict resolution on refactored code is exactly where behaviour gets silently lost. Check for open branches first; coordinate or defer. ### 4. Change-controlled, regulated, or safety-critical code In medical devices, avionics, automotive, payments, or anything under a certification regime (e.g. code covered by a validated release, an audit trail requirement, or formal verification), **any** change — even a rename — can trigger re-review, re-validation, re-certification, and paperwork costing orders of magnitude more than the cleanup is worth. Some organizations require every changed line to trace to an approved change request. Cosmetic edits are not permitted, and proposing them signals unfamiliarity with the domain. ### 5. You don't understand the code and have no safety net "Simplifying" a condition you haven't fully decoded is how subtle bugs enter. Classic traps: a redundant-looking null check that guards a real race; a loop that looks equivalent but changes evaluation order or short-circuiting; a duplicated block that is *deliberately* duplicated because the two copies must evolve independently; a `catch` that swallows an exception for a documented reason. With no tests, you cannot detect the difference. Either add a characterization test first or leave it alone. ### 6. The "cleanup" isn't behaviour-preserving If your change alters what the program does — tightening validation, changing an error message a client parses, altering log output a dashboard depends on, changing iteration order, adjusting a timeout — it is a **behaviour change** and must be proposed, reviewed and released as one. Smuggling it in under the label "refactor" is a review defect regardless of whether the change is an improvement. ### 7. Tool-owned or foreign files Generated code (from schemas, protobufs, ORMs, build plugins), vendored third-party dependencies, and lock files: hand-editing is overwritten on the next generation or causes painful upgrade conflicts. Fix the generator or the template, not the output. ### 8. Style that is or should be automated Hand-adjusting formatting is not Boy Scouting; it is diff noise. If style matters, adopt an auto-formatter repo-wide, land the bulk change as one mechanical commit, and add that commit to a blame-ignore list. Then no individual ever spends review capacity on it again. ### 9. Diff-budget exhaustion Even when cleanup is legitimate, there is a point where it stops being opportunistic. Practical heuristics: keep the cleanup diff no larger than the functional change; keep it inside the region you actually had to read; time-box it. Past that, it graduates to its own PR — ideally merged **before** the functional change so the functional diff stays clean. ### 10. Public API surface Renaming an exported symbol, changing a signature, or restructuring a published contract has a blast radius beyond your repo (other teams, external consumers, serialized data, reflection- or configuration-driven lookups). That's a deprecation cycle, not a drive-by. ## The constructive alternative In nearly every case above, the *information* is still valuable even when the fix isn't allowed. Do the cheapest thing that preserves it: - open a ticket naming the file and the specific smell, and link it from the PR description; - leave a marker with an owner and ticket id (`HACK(PROJ-1187): duplicated on purpose, see ticket`) — never a bare, ownerless `TODO`; - add it to a debt register or hotspot list that gets reviewed during planning; - if it's a recurring class of problem, propose a lint rule or a new-code-only gate so it stops arriving. ## How to answer Start by affirming the rule is a default with a cost, then give three or four *concrete* exceptions with their mechanism (hotfix → revertability; doomed code → wasted effort plus attachment; regulated code → re-certification cost; unclear code without tests → silent behaviour change). Finish with the alternative: record what you didn't fix so the knowledge isn't lost.
- You skipped the cleanup because it was a hotfix. How do you make sure it actually happens later?Create the follow-up ticket in the same session, link it from the hotfix PR, and attach it to the incident review action items — where follow-ups have an owner and get tracked. Debt that lives only in someone's memory or a bare TODO does not get paid.
- How do you distinguish a genuine behaviour-preserving refactoring from a behaviour change in review?Existing tests must pass unchanged. If a test had to be modified or added to make the change pass, the observable behaviour moved, and the commit should be labelled and reviewed as a behaviour change — not as a refactor.
- Duplicated code appears in two modules. Is deduplicating it always an improvement?No. Duplication is sometimes deliberate: the two copies serve different owners or lifecycles and are expected to diverge. Coupling them through a shared abstraction creates a dependency that turns future divergence into painful conditional logic — the standard warning that a wrong abstraction costs more than duplication.
You don't reorganize the medicine cabinet while someone is bleeding, and you don't repaint a room in a house scheduled for demolition next month.
saying these in an interview costs you the question
- Applying the rule during an incident and inflating a hotfix diff
- Deleting 'redundant' guards, catches or duplication without proving they're redundant
- Labelling a behaviour change as a refactor because it looked like an improvement
- Hand-editing generated or vendored files instead of fixing the generator or upgrading
- Renaming exported/public symbols as a drive-by, ignoring external consumers and deprecation
- Skipping cleanup and recording nothing, so the knowledge of the problem evaporates
- Insisting the rule has no exceptions, which signals no experience with regulated or migration work