Module 1: Why Not Rewrite
The second-system syndrome
Overview
Lesson 2 showed a failure mode that comes from outside: the business doesn't stop and parity recedes. This lesson shows one that comes from inside, from the team itself, and it's so strong that it appears even if the legacy were completely frozen. It's called the second-system syndrome (second-system effect), and Fred Brooks named it in The Mythical Man-Month in 1975. The observation is this: of all the systems an engineer designs, the second is the most dangerous of all. The first was made with fear and humility —you didn't quite know what you were doing, so you kept it simple—. But when making the second, you already "know" the domain, and you arrive loaded with all the ideas you had to leave out of the first: "this time I'll make it generic," "this time I'll support all the cases," "this time I'll put in that configuration layer I always wanted." The second system isn't over-decorated by mistake: it's over-decorated because the "fresh start" feels like the perfect permission to cram everything in.
A rewrite is, by definition, a second system —Mercado's rewrite would be "Mercado 2"—, so it inherits the full syndrome. And the damage isn't aesthetic: it's about the calendar. Each extra idea that sneaks into the scope is unplanned work, and that work pushes the closing date. Worse: the extra work is discovered during construction, not before, so the scope grows exactly while you try to close it. This lesson measures it. We're going to model a rewrite with a fixed work speed, and inject different levels of "gold-plating" —the percentage of each month's work that reopens as new scope— to see how the closing date slides from month 20 to 50, and how, with total inflation, the system is never ready.
Connection with the module. It's the second of the big rewrite's four failure modes. Lesson 2 measured the failure that comes from the business (the moving target); this one measures the one that comes from the team (scope inflation). They're independent and they add up: a real rewrite suffers both at once. Lesson 4 closes the trio with the lost tacit knowledge. The discipline of frozen scope that this lesson shows as an antidote is, not by chance, the same discipline the incremental approach imposes naturally (a slice has a small and bounded scope, hard to inflate) —we'll see it in lesson 5—.
An analogy: the kitchen remodel that never ends
You hired a remodel of your kitchen. The plan was clear: change the cabinets and the countertop, three weeks of work. But once they started demolishing, the usual thing happened. "Since we've opened the wall, don't you want to move the sink to the island?" Well, yes, it makes sense. "And since we're moving the plumbing, it would be silly not to also change the old pipes." Sure. "Hey, and with the kitchen open, this is the moment to knock down the wall toward the dining room, you'll never have a better chance." You're right, let's do it. Each suggestion is reasonable on its own —it really is more efficient to do it now that the wall is open—. But addition after addition, the three weeks became four months, and every time you think they're almost done, one more thing appears that "while we're at it" is worth doing. The job didn't run late because of a single big mistake: it ran late because of a hundred small decisions, each sensible, that inflated the scope while the job was underway.
That's exactly the second-system syndrome in a rewrite. "Since we're rewriting the catalog, let's make it generic for any type of product." "Since we're touching orders, let's also support the recurring orders we always wanted." "Since we're redoing payments, let's add that configurable rules engine." Each "while we're at it" is reasonable in isolation and catastrophic together: it reopens the scope exactly when you try to close it, and the delivery date recedes as much as in the kitchen. The difference from the remodel is that the kitchen, at least, has physical walls that limit how much you can add. Software doesn't have that natural boundary —there's always room for one more feature—, so the syndrome is even worse.
Worked example: the closing date that recedes
We're going to model a rewrite with an initial scope of 200 work units and a team that closes 10 units per month. If the scope were frozen, closing would take exactly 20 months (200 / 10). Now we inject the gold-plating: a fraction of each month's work reopens as new scope ("while we're at it, let's do it right"). With 0% inflation there's total discipline; with more, the scope grows while you close it:
VELOCITY = 10 # work units the team closes per month
INITIAL_SCOPE = 200 # the scope the rewrite starts with
def months_to_finish(inflation_rate, cap=120):
# inflation_rate = fraction of the month's work that REOPENS as new
# scope ("while we're at it, let's do it right"). Returns closing month or None.
remaining = INITIAL_SCOPE
for month in range(1, cap + 1):
remaining -= VELOCITY # work closed this month
remaining += VELOCITY * inflation_rate # gold-plating that sneaks in
if remaining <= 0:
return month
return None
scenarios = [
("frozen scope (discipline)", 0.0),
("light gold-plating", 0.3),
("classic second system", 0.6),
("'let's do it right once and for all'", 1.0),
]
print(f"{'strategy':<34}{'inflation':>10}{'closes at':>18}")
print("-" * 62)
for name, rate in scenarios:
m = months_to_finish(rate)
when = f"month {m}" if m is not None else "NEVER (>10 years)"
print(f"{name:<34}{rate:>9.0%}{when:>18}")
# Remaining work month by month: discipline (drops) vs second system (stalls).
print("\nRemaining work (units) - discipline vs second system:")
print(f"{'mo':>4}{'frozen':>12}{'2nd system':>14}")
print("-" * 30)
frozen = INITIAL_SCOPE
second = INITIAL_SCOPE
for month in range(0, 25):
if month % 4 == 0:
f_txt = frozen if frozen > 0 else "done"
print(f"{month:>4}{str(f_txt):>12}{second:>14.0f}")
frozen = max(0, frozen - VELOCITY)
second = second - VELOCITY + VELOCITY * 0.6
print("\n The plan promised to close in month 20 (200 / 10).")
print(f" With 60% inflation, the net progress drops from 10 to 4 units/mo and the")
print(f" real close slides to month {months_to_finish(0.6)}: a slip of "
f"{months_to_finish(0.6) / 20:.1f}x.")
print(f" With 100% inflation the net progress is 0: the system is NEVER ready.")
What to expect. When you run the file, the output is exactly this:
strategy inflation closes at
--------------------------------------------------------------
frozen scope (discipline) 0% month 20
light gold-plating 30% month 29
classic second system 60% month 50
'let's do it right once and for all' 100% NEVER (>10 years)
Remaining work (units) - discipline vs second system:
mo frozen 2nd system
------------------------------
0 200 200
4 160 184
8 120 168
12 80 152
16 40 136
20 done 120
24 done 104
The plan promised to close in month 20 (200 / 10).
With 60% inflation, the net progress drops from 10 to 4 units/mo and the
real close slides to month 50: a slip of 2.5x.
With 100% inflation the net progress is 0: the system is NEVER ready.
Read the first table as a staircase toward the abyss, one step per row.
The first scenario, frozen scope, is perfect discipline: 0% inflation, zero "while we're at it." It closes in month 20, exactly as the plan promised. This is the ideal world —and notice that not even this world includes lesson 2's moving target; here the legacy is frozen and even so we're going to see how it derails—.
Go down a row. Light gold-plating, just 30% inflation: for every 10 units the team closes, 3 reopen as new scope. The close slides from month 20 to 29 —almost 50% more—, and all for a level of "while we're at it" that most teams wouldn't even notice as excessive. A 30% scope creep sounds moderate, almost healthy; it costs nine months.
Go down another. Classic second system, 60% inflation: for every 10 closed, 6 reopen. The net progress drops to 4 units per month (you close 10 but 6 are added), and closing 200 units at 4 net per month takes 50 months —two and a half times the plan—. The footnote says it: a slip of 2.5x, not from incompetence, but because 60% of the effort goes into features nobody asked for at the start.
And the last row is the cliff. "Let's do it right once and for all," 100% inflation: for every 10 units closed, 10 reopen. The net progress is exactly zero. The team works full tilt, closes 10 units every month, and the remaining work doesn't drop a single unit, because each advance generates its own setback. It's NEVER ready. This is the rewrite that's been "almost done" for four years and where every demo reveals three new features to build.
The second table shows the mechanism in slow motion. The frozen column drops clean and even: 200, 160, 120, 80, 40, "done" in month 20. The second system column (60% inflation) drops painfully: 200, 184, 168, 152, 136... in month 20, when the disciplined one already finished, the second-system one still has 120 units to go —more than half of the original scope after having worked twenty months—. It's not that it works less: the column does drop, yes, but at 4 per month instead of 10, because 60% of its effort evaporates in gold-plating.
The lesson's point is uncomfortable: this failure mode requires neither bad faith nor laziness. On the contrary, it requires enthusiasm —the team is motivated, wants to do things "right," sees the rewrite as the chance to fix everything it hated about the old system—. That enthusiasm, without the discipline of a frozen scope, is exactly the syndrome's fuel. And the final irony: the old system, the one everyone wants to replace, was simple precisely because it was made without that enthusiasm, with the humility of someone who didn't know. The second system is dangerous because it thinks it already knows.
Deep dive: why incremental resists the syndrome
You might think the solution is "just have discipline" —freeze the scope and don't give in to the "while we're at it"s—. It's correct in theory and very hard in practice, because each individual suggestion is reasonable, and saying no to each one feels petty ("seriously, you're not going to support recurring orders, since you're redoing orders anyway?"). Pure discipline depends on a will sustained over years against constant pressure, and wills give in.
The incremental approach doesn't depend on will: it changes the structure so the syndrome has nowhere to grow. When you modernize a small slice —say, just the catalog read— that slice's scope is tiny and concrete: "make the catalog read work the same as today, but in the new service." There's no room for "while we're at it, let's also support X," because the explicit goal is parity with what already exists, not improvement. And since each slice is delivered in weeks and goes to production, the team sees real value fast, which reduces the anxiety of "cram everything in now because there won't be another chance" —there will be many other chances, one per slice—.
Pure discipline Incremental structure
(fragile) (robust)
┌───────────────────┐ ┌───────────────────┐
Scope: │ huge, open │ │ small, closed │
│ (whole system) │ │ (one slice) │
Antidote: │ say "no" a │ │ the goal IS │
│ thousand times │ │ parity, not better│
Depends on: │ sustained will │ │ the step size │
Fails when: │ the will yields │ │ (rarely fails) │
└───────────────────┘ └───────────────────┘
This doesn't mean that in an incremental migration you never improve anything —of course you do, that's half the point of modernizing—. It means the improvements are made after reaching parity, slice by slice, as conscious and separate decisions, not as a "while we're at it" that sneaks in while you try to close. First you match, you turn off the old, and then, with the new system already in production and delivering value, you decide whether it's worth adding recurring orders. The improvement stops being a scope stowaway and becomes a decision of its own.
Common mistakes
Confusing "seize the opportunity" with "inflate the scope." What happens: each extra feature is justified with "it's more efficient to do it now that we're here," and since each justification is true in isolation, nobody stops them. Why it happens: local efficiency (yes, it's cheaper to move the sink with the wall open) hides the global cost (the whole project derails). How to spot it: if the rewrite's meetings generate more features than they close, and phrases like "while we're at it" or "this time let's do it right" appear often, the syndrome is active. How to fix it: separate two questions the "while we're at it" fuses: "is it cheaper to do it now?" (often yes) and "should we do it now?" (almost always no, if it moves the date of a system the business is waiting for). The efficiency of an isolated task doesn't justify derailing the project. Freeze the scope at parity and schedule the improvements as separate work, after the turn-off.
Measuring progress by features built instead of by remaining work. What happens: the rewrite's report celebrates "we built 10 units this month" and gives a sense of progress, even though the remaining work doesn't drop. Why it happens: what's built is visible and satisfying; the scope that reopens is diffuse and isn't counted with the same enthusiasm. How to spot it: compare month against month the remaining work (the example's second table), not the closed units. If you close 10 a month but the remaining drops 4, or doesn't drop, the syndrome is eating 60% or 100% of your effort. How to fix it: the honest metric of a rewrite isn't "how much have we done" but "how much is left, and is that figure really dropping?". A stalled remaining with a team working full out is the exact signature of the second system. Lesson 7 of the decisions guide (fitness functions) gives the general idea of protecting a property with an automated test; here it's enough to plot the remaining and demand that it drop.
Believing discipline will suffice "this time." What happens: the team recognizes the syndrome but believes it'll avoid it by sheer willpower —"we're going to freeze the scope and not give in"—. Why it happens: it's easier to promise discipline than to change the structure of the work. How to spot it: if the only plan against scope creep is "have discipline," without a structural mechanism that makes it cheap, discipline is going to give in at the thousandth reasonable suggestion. How to fix it: don't bet on will; change the structure. The small size and the parity goal of each incremental slice make the "while we're at it" have nowhere to enter —not because the team is stronger, but because the step is so small that inflating it is obvious and absurd—. It's the difference between resisting temptation and not exposing yourself to it.
Exercises
Exercise 1 — Compute the slip. A rewrite has an initial scope of 300 units and a team that closes 15 per month. With frozen scope, in what month does it close? Now apply a 40% gold-plating (for every 15 closed, 6 reopen). What's the net progress per month and in what month does it close approximately? And with 100% inflation?
See solution
- Frozen scope (0%): close = 300 / 15 = month 20.
- 40% gold-plating: for every 15 closed,
15 * 0.40 = 6reopen, so the net progress is15 - 6 = 9units per month. Close ≈300 / 9 = 33.3, i.e. month 34 (rounding up, because month 33 doesn't yet reach 0). The slip is 34/20 ≈ 1.7x, and only for a 40% inflation that many teams would consider moderate. - 100% inflation:
15 * 1.0 = 15reopen for every 15 closed; net progress =15 - 15 = 0. The remaining work stays nailed at 300 forever: it NEVER closes. The team produces 15 units of real work every month and doesn't get a step closer to the goal, because each advance generates its own setback.
The lesson: the progress that matters is the net (closed minus reopened), not the gross (closed). A fast team with high inflation can have very slow or null net progress, without its gross speed betraying it.
Exercise 2 — Mercado's "while we're at it." During the rewrite of Mercado's catalog, these three proposals arise: (a) "since we're redoing the catalog, let's make it generic to support services in addition to physical products"; (b) "since we're touching images, let's add product video support we always wanted"; (c) "since we're migrating search, let's put in semantic AI search." For each, say whether it's second-system scope creep and how you'd handle it without derailing the rewrite.
See solution
All three are classic second-system scope creep: none is parity with what the catalog does today; all are new improvements that sneak in under the "while we're at it." The correct handling is the same for all three, with nuances:
- (a) Generic catalog for services. It's the most dangerous because it sounds like "good architecture": generalize. But the current catalog only handles physical products, so supporting services is pure new scope. Handling: freeze the slice at "do what the catalog does today, but in the new service." If the business really wants to sell services, that's a feature with its own business case, scheduled after the modernized catalog is in production —as a conscious decision, not as a stowaway—.
- (b) Product video. Clear improvement, not parity. Same treatment: out of the migration's scope; schedule it as a separate post-parity feature. Note that putting it in now also enlarges lesson 2's moving target (more features to match).
- (c) Semantic AI search. The most tempting and the most expensive. It's a whole project, not a "while we're at it." Putting it in the catalog rewrite is a guarantee of derailment. Out; let it compete as an initiative of its own with its own budget.
The principle: during the migration, the goal is to match, not improve. The three proposals may be good ideas —but as separate decisions, after the turn-off, not as scope inflation while you try to close.
Exercise 3 — Why the first system was simple. Brooks observes that an engineer's first system tends to be simple and the second tends to be overloaded. Explain, in your words, why the lack of knowledge in the first system ends up being an advantage, and why the knowledge accumulated in the second ends up being a trap.
See solution
In the first system, the engineer doesn't know the domain, so they move cautiously: they only build what is clearly necessary, because they don't have the confidence to add speculative generalizations ("I don't know if this will be needed, better not do it"). That ignorance works as a natural brake on scope: not knowing what could be needed, they do only what is needed. The result is simple, not by virtue, but by forced prudence.
In the second system, the engineer already knows the domain, and with the knowledge comes confidence —and a mental list of everything they had to leave out of the first—. Now they feel authorized to "do it right": generalize, anticipate cases, add the flexibility they didn't dare put in before. The problem is that much of that flexibility is speculative (it solves problems that may never arrive) and all of it inflates the scope. The knowledge becomes a trap because it turns "I don't know if it'll be needed" into "I know that someday it could be needed, so I'll put it in now" —and that now is what derails the calendar—.
The moral for modernization: the humility of the first system is exactly what the incremental approach recovers artificially. By forcing the goal to be "parity with what already exists," it takes away the team's permission to "do it better right away," and with that it reintroduces the simplicity that knowledge tends to destroy. Lesson 5 develops it as the case for incremental.
Summary and next step
In this lesson you opened the big rewrite's second failure mode: the second-system syndrome. You saw, with the kitchen remodel that never ends, that each "while we're at it" is reasonable on its own and catastrophic together, because it reopens the scope exactly when you try to close it. And you measured it: a 30% gold-plating slides the close from month 20 to 29; 60% takes it to 50 (a 2.5x slip); and 100% pushes it to infinity, with the remaining work nailed despite a team working full tilt. This failure mode doesn't come from the business or from incompetence: it comes from the team's own enthusiasm, and that's why pure discipline is fragile against it. The robust antidote is structural: the small scope and the parity goal of each incremental slice leave the syndrome no room.
Before moving on you should be able to: explain why the second system is the most dangerous; compute how scope inflation reduces net progress and slides the closing date; distinguish "it's cheaper to do it now" from "we should do it now"; and argue why the incremental structure resists the syndrome better than will.
Lesson 4 closes the trio of failure modes with the subtlest and most dangerous: the tacit knowledge buried in the legacy. You'll see that the "weird" parts of the old code —the ones a clean rewrite would want to throw away— are almost never bugs, but business rules won over years that nobody documented, and you'll count the silent regressions a blind rewrite introduces by ignoring them.
Resources
- Frederick P. Brooks, The Mythical Man-Month (Addison-Wesley, 1975), ch. 5 "The Second-System Effect" — the original source of this lesson's concept. Brooks describes how the second system tends toward over-engineering with all the ideas the first, out of prudence, left out. Required reading of the craft. In English.
- Joel Spolsky, "Things You Should Never Do, Part I" (2000) — joelonsoftware.com/2000/04/06/things-you-should-never-do-part-i. Connects the second system with the concrete failure of Netscape's rewrite. In English.
- Steve McConnell, Rapid Development (Microsoft Press, 1996), ch. on "Feature Creep" — the classic treatment of scope creep as one of the main causes of project failure, with strategies to control it. In English.
- Sam Newman, Monolith to Microservices (O'Reilly, 2019) — how the bounded size of each migration step structurally limits scope inflation; the deep dive's antidote, developed. In English.