5. Inferface Segregation Principle (ISP) Flashcards
What does ISP state?
That clients should not be forced to depend on methods they do not use.
What kind of interfaces should we prefer according to ISP?
We should prefer small, cohesive interfaces to large, “fat” ones.
What is the interface of a type in the context of ISP?
Whatever can be accessed by client code with an instance of that type.
What is a client in the context of ISP?
The code that is interacting with an instance of an interface. It’s the calling code.
What does violating ISP results in?
It results in classes that depend on things they don’t need. This increases coupling and makes it harder to change or swap out individual implementations because the number of clients that might break is much larger.
What does having more dependencies than needed cause?
- More coupling
- More brittle code
- More difficult testing
- More difficult deployments
What are the three common indicators that ISP is being violated?
- Large interfaces
- NotImplementedException
- Code that uses only a subset of a larger interface
What can we do to implement ISP when dealing with a large legacy interface that violates it?
We can break it into smaller interfaces, and then at places where an error is occurring, we can implement the pieces of the now broken interface.
How does violating ISP negatively impact compliance with LSP?
Large interfaces are harder to fully implement, and thus, more likely to only be partially implemented, and therefore, to not be substitutable for their base type.
How does ISP relate to cohesion?
The Interface Segregation principle relies heavily on cohesion — small, cohesive interfaces are preferable to large interfaces whose methods are only loosely related to one another.
How does ISP relate to PDD?
You shouldn’t break up interfaces just to satisfy the principle but rather use the principle to help identify the source of some pain you’re experiencing with the codebase.
What is a potential drawback of not following PDD when implementing ISP?
If you try to preemptively follow ISP everywhere, you could end up with a bunch of single-method interfaces that are much more difficult to use, group together, and understand than a few cohesive interfaces.
Once identified, how should we fix ISP violations?
- For interfaces you control:
Break up the interfaces into smaller ones — if the original interface is still being used, you can compose it from smaller ones for backward compatibility. - For interfaces you don’t control:
Create small, cohesive interfaces that follow the adapter design pattern — your code should work with the adapter interface that you control and it, in turn, can work with the original large interface where only the adapter knows about the underlying large interface. - Generally:
It’s easy to follow ISP if you let client code define interfaces the code will work with. In fact, it’s impossible to violate ISP in this case.
How can we identify how exactly to implement ISP on a large interface?
By looking at a place where the interface is being used, identifying which parts of the interface it uses, and then, if a given part is another interface or method, diving in and seeing what individual parts of that are being used.
What are the key takeaways of this module?
- Prefer small, cohesive interfaces to large, expensive ones
- Following ISP helps with SRP and LSP
- Break up large interfaces by using
a. Interface inheritance
b. Adapter design pattern