Progressive Refactor
Progressive Refactor
Trying to fix every problem in one big refactor often fails. A pattern of steady cleanup in small units tends to produce more stable results — a common observation. This article covers the Boy Scout Rule and the Strangler Fig Pattern.
1. Boy Scout Rule
A motto Robert C. Martin ("Uncle Bob") cited around chapter 14 of Clean Code (2008). The original line, taken from US Boy Scouts' campground rules:
"Always leave the campground cleaner than you found it."
Applied to code, "leave any code you touch a little cleaner than you found it". Two essentials:
- Small cleanup — one variable name, one dead import, one missing comment. Don't split big refactors out as separate work — fold them into daily work.
- Where you're already touching — don't clean up unrelated files. Don't let the scope of changes blur the PR's intent.
Practical value of this rule:
- Even without a big refactor schedule, code quality on average rises over time.
- Each change is small, so reviews are fast and regression risk is low.
- No political burden of having to justify a large change all at once.
Frequently cited limits:
- If every change is cleanup, the PR's intent blurs. Separate the main work from cleanup into separate commits when possible.
- When the boundary of "what I'm touching" is fuzzy, unrelated changes mix into the PR.
2. Strangler Fig Pattern
A pattern Martin Fowler organized on his blog. Fowler wrote that he drew the analogy from a strangler fig tree he saw in a Queensland, Australia rainforest in 2001. The latest update of the article is dated August 22, 2024.
The analogy — the strangler fig sprouts on a host tree and grows, gradually absorbing nutrients until it stands on its own. The original tree disappears. This gradual replacement resembles legacy system modernization.
Application:
- Place a new system (or new module) alongside the legacy.
- Branch at the call entry point and route only some traffic to the new system (facade, proxy, API gateway).
- The new system takes over one feature at a time.
- When all features have moved, retire the legacy.
What this pattern solves:
- Reduces the risk of "Big rewrite" (criticized by Joel Spolsky in his 2000 article Things You Should Never Do, Part I). Rewrite-from-scratch attempts often overrun schedules and stop delivering user value.
- The new system also runs while the legacy works, so both face the same traffic patterns and problems are caught early.
- Rollback is gradual. If one feature has issues, only that feature reverts to the legacy.
3. Cleanups in small units
At the code level:
- Rename meaningless abbreviated variables to meaningful ones (
d→daysInMonth). - Extract one responsibility from a large function.
- Remove dead code (unused exports, unreachable branches).
- Replace magic numbers with named constants.
- Convert nested if into early return.
At the system level (Strangler application):
- Route just one endpoint to a new service.
- Dual-write one table to a new schema, verify, then switch read traffic.
- Move one module to a new build system, then expand gradually.
4. Other paths
A full rewrite (Big Rewrite) isn't always wrong. Where dependencies are very shallow, the system is small, or the legacy is no longer operable, rewrite can be reasonable. Strangler too brings the cost of running legacy and new systems simultaneously.
The choice depends on environment:
- System is in operation with users → Strangler is safer.
- No users yet, code is small → rewrite may be faster.
- Scope of change is extremely narrow → the Boy Scout Rule alone is often enough.
5. Common shapes
PR pattern recommended in code review:
PR #123: feat(auth): add password reset
- Main work: add password reset endpoint
- Side: remove unused import in same file (boy scout)
Limit side changes to the same file or adjacent code as the main work. Unrelated directories go in separate PRs.
A Strangler facade example (much simplified):
// existing monolith routes
app.use("/api/users", legacyUsersRouter);
app.use("/api/orders", legacyOrdersRouter);
// route only orders to the new service
app.use("/api/orders", proxy("https://orders-v2.internal"));
6. Common pitfalls
Accidents where bulk unrelated cleanup is mixed into a PR under the Boy Scout Rule banner — review time grows and finding regression causes is harder. Restrain to "1 main change + small amount of side cleanup".
The temporary coexistence period (legacy + new) of Strangler turning into forever — set the migration end date and feature-handover KPIs from the start for safety.
Dual-write accidents desynchronizing the state of two systems — clarify which side is authoritative (SSOT) and agree in advance which side recovers from incidents.
The temptation of a big refactor — "if we just rewrite it cleanly once" often blows the schedule. The "second-system effect" in Mythical Man-Month (Brooks, 1975) is the same trap.
Closing thoughts
Progressive refactor is the safest path to consistent quality improvement. When the small cleanups of the Boy Scout Rule and the gradual replacement of Strangler work together, code and systems steadily improve without the risk of a big refactor. The temptation to "rewrite it all at once" almost always ends up expensive.
Next
- docs-for-agent-and-human
- korean-first
Martin Fowler Strangler Fig Application · Robert C. Martin Clean Code · Joel Spolsky Things You Should Never Do, Part I · Microsoft Cloud Adoption Strangler Fig · Sam Newman Monolith to Microservices for reference.