Skip to main content

Sign in to CleanKata

Track your progress, earn XP, and unlock every lesson.

By signing in you agree to our Terms of Use and Privacy Policy.

Clean Architecture60 XP6 min

The Two Values of Software: Behavior vs Structure

Software derives value from behavior and structure. A perfectly working but rigid system will fail when requirements change.

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.

🔧 Some exercises may still have errors. If something seems wrong, use the Feedback button (bottom-right of the page) to report it — it helps us fix it fast.

Hint: Behavior satisfies today's requirements. Structure allows you to satisfy tomorrow's.

✗ Your version