The Open/Closed Principle: Extend Without Modifying

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.

See it in action: Check out Write Extendable code with the Open-Closed Principle - SOLID Principals E2 by BitsOfQ to see this theory applied.
Key Takeaway: Design your modules so that adding new behavior means writing new code — not editing existing, working code — by identifying the real axes of change and making those dimensions pluggable.

All newsletters