2026-04-28
The Open/Closed Principle (the "O" in SOLID) states: software entities should be open for extension but closed for modification. In practice, this means you should be able to add new behavior to a system without changing existing, tested code.
Why does this matter? Every time you modify existing code to add a feature, you risk breaking something that already works. The more a module is edited, the more regression tests you need, and the more fragile it becomes. The Open/Closed Principle pushes you toward designs where new requirements are met by writing new code, not editing old code.
A concrete example. Say you have a reporting system that calculates shipping costs:
if (method == "ground") { cost = weight * 1.50; }
else if (method == "air") { cost = weight * 4.00; }
else if (method == "freight") { cost = weight * 0.80; }
Every time the business adds a shipping method, a developer opens this function, adds another branch, and hopes they don't break the existing ones. This is closed for extension and open for modification — the exact opposite of what you want.
The fix is to define a ShippingCalculator interface with a calculate(weight) method, then implement GroundShipping, AirShipping, and FreightShipping as separate classes. The core function accepts any ShippingCalculator and calls calculate(). Adding drone delivery? Write a new DroneShipping class. The existing code never changes.
A rule of thumb for when to apply this: if a function or class has been modified to add a new "type" or "case" more than twice, it's time to refactor toward Open/Closed. Two branches are fine. Five branches with different concerns mixed together is a maintenance liability.
Common techniques that enable the Open/Closed Principle:
Where people go wrong: applying this prematurely. Don't build an abstract plugin system for something with one implementation. The principle is about recognizing axes of change — the dimensions along which requirements actually evolve — and making those specific dimensions extensible. Everything else can stay simple and concrete. Abstracting in the wrong direction is worse than no abstraction at all.
A practical litmus test: look at your version control history. If the same file keeps getting modified every sprint to handle "one more case," that file is violating Open/Closed on a real axis of change, and it's worth refactoring.
