Skip to content
Gustavo's Blog
Go back

SOLID — The Interface Segregation Principle

When abstracting a class, we often start with a simple base concept that includes two or three methods. This base class serves as an interface for derived classes. As our model grows, these derived classes may develop specific requirements — such as needing to implement an additional base class.

The Pollution Problem

Back to the credit card example. Some types of credit card need to be processed by an external API. To handle that, they need to inherit a base class called BaseProcessingCard to call a specific method:

public class ExpressCard : BaseCard { ... }
public class TowerCard : BaseCard { ... }
public abstract BaseCard extends BaseProcessingCard { ... }

What we’re doing here is polluting the BaseCard interface by including methods that serve purposes beyond its intended scope. Our interfaces should only contain the methods they require. Consequently, classes that have nothing to do with the external API end up having to incorporate these methods just to satisfy one of their derived subclasses.

A common workaround is to provide degenerate implementations of these methods in the base class, so that derived classes aren’t forced to implement them. This is dangerous — it can violate LSP, leading to unexpected behavior from clients.

The key principle here: “Clients should not be forced to depend on methods they do not use.”

The Fix

For cards designed to interact with an external API, extend BaseProcessingCard directly — not through BaseCard.

public class CardUsedByExternalApi : BaseCard, BaseProcessingCard { ... }
  CardService         BaseCard            CardUsedByExternalApi
  ┌─────────┐        ┌──────────┐         ┌──────────────────┐
  │         │─uses──▶│          │◀─────────│                  │
  └─────────┘        └──────────┘         └────────┬─────────┘

                     ExternalAPI                    ▼
                     ┌─────────┐         ┌──────────────────┐
                     │         │─uses───▶│ BaseProcessingCard│
                     └─────────┘         └──────────────────┘

By doing this, clients of BaseProcessingCard can rely directly on cards that implement its interface rather than on the base class itself. This separation of concerns results in a cleaner and more cohesive design.

Whenever a base class or interface contains a group of methods that can be logically divided according to client usage, consider splitting it into two separate classes. Any component that requires a specific interface can use it independently. This not only makes the software more robust but also helps prevent violations of LSP.

Closing Thoughts on SOLID

The SOLID principles represent a timeless collection of heuristic insights from pioneering software engineers of the early ’90s — and even before. Despite the passage of time, these concepts remain steadfast as fundamental truths in software design. The rise of artificial intelligence has certainly transformed many aspects of our industry, yet the fear of being replaced by technology in the realm of domain modeling has largely subsided. After all, the art of representing complex domain logic in our systems is an inherently human endeavor. No machine can entirely capture the subtleties and context that we, as developers, bring to our work.

This series is not just an exploration of SOLID for its own sake; it’s a reminder that the principles are tools to help us translate our deep domain knowledge into elegant, resilient code. They remind us that, while technology evolves, the core insights that drive quality software design are anchored in human experience and understanding.


Florianópolis, Brasil — February 2025


Share this post on:

Previous Post
Hello World
Next Post
SOLID — The Dependency Inversion Principle