TL;DR — Refactor when the code blocks an upcoming change, not when it offends. Three questions: is anyone planning to touch this soon? Is the next change easier or harder after refactoring? Does the refactor fit in this PR or does it need its own?

Refactor decision tree — three questionsRefactor pays back when an upcoming change is blocked or made easier. Otherwise it is a hobby. — /refactor or ship? Start here Touching this in next quarter? no It’s a hobby leave it. ship. yes Does refactor make next change easier? yes → do it
Refactor pays back when an upcoming change is blocked or made easier. Otherwise it is a hobby.

“This needs to be refactored” is almost always true. So is “we are shipping next week”. The decision is not whether the code is good — it is whether the refactor pays back inside the timeframe you are working in. Here is the decision tree we use.

Three questions

  1. Is anyone planning to touch this in the next quarter? If no, the refactor is a hobby. If yes, it might be a runway investment.
  2. Is the next planned change easier or harder after the refactor? Easier means the refactor pays back. Harder or neutral means leave it.
  3. Does the refactor fit cleanly in this PR, or does it need its own? Adjacent improvements are fair game. Cross-cutting rewrites get their own PR with their own review.

When refactor is the right call

  • Three teams are about to touch the same module and the contract is unclear
  • The next planned feature is blocked by the current shape
  • A bug class keeps recurring because the abstraction encourages it
  • Onboarding a new engineer requires a 30-minute explanation of “why this is structured this way”

When to leave it alone

  • The code is stable and nobody is changing it
  • The refactor expands beyond the current PR's scope
  • There is no test coverage and the refactor would land blind
  • The improvement is aesthetic, not behavioural or structural

The discipline

Keep a “to refactor” list per module. Each entry has a one-line justification and a “trigger condition” — what would make this worth doing. When the trigger fires, the refactor jumps the queue. Until then, it waits.

Frequently asked questions

Should I refactor as I go?

Sometimes. Refactor adjacent code if it lowers the risk of your current change. Do not refactor unrelated code on the same pull request — it makes review harder and increases blast radius.

What about "broken windows"?

Real, but bounded. The broken-window principle holds at the team level, not as license to scope-creep individual PRs. Track the broken windows in a list and address them deliberately.

Working on something similar?

T-Square architects, builds and operates production systems for learning, AI and custom software products. Talk to a senior engineer for a second opinion.