Open-Closed Principle
Software entities should be open for extension but closed for modification: you add new behavior by adding new code, instead of changing code that already works.
Also known as: Open/Closed Principle, OCP, Open Closed Principle
Category: Software Development
Tags: software-development, software-design, object-oriented, design-patterns, architecture, maintainability, principles
Explanation
Every time you modify working code, you risk breaking it. And everything that depends on it. The Open-Closed Principle (OCP) is about avoiding that risk: design modules so that new behavior can be added without touching what already works.
The principle states that "software entities should be open for extension, but closed for modification". Bertrand Meyer introduced the term in 1988, in Object-Oriented Software Construction. It's the O in SOLID.
**Two versions of the same idea**:
- **Meyer's version (1988)**: Once a class is finished and published, you stop changing it, except to fix bugs. New features go into new subclasses that inherit from it (implementation inheritance)
- **The polymorphic version (1990s)**: Robert C. Martin's 1996 article "The Open-Closed Principle" moved the focus to abstract interfaces. The interface stays closed to modification, and you extend the system by writing new implementations of it. This is the version most people mean today
Martin later summarized it in one line: "A Module should be open for extension but closed for modification."
**An example**:
Consider a function that calculates shipping costs with a `switch` on the carrier: `case "DHL"`, `case "UPS"`, and so on. Every new carrier means opening that function and editing it, along with every other `switch` on carriers scattered through the codebase. With OCP, you define a `ShippingCarrier` interface with a `cost(parcel)` method, and each carrier becomes its own implementation. Adding a carrier now means adding a class. The existing, tested code stays untouched.
**Common ways to apply it**:
- **Interfaces and polymorphism** instead of `switch` or `if/else` chains on types
- **Strategy and plugin patterns**, where new behavior plugs in from the outside
- **Configuration and data** instead of hardcoded rules
- **Hooks, events and extension points** in frameworks and tools (e.g., Obsidian plugins add features to the app without modifying it)
**Keep in mind**:
You can't make code closed against every possible change, and trying to creates layers of abstraction nobody needs (see YAGNI). Every abstraction is a bet on which changes are likely. A pragmatic approach: write the simple version first, then introduce the extension point when the second or third variation actually shows up.
**In AI skills**:
The same principle applies to AI skills: extend via references, not modification. Instead of growing a skill's main file every time it needs to handle a new case, keep the core stable and load additional material by reference, only when it's needed (see Prompt Lazy Loading and progressive disclosure, with its three levels).
Related Concepts
← Back to all concepts