Interface Segregation Principle: No Fat Interfaces
Clients shouldn't be forced to depend on methods they don't use. We explain the 'I' in SOLID with...
Abstract AlgorithmsTLDR: The Interface Segregation Principle (ISP) states that clients should not be forced to depend on methods they don't use. Split large "fat" interfaces into smaller, role-specific ones. A
RoboticDuckshould not be forced to implementfly()just because it's in aBirdinterface.
๐ The Fat Remote Control Problem
Imagine a TV remote with 50 buttons. You only ever use 5: power, volume, channel up/down, and input select. ISP says: don't give every device the full remote. Give each device the buttons it actually needs.
In software, a fat interface forces every implementing class to provide methods it doesn't need, creating:
- Stub implementations that throw
UnsupportedOperationException. - Tight coupling โ changes to the fat interface force all implementers to update.
- Fragile tests โ mocking 30 methods to test 2.
๐ The Classic Violation: The Printer Interface
public interface Machine {
void print(Document d);
void scan(Document d);
void fax(Document d);
void copy(Document d);
void staple(Document d);
}
public class SimplePrinter implements Machine {
public void print(Document d) { /* works */ }
public void scan(Document d) { throw new UnsupportedOperationException(); }
public void fax(Document d) { throw new UnsupportedOperationException(); }
public void copy(Document d) { throw new UnsupportedOperationException(); }
public void staple(Document d){ throw new UnsupportedOperationException(); }
}
SimplePrinter can only print โ but the Machine interface forces it to "implement" 4 other operations it can't do. Any code that calls simplePrinter.fax() fails at runtime rather than at compile time.
โ๏ธ Applying ISP: Split by Role
// Segregated interfaces โ each is a single capability
public interface Printable { void print(Document d); }
public interface Scannable { void scan(Document d); }
public interface Faxable { void fax(Document d); }
public interface Copyable { void copy(Document d); }
public interface Stapleable { void staple(Document d); }
// Simple printer: only what it can do
public class SimplePrinter implements Printable {
public void print(Document d) { /* full implementation */ }
}
// All-in-one office printer: combines all
public class OfficePrinter implements Printable, Scannable, Faxable, Copyable, Stapleable {
public void print(Document d) { /* ... */ }
public void scan(Document d) { /* ... */ }
public void fax(Document d) { /* ... */ }
public void copy(Document d) { /* ... */ }
public void staple(Document d) { /* ... */ }
}
classDiagram
class Printable { +print(d) }
class Scannable { +scan(d) }
class Faxable { +fax(d) }
SimplePrinter ..|> Printable
OfficePrinter ..|> Printable
OfficePrinter ..|> Scannable
OfficePrinter ..|> Faxable
Now:
SimplePrintercompiles and works with zero stubs.OfficePrinterimplements everything it genuinely supports.- Code that only needs
Printableaccepts both โ no forced coupling.
๐ง Python Version: Protocol-Based ISP
Python uses structural subtyping via Protocol (PEP 544) โ no explicit implements required:
from typing import Protocol
class Printable(Protocol):
def print(self, doc: str) -> None: ...
class Scannable(Protocol):
def scan(self) -> str: ...
class SimplePrinter:
def print(self, doc: str) -> None:
print(f"Printing: {doc}")
def send_to_printer(device: Printable, doc: str) -> None:
device.print(doc)
send_to_printer(SimplePrinter(), "Invoice.pdf") # OK โ duck typing via Protocol
SimplePrinter never declared it implements Printable. The type checker confirms structural compatibility at analysis time without runtime overhead.
โ๏ธ ISP vs Other SOLID Principles
ISP is closely related to:
| Principle | Focus | Relationship to ISP |
| SRP (Single Responsibility) | Classes have one reason to change | ISP = SRP applied to interfaces |
| DIP (Dependency Inversion) | Depend on abstractions, not concretions | ISP keeps those abstractions narrow |
| OCP (Open/Closed) | Extend without modifying | Narrow interfaces are easier to extend without breaking others |
Rule of thumb: If you ask "when would a class mock or stub this method just to satisfy the interface?", that method doesn't belong in that interface.
When Fat Interfaces Are Acceptable
| Situation | Verdict |
| All implementations genuinely use all methods | Fat interface is fine โ it's cohesive |
| Interface will never be implemented outside your team | Acceptable technical debt |
| Splitting creates so many tiny interfaces it hurts readability | Consolidate to 2โ3 cohesive groups |
| Library API that external code depends on | Apply ISP strictly โ breaking changes are costly |
๐ Summary
- Fat interfaces force stub implementations and tight coupling โ avoid
UnsupportedOperationExceptionas a design smell. - Split by role: Each interface represents one capability. Classes implement only what they support.
- Java uses explicit interface implementation; Python achieves the same with
Protocoland duck typing. - ISP = SRP for interfaces: One reason to change, one capability per interface.
- Apply strictly when the interface is part of a public API or library boundary.
๐ Practice Quiz
A
RemoteControlinterface has methodsturnOn(),changeChannel(),setTemperature(). ATVRemoteclass implements it but throwsUnsupportedOperationExceptiononsetTemperature(). Which SOLID violation is this?- A) SRP โ the remote has too many responsibilities.
- B) ISP โ
TVRemoteis forced to implement a method it doesn't support because the interface is too fat. - C) OCP โ the remote can't be extended.
Answer: B
After splitting
MachineintoPrintable,Scannable, andFaxable, what does aSimplePrinterclass implement?- A) All three interfaces with stubs for the others.
- B) Only
Printableโ the interfaces it genuinely supports. - C) None โ it uses reflection.
Answer: B
In Python, which feature enables ISP-style narrow interface enforcement without explicit
implementsdeclarations?- A) Abstract Base Classes (ABC) with
@abstractmethod. - B)
Protocolfrom thetypingmodule โ structural subtyping checked by the type checker. - C)
dataclassdecorator.
Answer: B
- A) Abstract Base Classes (ABC) with

Written by
Abstract Algorithms
@abstractalgorithms
More Posts
SFT for LLMs: A Practical Guide to Supervised Fine-Tuning
TLDR: Supervised fine-tuning (SFT) is the stage where a pretrained model learns task-specific response behavior from curated input-output examples. It is usually the first alignment step after pretraining and often the foundation for later RLHF. Good...
RLHF in Practice: From Human Preferences to Better LLM Policies
TLDR: Reinforcement Learning from Human Feedback (RLHF) helps align language models with human preferences after pretraining and SFT. The typical pipeline is: collect preference comparisons, train a reward model, then optimize a policy (often with KL...
PEFT, LoRA, and QLoRA: A Practical Guide to Efficient LLM Fine-Tuning
TLDR: Full fine-tuning updates every model weight, which is expensive in memory, compute, and storage. PEFT methods update only a small trainable slice. LoRA learns low-rank adapters on top of frozen base weights. QLoRA pushes efficiency further by q...
LLM Model Naming Conventions: How to Read Names and Why They Matter
TLDR: LLM names encode practical decisions: model family, size, training stage, context window, format, and quantization level. If you can decode naming conventions, you can avoid costly deployment mistakes and choose the right checkpoint faster. ๏ฟฝ...
