Module 6: Designing for Change
The architecture is never final
Overview
The previous lesson installed the thesis with a measurement: in five years, three quarters of the assumptions of Mercado's day-one design get invalidated. This lesson takes that thesis and turns it into an operational stance: if the design erodes no matter what, then the architecture isn't a frozen artifact —a blueprint that's drawn, approved, and filed— but a flow of decisions that runs as long as the system is alive. Every time an assumption falls, the system receives a new decision. The architect's question isn't "is the architecture finished?" —it never is— but "is it postured to receive the next decision cheaply, or is it going to fight against it?".
This mindset shift —from the photo to the film— has a consequence that isn't obvious and that this lesson measures: what breaks a system is almost never an individual change. A big, painful change is seen coming and handled. What breaks is the accumulation: hundreds of small changes pushed against a structure treated as final, each one a bit more expensive than the last because the structure wasn't designed to move. The drift accumulates slowly, invisibly, until one day a trivial change takes three weeks and no one understands why. This lesson puts a number on that accumulation: it compares the total cost, over the life of Mercado, of treating the architecture as frozen against treating it as a flow —and shows the difference isn't in any one change, but in the sum of all of them—.
Connection with the module. It's the first of the three lessons that install the basic stance (this one: the architecture is a flow; lesson 3: keeping options open; lesson 4: building to throw away). Here we don't yet talk about how to leave seams —that's lessons 5, 6, and 7—; we install the mental frame that makes leaving them make sense: if you don't believe the architecture is a flow, you're not going to bother posturing it for change. Frontier with the sister guide: the mechanics of managing change decision by decision (technical debt, last responsible moment) is architecture-decisions; here we work the disposition of seeing the system as a film in progress, not as a finished photo.
An analogy: the house that's lived in vs. the house that's finished
Think about two ways to have a house, and how each one ages.
The house that's finished. A couple builds their dream house with a perfect blueprint: every wall in its place, every outlet calculated, the kitchen exactly where they wanted it the day they designed it. The day they move in, the house is finished —that's the word they use—. And they treat it as finished: it's a completed work to preserve. The years pass. A child comes, and one more room is needed: but the walls are load-bearing, moving them is very expensive, so they squeeze the kid into a corner. The job changes, an office is needed: but there's nowhere, everything is fixed, so they work at the dining table. The time comes to install solar panels, chargers, fiber: but the electrical installation was calculated for the appliances of twenty years ago, and updating it means breaking walls. Every new need fights against a house declared finished, and every fight is more expensive than the last, because every fix stacks on the previous one's patches. The house didn't fail from a blow; it became uninhabitable by accumulation.
The house that's lived in. Another couple builds thinking differently: the house isn't a work that's finished, it's a space that's going to be lived in and changed over decades. So they leave things in place for the future they don't know: non-structural interior walls, easy to move; an electrical installation with spare capacity and accessible junction boxes; an attic that can be converted into a room; pipes with capped outlets where someday there'll be a bathroom. None of that is building the child's room or the office in advance —they don't yet know they'll come—; it's leaving the house ready to receive them. When the child comes, moving a non-structural wall is a weekend. When remote work comes, the attic becomes an office in two weeks. When the panels come, the installation already had capacity. The house ages well, not because they guessed the future, but because it was never declared finished: it was designed to keep changing.
Here's the point, and it's subtle: the difference between the two houses isn't seen the day they're built —both look perfect—; it's seen over the years, in the sum of all the changes. The first house isn't worse on day one; it's worse over time, because every change fights against a frozen structure and the costs accumulate. The second isn't a "more flexible" house in the abstract; it's a house that recognized it was going to change and postured itself for it. The software system is the same. The architecture treated as "finished" doesn't fail the day it launches —it looks perfect—; it fails in the accumulation of changes that fight against it. The architecture treated as a flow ages well because it was never declared final. This lesson measures that accumulation, which is where the difference lives.
Worked example: the accumulated cost of freezing vs. flowing
We're going to measure what the analogy asserts: that the difference between the two stances isn't in any individual change, but in the sum over the life of the system. We take the same sequence of eight business changes Mercado receives, one quarter after another —the same changes, in the same order, with the same base cost—, and run them through two architectures.
frozen— the architecture treated as final. Each change fights against a structure that wasn't designed to move, and the drift accumulates: the farther the system gets from the original frozen design, the worse the next change fits. The cost multiplier starts at 1.0 and rises half a point with each change that stacks.evolving— the architecture treated as a flow. It was postured to receive changes, so each one costs near its base cost (a constant and low multiplier, of 1.1). There's no accumulated drift because the system was ready to move.
Notice the experiment's design: the base cost of each change is identical in both architectures. The only thing that differs is how the structure receives the change. That way we isolate the effect of the stance:
# The architecture isn't an artifact that freezes on day one; it's a FLOW of
# decisions over the life of the system. Two stances facing the SAME
# sequence of 8 business changes Mercado receives, one quarter after another:
# frozen : the architecture was treated as final. Each change fights against a
# structure not designed to move, and the "drift" accumulates:
# the farther from the original design, the more expensive to fit the next.
# evolving: the architecture was treated as a flow. It was designed to RECEIVE
# changes, so each one costs near its base cost.
CHANGES = [
# (quarter, change, base_cost_usd)
("Q1", "add_wishlist", 8000),
("Q2", "split_search_service", 12000),
("Q3", "second_payments_provider",10000),
("Q4", "reviews_and_ratings", 14000),
("Q5", "international_currencies", 16000),
("Q6", "seller_self_service_api", 20000),
("Q7", "async_shipping_events", 12000),
("Q8", "recommendations_ml", 18000),
]
def frozen_multiplier(step):
# The drift accumulates: each change leaves the structure farther from the
# frozen design, so the next fits worse. Starts at 1.0 and rises 0.5 per step.
return 1.0 + 0.5 * step
EVOLVING_MULTIPLIER = 1.1 # an architecture designed to receive change costs ~its base
print(f"{'qtr':<6}{'change':<26}{'base':>8}{'frozen':>10}{'evolving':>10}")
print("-" * 60)
frozen_total = evolving_total = 0
for step, (q, name, base) in enumerate(CHANGES):
fc = base * frozen_multiplier(step)
ec = base * EVOLVING_MULTIPLIER
frozen_total += fc
evolving_total += ec
print(f"{q:<6}{name:<26}{base:>8,}{fc:>10,.0f}{ec:>10,.0f}")
print("-" * 60)
print(f"{'ACCUMULATED TOTAL (USD)':<40}{frozen_total:>10,.0f}{evolving_total:>10,.0f}")
print()
print("No individual change breaks the system; what breaks it is the")
print(f"ACCUMULATION over the life of the system: {frozen_total / evolving_total:.1f}x more expensive")
print("to treat the architecture as final than as a flow of decisions.")
What to expect. Running the file, the output is exactly this:
qtr change base frozen evolving
------------------------------------------------------------
Q1 add_wishlist 8,000 8,000 8,800
Q2 split_search_service 12,000 18,000 13,200
Q3 second_payments_provider 10,000 20,000 11,000
Q4 reviews_and_ratings 14,000 35,000 15,400
Q5 international_currencies 16,000 48,000 17,600
Q6 seller_self_service_api 20,000 70,000 22,000
Q7 async_shipping_events 12,000 48,000 13,200
Q8 recommendations_ml 18,000 81,000 19,800
------------------------------------------------------------
ACCUMULATED TOTAL (USD) 328,000 121,000
No individual change breaks the system; what breaks it is the
ACCUMULATION over the life of the system: 2.7x more expensive
to treat the architecture as final than as a flow of decisions.
Read the table row by row, because the whole argument is in how the two columns separate over time.
In the first change (Q1), the two architectures cost almost the same. frozen costs 8000, evolving 8800 —in fact frozen is a bit cheaper at the start, because it didn't pay the "premium" of being postured for change (the 1.1 multiplier)—. This is the detail that fools so many people: on day one, freezing looks equal to or better than flowing. The architect who freezes saved the small investment of leaving the system ready to move, and in the first change the difference isn't noticed. Just as the two houses look perfect the day they're built.
But look at how they diverge. In Q4, frozen already costs 35000 against evolving's 15400 —more than double—. In Q8, the same kind of change (recommendations_ml, base 18000) costs 81000 in the frozen architecture against 19800 in the fluid one —more than four times—. The base cost is identical; what changed is that in frozen the drift accumulated: each change left the structure farther from its original design, so the eighth change has to force its way through seven layers of previous patches. In evolving, the eighth change costs almost the same as the first, because the structure was still ready to receive it.
And there's the lesson, in the totals: 328000 against 121000, 2.7 times more expensive. But the number that matters isn't the 2.7; it's where it comes from. It doesn't come from any catastrophic change —there was no "big redesign" that cost a fortune—. It comes from the accumulation: eight normal changes, each a bit more expensive in the frozen architecture, that summed triple the cost. This is the heart of why "the architecture is never final" is a stance and not a pretty phrase: whoever treats the architecture as finished doesn't pay on day one —they pay in growing installments over the whole life of the system, and the total bill is brutal—.
As bars, the divergence per quarter looks like this:
Cost per change (USD): frozen vs evolving, quarter by quarter
Q1 frozen |## 8,000 evolving |## 8,800
Q4 frozen |######### 35,000 evolving |### 15,400
Q8 frozen |#################### 81,000 evolving |### 19,800
─────────────────────
frozen shoots up; evolving stays flat. The gap IS the stance.
Deep dive: why "final" is the dangerous word
The experiment modeled the accumulated drift with a growing multiplier, and it's worth understanding what that growth represents in the real world, because it's not a trick of the model: it's a well-documented phenomenon.
When an architecture is treated as final, each change the business imposes is implemented against the structure, not with it. Since the structure wasn't designed for that change, the change gets in however it can: a patch here, an exception there, a new dependency that crosses a boundary it "shouldn't" cross. Each of those patches leaves the system a bit farther from any coherent design, and —this is the key— makes the next change harder, because now you also have to understand and work around the previous patches. It's compound interest: today's mess makes tomorrow's work more expensive, which in turn adds more mess. That's exactly what the sister guide architecture-decisions studies as technical debt —and its mechanics, how to measure and pay it, is that guide's, not this one's—. Here what matters is the stance that generates it: technical debt isn't born from careless programmers; it's born, in good part, from treating the architecture as a finished artifact to defend instead of a flow to accompany.
There's a psychological reason "final" is so tempting, and it's worth naming. A finished design feels like an achievement. It takes effort, it's presented, it's approved, and it produces the feeling of having closed something. A flow, by contrast, never closes: it's always in progress, there's always one more decision to come. For an architect who needs the satisfaction of "finishing", the flow is uncomfortable —it seems the work never ends—. But that discomfort is the sign of having understood the craft: the architect's work, by design, doesn't end while the system lives. It's not a defect of the role; it's its nature. The architect who seeks the peace of "it's done" is going to treat every subsequent change as an intrusion, and is going to freeze. The one who makes peace with the flow is going to receive every change as the normal thing, and is going to flow.
And there's a nuance that avoids the opposite misunderstanding, important so as not to fall on the other side. "The architecture is never final" does not mean "redesign it all the time" nor "never commit to anything". An architect who remakes the structure every quarter out of trend or anxiety is as harmful as the one who freezes —in fact, it's paralysis from the other extreme—. Flowing isn't changing for change's sake; it's being ready and postured to change when the business asks, and still when it doesn't. The fluid architecture of the example wasn't redesigned eight times; it was designed once to receive the eight cheap changes. The right stance is a stable commitment to a structure that, on purpose, left room to move —neither the freezing that fights against every change, nor the nervousness that doesn't commit to anything—. That fine calibration is exactly what lessons 5, 6, and 7 will teach to measure: where to leave room (a seam) and where not.
A consequence for how the architect measures their own work. If the architecture is a flow, then the architect shouldn't measure their success by "how good the initial design was" —that metric rewards freezing—, but by "how cheaply the system absorbs the changes the business asks for". An elegant initial design that makes every subsequent change more expensive is a bad design, however pretty it was on day one; a modest initial design that receives cheap changes for years is a great design. The craft's metric isn't the beauty of the blueprint; it's the slope of the cost of change over time. The frozen architecture had, perhaps, a "cleaner" initial design (it didn't pay the premium of the seams); its slope sank it. The evolving one paid a bit more on day one and kept the slope flat. That slope is what an architect who understands the flow watches.
Common mistakes
Declaring the architecture "finished" and defending it. What happens: the architect invests in an initial design, approves it, and from there treats the business's changes as threats to a completed work —"that breaks the architecture"— instead of as the normal state of a living system. The system accumulates patches because no one wants to move it "for real". Why it happens: a finished design feels like an achievement that gives peace, and the flow —which never closes— is uncomfortable; besides, the grammar of "the system is this way" pushes toward thinking in photos. How to spot it: if you hear "that breaks the architecture" in the face of reasonable features, if every change is lived as an emergency, or if the architect resists touching the structure even though the business clearly changed, a photo is being defended. How to fix it: adopt the flow metric —measure the slope of the cost of change, not the beauty of the blueprint— and receive every change as the expected. The example measures it: the frozen stance costs 2.7 times more in total, not because of one change, but because of the accumulation.
Confusing "not final" with "redesign it all the time". What happens: the architect, half-understanding that the architecture isn't final, falls on the other side: restructures out of trend or anxiety, never commits to anything, and the team lives in a permanent construction site that never stabilizes. Why it happens: "flow" is read as "change", when flowing is "being ready to change when needed". How to spot it: if the base structure changes every few months without the business having asked for it, if there are perpetual migrations no one finishes, or if the team can't build on anything stable, it's change for change's sake. How to fix it: commit to a stable structure that, on purpose, left room to move —and move it only when the business justifies it, not by reflex—. The fluid architecture of the example was designed once to receive eight changes, it wasn't redesigned eight times.
Judging the design only by day one. What happens: an architecture is evaluated by how clean and elegant it looks at launch, not by how it ages —and the design that saved the "premium" of the seams is rewarded because on day one it looks cheaper and neater—. Why it happens: day one is visible and presentable (a pretty diagram, a successful launch); the slope of the cost of change is invisible until it accumulates, months later. How to spot it: if the conversation about an architecture ends on launch day, or if no one looks at how much it costs to change it six months later, the photo is being judged. How to fix it: judge (and review) architectures by their slope of change cost over time, not by their initial elegance; in the example, frozen started cheaper (8000 vs 8800 in Q1) and ended three times more expensive. Day one lies; the accumulation tells the truth.
Exercises
Exercise 1 — The first-change trap. In the example, the frozen architecture is cheaper than evolving in the first change (8000 against 8800). An engineer looks at that first number and concludes: "freezing is cheaper, let's leave it that way, let's not pay the premium of the seams". Explain why that conclusion is a mistake, and what they should look at instead.
See solution
The conclusion is a mistake because it looks at a photo of a flow. The first change is the only moment when freezing looks better, precisely because frozen didn't pay the small premium (the 1.1 multiplier) of leaving the system postured for change. But that premium isn't waste: it's the investment that keeps the slope of the change cost flat. In the second change frozen already costs more (18000 vs 13200), and the gap only grows: in Q8, frozen costs 81000 against 19800. The engineer is optimizing the first data point of a series that's going to diverge dramatically.
What they should look at isn't the cost of the first change, but the slope of the cost of change over time —the accumulated total over the life of the system—. There frozen costs 328000 and evolving 121000: 2.7 times more. The craft's rule: never judge an architecture by its cost on day one (the photo), judge it by how the cost of changing it ages (the film). Day one lies in favor of freezing; the accumulation tells the truth. It's exactly the two-houses mistake: both look perfect the day they're built, and the difference only appears in the years of changes.
Exercise 2 — Where the 2.7x comes from. The text insists that the number that matters isn't the 2.7, but where it comes from. Explain, without code, what the growing frozen multiplier (1.0, 1.5, 2.0, ...) represents in real terms of a software system, and why that growth is the mechanism of the damage —connect it with the idea of technical debt and with the ecosystem's frontier—.
See solution
The growing frozen multiplier represents the accumulated drift: each change forced against a structure not designed for it leaves the system a bit farther from any coherent design —a patch, an exception, a dependency that crosses a boundary it shouldn't—. And the key point is that that mess makes the next change more expensive: change number eight not only has to do its own work, but understand and work around the previous seven patches. That's why the multiplier rises: it's not that the changes are intrinsically more expensive, it's that the structure they fall on is increasingly tangled by the previous changes.
That's compound interest: today's mess charges interest on tomorrow's work, which adds more mess, which charges more interest. It's precisely the mechanism of technical debt: a structure treated as final accumulates debt with every forced change, and the debt is paid with interest on every future change. Here's the ecosystem's frontier: how to measure that debt, when to pay it, how to classify it, is the mechanics the sister guide architecture-decisions teaches. What this lesson contributes is the stance that originates it: technical debt doesn't come mainly from careless code, but from treating the architecture as a finished artifact to defend, instead of a flow to accompany. The evolving architecture, with its flat 1.1 multiplier, doesn't accumulate that debt because each change is received with the structure, not against it.
Exercise 3 — Flowing isn't redesigning. A Mercado architect, convinced that "the architecture is never final", starts restructuring the system every quarter: one quarter they migrate to one pattern, the next to another, always chasing the "perfect evolutionary design". The team complains that there's never a stable base to build on. Did they misinterpret the lesson? Explain what flowing really is, and how it's distinguished from change for change's sake.
See solution
Yes, they misinterpreted it, and from the opposite side to freezing —but it's just as harmful—. They confused "the architecture is never final" with "you have to be redesigning it always". Flowing is not changing the structure all the time; it's being ready and postured to change it when the business asks, and staying still when it doesn't. This architect is changing by reflex, out of trend or perfectionist anxiety, without any business change justifying it. The result —a team with no stable base, in perpetual construction— is the same kind of damage as freezing, only from the other extreme: the paralysis of the one who never commits.
Real flowing is distinguished from change for change's sake by its trigger: the architect who flows moves the structure when an assumption falls and the business pushes a seam —a real, external change the architecture was postured to receive—; the one who changes for change's sake moves the structure out of internal impulses, with no business trigger. Notice the example: the evolving architecture was not redesigned eight times. It was designed once, with the seams in place, to receive the eight cheap changes. That's flowing: a stable commitment to a structure that, on purpose, left room to move. The calibration —when the room is justified and when it isn't— is what lessons 5, 6, and 7 measure. The right stance lives in the middle: neither the freezing that fights against every change, nor the nervousness that doesn't leave anything still.
Summary and next step
In this lesson you turned the thesis into an operational stance: the architecture isn't a frozen artifact, but a flow of decisions that runs the whole life of the system. You saw, with the two houses, that the difference between freezing and flowing isn't seen on day one —both look perfect— but in the accumulation of changes over the years. And you measured it: running the same sequence of eight changes through the two architectures, the frozen one costs 328000 and the fluid one 121000 —2.7 times more— not because of any catastrophic change, but because of the accumulation of eight normal changes, each a bit more expensive in the structure treated as final. You learned that the craft's metric isn't the beauty of the initial blueprint, but the slope of the cost of change over time, and that "not final" doesn't mean "redesign always" —flowing is being postured to change when the business asks, not changing by reflex—.
Before moving on you should be able to: explain why the cost of freezing isn't seen on day one but in the accumulation; connect the growing multiplier with technical debt (and place its mechanics in the sister guide); and distinguish flowing (postured to change) from change for change's sake (perpetual construction site).
Lesson 3 takes the second piece of the stance: optionality, keeping the doors open. If the architecture is a flow that's going to receive uncertain changes, how much is it worth leaving an option open for a change that might come? You'll see that an open option has value even if you never exercise it —like insurance— but that it costs a premium, and execute the break-even point: when that premium is worth it and when it's wasted. With numbers, so that "keep the doors open" stops being advice and becomes a measurable decision.
Resources
- Neal Ford, Rebecca Parsons, and Patrick Kua, Building Evolutionary Architectures (O'Reilly, 2017), ch. 1 ("Software Architecture") — the canonical development of this lesson's idea: architecture as something that evolves guided by fitness functions, not an artifact that freezes. In English.
- Martin Fowler, "Is Design Dead?" (2004) — martinfowler.com/articles/designDead.html. On how design doesn't die with the evolutionary, but changes nature: from a finished blueprint to a continuous practice. This lesson's photo/film distinction. In English.
- Andrew Hunt and David Thomas, The Pragmatic Programmer, 20th Anniversary Edition (Addison-Wesley, 2019), topic "Reversibility" — the root of why there are no final decisions and why the software that ages well is the one that didn't marry irreversible assumptions. In English.
- Mark Richards and Neal Ford, Fundamentals of Software Architecture, 2nd ed. (O'Reilly, 2020), ch. 19 ("Architecture Decisions") — on why significant decisions are measured by their cost of change over time, the "slope" metric this lesson works. The mechanics of technical debt and the last responsible moment lives in the sister guide
architecture-decisions. In English.