System DesignMedium
Give a real example of an Interface Segregation Principle violation
ISP: clients should not be forced to depend on methods they don't use.
Violation: a fat repository interface.
public interface IOrderRepository {
Task<Order?> GetAsync(Guid id);
Task<List<Order>> ListAsync();
Task AddAsync(Order o);
Task UpdateAsync(Order o);
Task DeleteAsync(Guid id);
Task<List<Order>> ExportToCsvAsync();
Task<int> CountByStatusAsync(string status);
}
A read-only dashboard service receives this interface — and can technically call DeleteAsync. Code reviews catch it, but the type system doesn't.
Segregated:
public interface IOrderReader {
Task<Order?> GetAsync(Guid id);
Task<List<Order>> ListAsync();
Task<int> CountByStatusAsync(string status);
}
public interface IOrderWriter {
Task AddAsync(Order o);
Task UpdateAsync(Order o);
Task DeleteAsync(Guid id);
}
public interface IOrderExporter {
Task<List<Order>> ExportToCsvAsync();
}
The dashboard takes IOrderReader — Delete is now a compile-time impossibility.
Benefits compound:
- Mocking is easier (each interface has 1-3 methods)
- Decorators are easier (wrap only the methods you care about)
- The CQRS split between read and write models follows naturally
Caveat: don't over-segregate. If you find yourself injecting 8 single-method interfaces into one constructor, you've passed the useful point. Aim for cohesive sets — methods that change together belong together.