SOLID Principles in Depth: The Interface Segregation Principle (ISP)
As we reach the fourth letter of the SOLID acronym, we land on a principle that’s especially important in microservices, SDK design, and modular backend architecture: the Interface Segregation Principle.
This principle helps us build interfaces that are focused, clear, and adaptable—and avoid the all-too-common trap of creating "God interfaces" that force clients to depend on methods they don’t need.
What is the Interface Segregation Principle?
Definition (Robert C. Martin):
“Clients should not be forced to depend on methods they do not use.”
In simpler terms:
Split big, bloated interfaces into smaller, more specific ones so that implementing classes and their consumers only interact with what they actually need.
It promotes low coupling and high cohesion, which leads to more maintainable and flexible code.
Real-World Analogy: Universal Remote Control
Imagine buying a universal remote control with 50 buttons:
- You only want to change the TV volume and switch inputs.
- But the remote also includes: AC control, fan speed, light dimmer, garage opener, coffee maker…
Every time you use it, you have to ignore 90% of the buttons.
Now imagine a minimal remote with just the 3 functions you actually use—that's the ISP in action. Clients (users) are not forced to interact with functions irrelevant to their context.
Common Violation in Real Projects
Let’s move to a real backend software example from a typical SaaS system: a UserService interface in a shared monolith or service contract.
class UserService: def register_user(self, data): ... def authenticate_user(self, credentials): ... def reset_password(self, email): ... def delete_account(self, user_id): ... def get_audit_logs(self, user_id): ... def update_subscription_plan(self, user_id, plan_id): ... def notify_user_of_billing_change(self, user_id): ...
Now you have:
- The Auth team only needs authenticate_user()andreset_password()
- The Billing team only needs update_subscription_plan()andnotify_user_of_billing_change()
- The Audit team only uses get_audit_logs()
But each team’s service must implement or mock all methods, and any change to
This violates the Interface Segregation Principle.
ISP-Compliant Refactoring
Instead, we segregate the interface:
class AuthService: def register_user(self, data): ... def authenticate_user(self, credentials): ... def reset_password(self, email): ... class BillingService: def update_subscription_plan(self, user_id, plan_id): ... def notify_user_of_billing_change(self, user_id): ... class AuditService: def get_audit_logs(self, user_id): ...
Each service now depends only on the contract it actually needs. This makes the codebase:
- Easier to test
- Safer to refactor
- More understandable for new developers
- More robust to changes in unrelated domains
Real-World Example: AWS SDKs
Amazon Web Services (AWS) SDKs follow ISP at scale. Let’s say you’re using AWS SDK for Python (
You import and instantiate only:
s3 = boto3.client('s3')
AWS separates each service into its own logical and programmatic interface—so you're never forced to depend on what you don’t use. Imagine if they gave you a single
Common Signs You're Violating ISP
- Interfaces with dozens of unrelated methods
- Mocking unnecessary methods in unit tests
- Service classes filled with NotImplementedError
- Downstream teams avoiding shared interfaces due to “noise”
Pro Tips for Applying ISP
- Ask: “Does this class use everything from this interface?”
- Favor smaller, focused interfaces—especially across team/service boundaries
- Use composition over inheritance when sharing capabilities
- Consider segregating APIs and SDKs for different client personas (e.g., admin, end-user, third-party developer)
Useful Design Patterns That Support ISP
- Interface Segregation goes hand-in-hand with:
- Adapter Pattern – for translating smaller interfaces to legacy ones
- Facade Pattern – for providing tailored views over complex subsystems
- Role-based Interfaces – especially in systems where users have specific capabilities
Conclusion
The Interface Segregation Principle teaches us to be kind to our collaborators—whether human developers or dependent services. By keeping interfaces lean and purpose-driven, we avoid bloat, confusion, and tight coupling.
In modern software architecture—especially in microservices, API gateways, and shared SDKs—ISP is essential to building scalable, maintainable, and team-friendly systems.
Up Next: The Dependency Inversion Principle—build systems that depend on abstractions, not concretions.