When building scalable applications in Salesforce Apex, we often use inheritance, abstract classes, and interfaces to create configurable, maintainable, and reusable code. These features help us design systems that are easy to maintain and extend. However, if they are used incorrectly, they can lead to bloated classes, unnecessary dependencies, and fragile architectures that are difficult to modify. The Interface Segregation Principle (ISP) is a vital object-oriented design principle that helps prevent these specific issues.
In this guide, we’ll explain ISP in simple, practical terms so that it is easy to understand and remember.
Refer post – Mastering Liskov Substitution Principle in Apex
What is the Interface Segregation Principle?
The Interface Segregation Principle states that a class should never be forced to implement an interface with methods it does not use. Instead of creating a single, large interface that covers every possible action, it is better to create multiple, smaller, and more specific interfaces.
In simple terms:
Clients should not be forced to depend upon interfaces that they do not use.
This means that our interface design should be lean and focused. When an Apex class implements an interface, it should actively use all of the methods defined by that contract, rather than writing empty, dummy implementations just to pass the Apex compiler.
Why ISP Matters in Apex
In Apex, developers frequently use patterns such as:
- Service layers and domain classes
- Enterprise Trigger frameworks
- E-commerce and checkout integrations
- External API connectors
- Custom notification Pattern
These patterns rely on clear contracts to decouple business logic. If an interface becomes a “catch-all” container for every method related to a feature, it becomes a “fat” or “polluted” interface.
When you force a small, specialized Apex class to implement a massive, generic interface, you introduce empty // Do nothing code blocks or artificial runtime exceptions. This breaks clean code practices, makes code reviews tedious, and introduces technical debt into your Salesforce org.
Let us take an example: we have an interface that handles Lead conversion communication and integration.
When this interface is implemented by any class, all methods should be overridden.
This code compiles and even passes a code review. This code works when the validateLead method is called, but it silently does nothing when other methods are called.
The downstream impact:
- A caller cannot trust which methods produce real results and which are empty stubs.
- A test must mock or stub methods that are irrelevant to the scenario being tested.
- A new developer doesn’t know whether those empty methods are intentional or forgotten.
- Changes to the interface (adding an 8th method) force every implementing class to add another empty method — even classes that will never use it.
Fix Issue with Interface Segregation Principle
To fix the above issue, we can decompose the fat interface into smaller interfaces that each represent exactly one responsibility.
Now each implementing class only takes on the contracts it can genuinely fulfill.
StandardLeadProcessor is required only validateLead and convertLead functionalities, so it implements ILeadValidator and ILeadConverter interfaces.
MarketingLeadProcessor only needs to validate the lead, convert the lead and send a welcome letter, so it will only implement ILeadValidator, ILeadConverter, and ILeadEmailNotifier
EnterpriseLeadProcessor needs to call the external API as well, so it implements ILeadValidator, ILeadConverter, ILeadEmailNotifier, ILeadCRMSync, and ILeadDataWarehouseSync
Every class now carries zero dead code. Every method it declares, it can genuinely and fully execute.
Benefits of the Interface Segregation Principle in Apex
1. No Dead Code
Classes implement only the interfaces they actually need. As a result, developers don’t write empty methods, dummy return values, or methods that throw exceptions just to satisfy an interface contract.
2. Clear and Honest APIs
A class’s implemented interfaces clearly describe what it can do. For example, when EnterpriseLeadProcessor implements ILeadValidator, ILeadConverter, and ILeadCRMSync, you can understand its responsibilities without digging into the code.
3. Changes Stay Localized
When developers add a new method to ILeadCRMSync, they only need to update classes that implement that interface. Classes such as StandardLeadProcessor remain untouched and don’t require testing or redeployment.
4. Easier Code Reviews
Reviewers can quickly spot new capabilities when a pull request adds an interface such as ILeadDataWarehouseSync to a class. In contrast, adding a method to a large interface forces every implementing class to change, creating noisy pull requests filled with boilerplate code that adds little value.
Drawbacks of the Interface Segregation Principle
1. Interface Proliferation
When applied too aggressively, the Interface Segregation Principle can lead to a large number of highly specialized interfaces. In a complex Salesforce org, developers may find themselves navigating interfaces such as ILeadValidator, ILeadConverter, ILeadEmailNotifier, ILeadSMSNotifier, ILeadCRMSync, ILeadDataWarehouseSync, and ILeadTicketCreator. While each interface has a clear responsibility, understanding the overall architecture can become more difficult as functionality becomes scattered across many small contracts.
2. Increased Composition Complexity
Classes that perform multiple responsibilities often need to implement several interfaces. A class like EnterpriseLeadProcessor may end up with a lengthy implements declaration containing five or more interfaces. Although this accurately reflects the capabilities of the class, it can make the code appear more complex and intimidating, especially for developers who are new to the codebase.
3. The Danger of Over-Segregation
Not every variation in behavior justifies creating a new interface. If two methods are consistently used together and every implementation requires both, separating them into different interfaces can introduce unnecessary abstraction. In such cases, the additional interfaces increase maintenance and navigation overhead without providing meaningful flexibility or design benefits.
The goal of ISP is not to create the maximum number of interfaces possible, but to create interfaces that represent cohesive, meaningful capabilities. Effective interface segregation improves flexibility and maintainability; excessive segregation can have the opposite effect.
When Should You Apply the Interface Segregation Principle?
Apply ISP when:
- An interface has more than 3–4 methods and some implementing classes regularly leave methods empty or stubbed.
- Different classes implement different subsets of the same interface — a clear sign the interface bundles unrelated capabilities.
- A change to one interface method forces many unrelated classes to be updated and redeployed.
- You are writing mocks for unit tests and the mock has to stub 6 methods just to satisfy an interface for a test that only exercises 1.
- The interface serves different types of clients — some need integration capabilities, some need communication capabilities, some need both.
When Should You NOT Apply ISP?
Avoid over-applying ISP when:
- The interface has 2–3 cohesive methods that are always implemented and used together. These belong together — don’t split them.
- The interface represents a well-defined, stable contract (like Salesforce’s own
Database.Batchable<SObject>) — it hasstart,execute, andfinishand every batch genuinely needs all three. - The team is small and the org is early-stage — architecture overhead should be proportional to the scale and lifespan of the codebase.
- Splitting the interface would produce single-method interfaces across the board — at that point, reconsider whether you need interfaces at all vs. simple dependency injection.
Summary
The Interface Segregation Principle helps you keep Apex interfaces clear and practical. When an interface contains only the methods a class actually needs, every implementing class can fully support every method. This approach removes unnecessary code, avoids misleading contracts, and prevents developers from creating placeholder methods that do nothing.
In Salesforce development, applications often grow over many years as teams add new integrations, channels, and features. ISP prevents interfaces from becoming large collections of unrelated methods that classes must implement even when they don’t need them. By creating small, focused interfaces, you make your code easier to understand, simplify deployments, and write cleaner unit tests that mock only the functionality they use.
Need SOLID implementation: Contact Us with your requirements
Other SOLID Principle
References
- The Art of Naming (Clean Code for Salesforce Developers)
- Top Mistakes Developers Make in Salesforce Apex Triggers
- How to Handle Bulkification in Apex with Real-World Use Cases
- How to Confidently Manage Transactions in Salesforce Apex
Other Important Posts
- The Ultimate Guide to Apex Order of Execution for Developers
- How to Manage Technical Debt in Salesforce
- The Ultimate Checklist for Efficiently Querying Large Data Sets
- Optimizing Salesforce Apex Code
- Efficient Ways to Debug Salesforce Platform Events
- Handle Heap Size for Apex Code Optimization
- Build Scalable Solutions with Salesforce
- How to Correctly Publish Platform Event Using Salesforce Apex
