Module 1: Why Not Rewrite
Mini-project: build the defense against Mercado's rewrite
Overview
This is the module's capstone. Over seven lessons you installed the complete "why": the big rewrite's four failure modes (the business that doesn't stop, the moving parity, the second system, the tacit knowledge), the case for incremental (early value, bounded risk), the strangler fig metaphor, and the measured criterion of when each path is correct. Now you apply it end to end to a real case: Mercado's team is about to decide between rewriting the monolith from scratch or modernizing it by slices, and it's your job to build the defense against the rewrite —with numbers, not opinions—.
The project's work is the real work of an architect before touching a single line of code: turning the module's conviction into a deliverable a team can use to decide. It has three pieces. First, classify the modules of Mercado's monolith by value and risk to choose which would be the first slice to modernize —because if you go the incremental route, you have to start somewhere, and which one matters—. Second, model the cost/value of big-rewrite vs incremental to put the measured advantage on the table. Third, write a migration recommendation that pulls it all together: which strategy, which first slice, why not the rewrite (with the figures), and where the process goes next. Notice the boundary, which is deliberate: this project does not execute the migration (that's the whole guide), nor write the strangler mechanics (module 3), nor the formal decision with its ADR (that's the decisions guide). It produces what goes before: the reasoned and measured defense of why incremental beats the rewrite in Mercado, and where to start.
Connection with the module. It's the integration of the seven lessons into a single executed deliverable. The module classification uses the value/risk criterion of lessons 5 and 7; the cost/value model uses the value-periods of lesson 5 and the window of silence of lesson 1; the recommendation uses the tacit knowledge of lesson 4 (what "we don't know") and points to the mechanics of the modules that follow. When you finish it, you'll have the artifact that opens the work of the whole guide: a defensible recommendation to modernize Mercado by slices, starting with the catalog. The next step —stretch the net and strangle— is literally module 2 onward.
The reference solution, executed
We're going to build the solution in a single program that does the three steps: it classifies the modules and chooses the first slice, models the cost/value of the two strategies, and issues the recommendation. All with fixed data, reproducible.
Part 1 — The data: the modules of Mercado's monolith
We receive the six modules of the monolith, each scored on three axes from 1 to 5: value (how much is gained by modernizing it), risk (how dangerous it is to touch it) and coupling (how tangled it is with the rest; 1 = easy to peel off). The good first slice, following Sam Newman, is the one of high value and low coupling: valuable enough to be worth it, and easy to detach to learn the mechanics with low risk.
# value = how much is gained by modernizing it (current pain + upside) (1-5)
# risk = how dangerous it is to touch it (criticality, writes) (1-5)
# coupling = how tangled it is with the rest (1 = easy to peel off) (1-5)
MODULES = [
# (name, value, risk, coupling)
("catalog", 5, 2, 2),
("orders", 4, 5, 5),
("payments", 3, 5, 4),
("shipping", 3, 3, 3),
("search", 4, 2, 2),
("auth", 2, 5, 5),
]
Part 2 — The complete program
The three steps, chained. Classify and choose the first slice (lessons 5 and 7), model the cost/value of the two strategies (lessons 1 and 5), and issue the recommendation (lesson 4 for the honesty about what isn't known):
def first_slice_score(value, coupling):
# Good first slice (Newman): HIGH value and LOW coupling -> peels off
# easily, delivers value, and helps learn the mechanics with low risk.
return value - coupling
ranked = sorted(MODULES, key=lambda m: first_slice_score(m[1], m[3]), reverse=True)
print("=== Part 1: slice worklist (what to modernize first) ===")
print(f"{'module':<10}{'value':>7}{'risk':>6}{'coupling':>10}{'slice_score':>13}")
print("-" * 46)
for name, value, risk, coupling in ranked:
print(f"{name:<10}{value:>7}{risk:>6}{coupling:>10}"
f"{first_slice_score(value, coupling):>13}")
first = ranked[0]
print(f"\nFirst slice: {first[0]} "
f"(value {first[1]}, coupling {first[3]}: valuable and easy to peel off)")
# --- Part 2: big-rewrite vs incremental, measured -----------------------------
SLICES = len(MODULES) # 6 modules = 6 slices
HORIZON = 9 # periods observed
FEATURES_PER_PERIOD = 4 # what the business keeps asking for, it doesn't stop
inc_value = rw_value = rw_slip_value = 0
rw_backlog = 0
for t in range(1, HORIZON + 1):
inc_value += min(t, SLICES) # one slice delivered per period
rw_value += SLICES if t >= 6 else 0 # optimistic cutover in period 6
rw_slip_value += SLICES if t >= HORIZON else 0 # cutover that slips to the end
rw_backlog += FEATURES_PER_PERIOD # features frozen in the rewrite
print("\n=== Part 2: value-periods delivered in 9 periods ===")
print(f" incremental : {inc_value:>3} value-periods, backlog 0")
print(f" big-rewrite (cutover 6): {rw_value:>3} value-periods, backlog {rw_backlog}")
print(f" big-rewrite (slip 9) : {rw_slip_value:>3} value-periods, backlog {rw_backlog}")
print(f" incremental advantage vs optimistic rewrite: "
f"{inc_value / rw_value:.1f}x more value delivered")
# --- Part 3: the recommendation (NOT an ADR; the ADR is architecture-decisions) --
print("\n=== Part 3: migration recommendation ===")
print(f"Strategy: incremental (strangler fig), NOT a big rewrite.")
print(f"First: {first[0]} (high value, low coupling, few writes).")
print(f"Why not rewrite: it delivers {rw_value} value-periods vs {inc_value} from")
print(f" incremental, freezes {rw_backlog} features and risks 100%")
print(f" of the system in a single cutover.")
print(f"We know: catalog is read-heavy and clean-boundaried; it peels off with low risk.")
print(f"We don't: its exact behavior at the edges (tacit rules with no docs).")
print(f"Next: put it under characterization tests (M2), then strangler (M3),")
print(f" extract the service (M5), migrate data (M6), and measure progress (M7).")
What to expect. When you run the complete file, the output is exactly this:
=== Part 1: slice worklist (what to modernize first) ===
module value risk coupling slice_score
----------------------------------------------
catalog 5 2 2 3
search 4 2 2 2
shipping 3 3 3 0
orders 4 5 5 -1
payments 3 5 4 -1
auth 2 5 5 -3
First slice: catalog (value 5, coupling 2: valuable and easy to peel off)
=== Part 2: value-periods delivered in 9 periods ===
incremental : 39 value-periods, backlog 0
big-rewrite (cutover 6): 24 value-periods, backlog 36
big-rewrite (slip 9) : 6 value-periods, backlog 36
incremental advantage vs optimistic rewrite: 1.6x more value delivered
=== Part 3: migration recommendation ===
Strategy: incremental (strangler fig), NOT a big rewrite.
First: catalog (high value, low coupling, few writes).
Why not rewrite: it delivers 24 value-periods vs 39 from
incremental, freezes 36 features and risks 100%
of the system in a single cutover.
We know: catalog is read-heavy and clean-boundaried; it peels off with low risk.
We don't: its exact behavior at the edges (tacit rules with no docs).
Next: put it under characterization tests (M2), then strangler (M3),
extract the service (M5), migrate data (M6), and measure progress (M7).
Part 3 — The justification, read from the run itself
Part 1 ordered the six modules by slice_score (value minus coupling) and the winner is clear: catalog, with score 3. It's not at the top because it "sounds important," but because it combines the two things you look for in a first slice: high value (5, because it's read-heavy and a modernization with a cache would give it a big performance jump) and low coupling (2, because the catalog is mostly reads with a relatively clean boundary, easy to detach from the rest). It's followed by search (score 2, also valuable and lightly coupled), and then the heavy modules fall: orders, payments, and auth have negative scores, not because they aren't worth it, but because their high coupling (5, 4, 5) makes them hard and dangerous to peel off as the first slice. Careful with the reading: a negative score doesn't mean "never modernize"; it means "don't start here." You start where you learn the mechanics with low risk —the catalog—, and you leave the coupled and critical modules for when the team already masters the pattern.
Notice the distinction between value, risk, and coupling. risk doesn't enter the slice_score —the order is decided by value and coupling—, but it's information the recommendation uses: the catalog has risk 2 (few writes, mostly reads), which reinforces that it's a safe first slice. orders and payments, with risk 5, are exactly the modules where an error costs dearly (money, orders), so touching them first, without experience with the pattern, would be reckless. The ideal first slice is valuable, lightly coupled and low-risk: the catalog meets all three.
Part 2 puts incremental's advantage into numbers, bringing together lesson 1 and lesson 5. In 9 periods, incremental delivers 39 value-periods (one slice per period, accumulating value from the first) against 24 from the optimistic rewrite (which delivers the 6 all at once in period 6) and barely 6 from the late rewrite (which delivers everything in the last period). Incremental's advantage over the optimistic rewrite is 1.6x, and over the late one —the realistic scenario— 6.5x. And don't forget the backlog column: the rewrite freezes 36 features the business asked for and didn't receive over the 9 periods, while incremental delivered them all (backlog 0). The same effort, but one delivers value and features along the way and the other asks for silence.
Part 3 is the piece that integrates everything: the migration recommendation. Notice its structure, which inherits the decision brief from the sibling guide but adapted to migration: Strategy (incremental/strangler, not rewrite), First (catalog, with its value/coupling/risk justification), Why not rewrite (the figures: 24 vs 39 value-periods, 36 frozen features, 100% of the system at risk in one cutover), We know (what the evidence says: catalog is read-heavy and clean-boundaried), We don't (the honest fog of lesson 4: the catalog's tacit rules no doc captures), and Next (where it goes: M2 characterize → M3 strangler → M5 extract → M6 data → M7 measure). That recommendation doesn't execute the migration —it doesn't write the router or the tests—; it does something more valuable at this stage: it makes explicit, with numbers, why incremental beats the rewrite in Mercado, where to start, what's unknown, and what the path is. A team that starts from this recommendation doesn't start from scratch: it starts with the defense already made.
This project is the step 0 of a journey the rest of the guide completes:
flowchart LR
P["Project M1<br/>recommendation + first slice<br/>(step 0: why and where)"] --> M2["M2<br/>characterization tests<br/>(stretch the net)"]
M2 --> M3["M3<br/>strangler fig<br/>(divert traffic)"]
M3 --> M5["M5<br/>extract the service"]
M5 --> M6["M6<br/>migrate the data"]
M6 --> M7["M7<br/>measure the progress"]
Read it like this: here you decide why incremental and where to start; from there on, the guide takes the catalog from "chosen as first slice" to "modernized, with its data migrated and the old route turned off."
Your deliverable
Reproduce and adapt the reference solution. Your deliverable has three pieces:
- The executed slice worklist: Mercado's modules scored on value/risk/coupling and ordered by
slice_score, with the literal output of your program. You can use the example's modules or —better— add one or two of your own Mercado modules (for example,reviewsornotifications) and score them yourself, justifying each axis. - The cost/value model: the value-periods of incremental vs rewrite (on time and late) and the frozen backlog, with incremental's advantage factor. If you changed the number of modules, adjust
SLICESand observe how the figures move. - The migration recommendation: the six-line structure —Strategy / First / Why not rewrite / We know / We don't / Next—, honest about what isn't known (lesson 4's tacit knowledge). Don't execute the migration; justify why incremental wins and where to start.
Common mistakes
Choosing the first slice by its importance instead of its suitability. What happens: the project chooses to start with payments or orders "because they're the most important / the ones that hurt most." Why it happens: it seems logical to attack the most critical first. How to spot it: if your first slice is a module of high coupling and risk (negative score in the worklist), you're starting in the wrong place. How to fix it: the first slice isn't chosen by importance but by suitability for learning the pattern with low risk —high value, low coupling, low risk—. The catalog is the correct choice precisely because it's valuable and easy to peel off and low-risk: it lets you master the strangler mechanics before touching the dangerous modules. Starting with payments is learning to walk the highest tightrope without having practiced on the ground. The critical modules are modernized later, with the pattern already mastered. (Importance does matter —but for the general order, not for the first slice—.)
Writing a recommendation that fakes total certainty. What happens: the "We don't" line stays empty or says something cosmetic, and the recommendation sounds as if the catalog's whole behavior were already known. Why it happens: admitting what you don't know feels like weakness, when it's the opposite —it's the honesty lesson 4 made indispensable—. How to spot it: if your recommendation doesn't name any real uncertainty about the module's tacit knowledge, it isn't an honest migration recommendation; it's a declaration of faith. How to fix it: name the concrete fog (here, "the catalog's tacit rules no doc captures," like lesson 4's hidden rules) and still recommend advancing, because the first step —stretching the net with characterization tests— is precisely what turns that fog into captured behavior. A good recommendation says both things: "this we don't know" and "that's why step 1 is to characterize it, not to rewrite it blind."
Sliding from "recommending" to "executing the migration." What happens: the project drifts into designing the strangler router, or writing the catalog's characterization tests, or deciding the new service's stack. Why it happens: it's the "hands-on" part and it's where many want to jump. How to spot it: if your deliverable starts to contain migration code (the strangler_router, the tests, the new data schema), you've gone out of scope. How to fix it: remember the boundary. This project produces the defense and the prioritization, not the execution. Stretching the net is module 2; the router is module 3; extracting the service is module 5. Here you only decide why incremental and where to start, with the numbers that justify it —the recommendation ends in "Next: M2, M3...", not in a working router—.
Exercises
Exercise 1 — Add a module and re-prioritize. Mercado also has a reviews module (product reviews): value 3 (improves conversion, but it's not central), risk 2 (mostly reads and simple writes, not very critical) and coupling 2 (fairly independent, tied only to the catalog). Compute its slice_score, say what position in the worklist it would fall into, and argue whether it would be a good second slice after the catalog.
See solution
slice_score = value - coupling = 3 - 2 = 1. In the example's worklist, a score of 1 would fall between shipping (0) and search (2) —approximately fourth position, below catalog (3) and search (2), and above shipping (0) and the heavy modules with a negative score—.
A good second slice after the catalog? Yes, and for a reason that goes beyond the score: reviews is coupled precisely to the catalog (coupling 2, tied to it). Once the catalog is already modernized and extracted (the first slice), reviews becomes a natural continuation —it consumes the new catalog, shares its boundary, and the team already learned the strangler mechanics with the catalog—. Its risk is low (2) and its value decent (3). It's not the most urgent, but it's a low-risk second slice that leverages the work already done and consolidates the pattern before attacking the heavy modules (orders, payments). The method lesson: after the first slice, it's best to continue with the adjacent and low-risk, not to jump straight to the most critical. (The fine ordering of the intermediate slices is the topic of module 7, measuring progress; here it's enough to place it.)
Exercise 2 — Defend the choice of the catalog. A colleague looks at the worklist and objects: "catalog has value 5 and orders value 4, almost the same; but orders is the heart of the business. Let's start with orders, which is what really matters." Give an argument, using the module's concepts, for why starting with the catalog is the best play despite orders being more central.
See solution
The colleague has a valid point —orders is more central to the business— but confuses "most important" with "best first slice," and they're not the same. A module's importance tells you it has to be modernized eventually; suitability as the first slice is decided by other factors: the coupling and the risk.
And there catalog clearly wins:
- Coupling.
cataloghas coupling 2 (clean boundary, mostly reads), whereasordershas coupling 5 (tangled with payments, shipping, inventory). Peeling offordersfirst means untangling its connections with half the system simultaneously —exactly the hardest operation— without having practiced the pattern before. Peeling offcatalogfirst is detaching an almost independent piece: the strangler mechanics are learned with a manageable case. - Risk.
ordershas risk 5 (it handles orders and money; an error costs dearly and is hard to revert), against risk 2 forcatalog(mostly reads; an error is tolerable and reversible). Debuting the migration pattern in the module where a failure costs most is exactly the play lesson 5 (risk at stake) advises against.
The rule: you start where you learn the pattern with low risk, not with the most important in the abstract. Modernizing orders calmly and thoroughly later, with the team already expert in the strangler after having done the catalog (and perhaps search and reviews), is much safer than debuting the technique in the most critical and coupled module. Starting with the catalog doesn't postpone orders out of fear; it prepares it to be done right. Suitability governs the first slice; importance governs that none is left un-modernized. They're two different knobs.
Exercise 3 — Close the arc: from the recommendation to what comes next. The recommendation ends in "Next: characterization tests (M2), then strangler (M3), extract the service (M5), migrate data (M6), and measure progress (M7)". List, in order, the steps that would follow this recommendation to take the catalog from "chosen as first slice" to "modernized and with the old route turned off," naming which module of the guide covers each one.
See solution
The complete journey, from where this project leaves it:
- Stretch the net: characterization tests (module 2). Before touching the catalog, capture its current behavior —quirks included, like lesson 4's hidden rules— with tests that pin what it does today. Find the seam where to insert the test. This turns the "We don't" fog into captured behavior, and it's the prerequisite of any safe change (the coverage lever, lesson 7).
- Put the facade and divert traffic: strangler fig (module 3). Set up the
strangler_routerin front of the catalog, build the new service beside it, and divert traffic incrementally (by percentage or feature flag) with the old route as fallback —the mechanics of lesson 6's metaphor—. - Extract the service: anti-corruption layer (module 5). Separate the catalog from the monolith as its own service, with an anti-corruption layer that translates between the old model and the new one, and define the ownership of its data.
- Migrate the data without downtime (module 6). Move the catalog's data with expand-contract: dual-write (write to both), backfill (fill in the history), parallel-run (read from both and compare before trusting) and the final read-switch. The parallel-run's comparison catches the tacit-knowledge regressions before the switch.
- Measure the progress (module 7). With progress metrics —% of traffic on the new route, burn-down of calls to the legacy— know whether the migration is advancing and when it finished, and turn off the catalog's old route only when 100% has passed stably. Avoid the eternal migration that never turns off the old.
This project (module 1) is step 0: the defense that says why incremental and where to start. Everything else —stretch the net, strangle, extract, migrate, measure— is the rest of the guide, and module 8 travels that whole arc with the catalog end to end.
Summary and next step
You closed the module by applying its complete method to a real case. You took Mercado's monolith and produced the artifact that opens the work of a migration architect: a slice worklist that classifies the six modules by value and coupling and chooses the catalog as the first slice (valuable, lightly coupled, low-risk); a cost/value model that shows incremental's advantage in numbers (39 value-periods against 24 or 6 for the rewrite, with 36 frozen features on the rewrite's side); and an honest migration recommendation that pulls together the strategy, the first slice, the why-not-rewrite, what's known, what isn't, and where it goes next. You didn't execute the migration or write the router: you did the step 0 that tells the team why incremental wins and where to start.
With this the module 1 ends. You already have the complete "why": you know why the big rewrite fails (the four failure modes), why incremental wins (early value, bounded risk), what the strangler fig is, and when each path is correct. What follows in the guide is the "how." Module 2 attacks the first and indispensable thing: characterize and pin the legacy —work with code that scares you and has no tests, put in the characterization test that captures the current behavior (bugs included) before touching anything, and find the seam where to insert the change—. It's the safety net lesson 7 identified as the key lever, and the prerequisite of everything else. The recommendation you just wrote ends exactly there: "Next: characterize the catalog." Module 2 does it.
Resources
- Sam Newman, Monolith to Microservices (O'Reilly, 2019), ch. 3, "Splitting the Monolith" — how to choose the first slice by coupling and value, and the extraction order of a monolith. The direct framework for Part 1 of this project. In English.
- Michael Feathers, Working Effectively with Legacy Code (Prentice Hall, 2004) — the immediate destination of the recommendation: characterize the catalog with tests before touching it. Module 2 of this guide. In English.
- Martin Fowler, "StranglerFigApplication" (2004) — martinfowler.com/bliki/StranglerFigApplication.html. Where the first slice goes once chosen: the pattern that diverts it little by little. Module 3. In English.
- Joel Spolsky, "Things You Should Never Do, Part I" (2000) — joelonsoftware.com/2000/04/06/things-you-should-never-do-part-i. The defense against the rewrite this project formalizes with numbers, told with the real Netscape case. In English.
- microservices.io, "Refactoring a Monolith to Microservices" — microservices.io/refactoring/index.html. Catalog of patterns for migrating a monolith in parts, reference for modules 3 through 7. In English.