Facebook Pixel

Open/Closed Principle

Adding without breaking

The Open/Closed Principle states that a module should be open for extension and closed for modification. In practice this means: when a new requirement arrives, new code is added rather than editing existing, tested code. Editing working code is a common source of regressions — a change to one branch of a switch can break another. The goal is a structure where adding behavior does not require modifying code that already works.

The principle is most visible in classes that branch on a category. A discount calculator, a shipping-cost estimator, a tax engine — any system where the list of categories grows over time — will show whether the design is open/closed or not.

The branching smell

A shipping-cost calculator starts with two carrier options and a simple if/elif. Six months later it handles four carriers. A year later it handles eight, each with its own pricing rules. At that point every new carrier requires opening the calculator, navigating the existing branches, and verifying that no existing rule is accidentally affected. The class was intended to be stable, but it requires modification each time the list of carriers grows.

1# Bad: adding a new carrier means editing this function and risking existing branches.
2def calculate_shipping(carrier: str, weight_kg: float) -> float:
3    if carrier == "standard":
4        return 2.50 + weight_kg * 0.30
5    elif carrier == "express":
6        return 8.00 + weight_kg * 0.75
7    elif carrier == "overnight":
8        return 20.00 + weight_kg * 1.50
9    elif carrier == "freight":
10        # Freight has a minimum charge and a per-100kg rate
11        base = max(50.0, weight_kg / 100 * 12.0)
12        return base
13    else:
14        raise ValueError(f"Unknown carrier: {carrier}")

The fix: a strategy you extend, not a branch you edit

The open design extracts the pricing rule into an abstraction — a ShippingCarrier interface — and gives each carrier its own class that implements it. Adding a new carrier means writing a new class. The calculator itself does not change; it only calls cost() on whatever carrier it receives. Existing carrier classes are unaffected by a new addition because there is no shared branching code to modify.

Invest in Yourself
Your new job is waiting. 83% of people that complete the program get a job offer. Unlock unlimited access to all content and features.
Go Pro