In our world of Salesforce development, requirements change as quickly as business strategies. Whether it’s a new notification service logic for an account, discount logic for travel customers, or a specialized integration for different lead sources, our code must be resilient. This is where the Open/Closed Principle (OCP)—the “O” in the SOLID design principles—becomes a game-changer.
Check out also the Single Responsibility Principle (SRP) in Salesforce Apex — A Complete Guide
What is the Open/Closed Principle (OCP)?
The Open/Closed Principle, coined by Bertrand Meyer and popularized by Robert C. Martin, states:
Software entities (classes, modules, functions) should be open for extension, but closed for modification.
Open for extension means we can add new behavior. Closed for modification means adding new behavior does not require changing existing, tested code.
Every time we modify a working class to add a new feature, we risk introducing a regression. OCP pushes us to design code where new requirements are satisfied by adding new code, not editing old code.
Let us take an example of a notification service in a system that violates OCP.
When we need to add a new notification channel, it forces us to:
- Modify this class that is already in production and tested.
- Re-test ALL existing notification channels to ensure they still work.
- Risk of introducing a bug in a branch we didn’t intend to touch.
OCP Way: Strategy Pattern with Interfaces
We can solve the above problem most cleanly by implementing OCP in Apex. We can add OCP using the strategy pattern that defines a common interface (the contract) and implements each variation as a separate class like EmailChannel, ChatterChannel, SlackChannel etc,.
Benefits of OCP in Apex
1. Zero Regression Risk When Adding Features
When a new notification type is added, the existing notification classes are never opened. Their code doesn’t change — and neither do their test results. Using OCP will dramatically reduce deployment risk.
2. Parallel Development
Two developers can simultaneously build EmailChannel and SlackChannel in separate branches. There is no shared file to create a Git merge conflict on.
3. Clean Audit Trail
Each new business rule lives in its own class. When a business auditor asks, “When did we add the Slack channel and what is the logic?” we can simply point them to SlackChannel.cls’s Git history. No history through a 500-line if-else chain.
4. Testability Without Mocking
Because each strategy is a small, self-contained class, unit tests are pure and fast. No mocks, no stubs, no test setup overhead for things we don’t care about in this test.
Drawbacks of OCP
1. More Classes, More Navigation
A project with 10 notification types will have 10 notification strategy classes, plus the interface, plus the registry. For a developer new to the codebase, understanding the full picture requires navigating more files.
2. Registry Maintenance
The strategy map NotificationRouter must be updated when new strategies are added. This is a single-line change, but it is still a change to a shared file — it must be coordinated in team environments.
3. Abstraction Overhead for Simple Cases
If we have only ever had two notification channels and they will never change, the strategy pattern is overkill. A simple if-else in a private method is perfectly acceptable for genuinely stable, small logic.
When Should We Apply OCP?
OCP should be implemented when
- We have logic that branches on a type, category, or classification (
DiscountType__c,Channel__c,IntegrationPartner__c). - The branching logic is expected to grow — the business has asked for “these two types now, but more are coming.”
- Each branch has distinct, non-trivial logic that deserves its own test class.
- Multiple teams or stakeholders own different branches (Sales owns VIP logic, and IT owns Partner logic).
- The class is called from multiple entry points (triggers, batch, and flow-invocable), and changes carry high deployment risk.
When Should You NOT Apply OCP?
Avoid OCP when:
- The branching logic is truly static — it has not changed in years and has no roadmap for change. Two lines of
if-elsedon’t need a Strategy Pattern. - The “different types” are so similar that a strategy class would be just one line of arithmetic—parameterize it instead.
- You are writing anonymous Apex or Data Loader scripts — architecture principles are for production code with a lifecycle.
- The team is junior or unfamiliar with interfaces—a pattern no one understands is worse than a readable if-else chain. Introduce it gradually.
Summary
The Open/Closed Principle is our shield against regression. In Salesforce Apex, where orgs evolve over the years and business rules expand constantly, OCP means that each new requirement is a new class—not a modification to one growing, fragile class.
The Strategy Pattern is the primary tool for OCP in Apex. For purely data-driven variation, custom metadata types offer a zero-code-deployment alternative that is even more “closed” to modification.
Apply OCP wherever you have type-based branching logic that is likely to grow. The upfront investment of creating an interface and a registry pays back tenfold in reduced deployment risk, isolated tests, and parallel development over the lifetime of the org.
