Why this matters
Every piece of software provides two values to its stakeholders: behavior (what it does right now) and structure (its ability to change). Most developers and business stakeholders focus entirely on behavior — if it works, ship it. But a system that works today and cannot be changed tomorrow has already begun to die.
Martin argues that structure is more important than behavior. A system that doesn't quite work but is easy to fix can be made to work. A system that works perfectly but can never be changed will become useless the moment requirements shift — and requirements always shift. The developer's responsibility is to fight for the structure that keeps the system soft (soft-ware: easy to change).
The problem
Hardcoding behavior in a function leaves no room for change. When the pricing strategy must differ per region, per season, or per customer type, every change requires touching — and testing — the same function.
Bad
class OrderProcessor:
def calculate_total(self, items: list[dict]) -> float:
total = sum(i["price"] * i["qty"] for i in items)
discount = total * 0.10 # hardcoded — impossible to change
return total - discount
class OrderProcessor {
calculateTotal(items: { price: number; qty: number }[]): number {
const total = items.reduce((s, i) => s + i.price * i.qty, 0);
return total * 0.90; // hardcoded — rigid, not soft
}
}
The solution
Injecting the strategy keeps behavior correct today and structure flexible for tomorrow. New discount rules are new classes, not edits to existing ones.
Good
class PercentDiscount:
def __init__(self, rate: float): self.rate = rate
def apply(self, total: float) -> float:
return total * (1 - self.rate)
class OrderProcessor:
def __init__(self, discount):
self.discount = discount
def calculate_total(self, items: list[dict]) -> float:
total = sum(i["price"] * i["qty"] for i in items)
return self.discount.apply(total)
proc = OrderProcessor(PercentDiscount(0.10))
print(proc.calculate_total([{"price": 100, "qty": 2}]))
interface DiscountStrategy {
apply(total: number): number;
}
class PercentDiscount implements DiscountStrategy {
constructor(private rate: number) {}
apply(total: number) { return total * (1 - this.rate); }
}
class OrderProcessor {
constructor(private discount: DiscountStrategy) {}
calculateTotal(items: { price: number; qty: number }[]): number {
const total = items.reduce((s, i) => s + i.price * i.qty, 0);
return this.discount.apply(total);
}
}
Key takeaway
Behavior satisfies today's requirements. Structure is what allows you to satisfy tomorrow's — and it is the harder, more valuable thing to protect.