Zemazon Inc has successfully launched a Home Automation Platform that exposes an API for the developers to build their home automation applications.
Ravi (sales executive at Zemazon): ‘As always, Our Devs worked day and night to build this platform from scratch, Now all we need to do is create some killer products for the customers, and we will be minting money in no time.’
Smart Home Module API
🚦 Can you see any problems in the above interface? Can you recall any principle that we studied earlier that is relevant here?
Mohan (lead dev at Zemazon): ‘Our Api ensures Consistency and Standardization. This platform will enable anyone in this world to create home automation applications. In fact, we already have a team working on a Remote Controller app, which can be used for operating everything in your home, with a touch of your finger! ’
Remote Module Design and Code
Ravi: ‘These are the upcoming products that we want to launch next quarter:’
List of Upcoming Home Automation Products at Zemazon
Vikas (SDE intern): ‘Since the API is already finalized, all we need to do is extend the interface and implement product-specific functionalities.’
SmartHome Module initial Design and Code
Notice how Vikas was forced to implement interfaces that are not required? Such types of ‘functionally overloaded’ interfaces are commonly known as fat interfaces.
What is Fat Interface?
~ an interface that incorporates operations that are logically incohesive.
We call an interface ‘fat’ if the interface can be broken down into groups of logically cohesive functions and each group serves a certain subset of clients. Fat interfaces lead to:
- Interface Pollution: Each client will have to implement methods that it does not use. Furthermore, any modification to the base interface will affect all the child classes even if there is no functional dependency between them.
- Dependency Hell: Let's assume that the smart door class requires a third-party Hardware module as a dependency. But this change will cause a recompilation of all the Remote classes, due to the introduction of a new compile-time dependency. This means that any failure in the hardware module can impact LEDRemote or AudioRemote classes, even if there is no run time dependency between them.
If a client depends on modules that it does not use, it can lead to complex dependencies in code.
To avoid such scenarios, Robert. C Martin coined Interface Segregation Principle (ISP) which states,
Clients Should Not be Forced to depend on Interfaces that they do not use.
Solution using Interface Segregation Principle
This unfortunate coupling can be avoided by depending on logically cohesive interfaces instead of fat interfaces.
Updated API and Code
AMA: Ask me Anything with The Wise Developer
Question: LSP vs ISP
Mohan: ‘We have already discussed Liskov Substitution Principle (LSP), how is it different from ISP ?’
The Wise Developer: ‘Good Catch Mohan! both LSP and ISP are complementary ideas. But there is one key difference, LSP focuses on honoring the promises of the base type so that abstract class users should never have to know about which subclass is being used to serve their requests.
ISP focuses on defining cohesive base types so that there is no such case where module A depends on module B at compile-time, but not at run time.
In other words, If your abstractions are like a pie, then ISP helps you in defining the correct slices, and LSP ensures that the promises made by those slices are honored by subtypes.
Question: Compile-time vs Runtime Dependency
Mohan: ‘Is there a difference between runtime and compile-time dependencies? I thought both are the same.’
The Wise Developer: ‘Compile time Dependencies are required by the compiler for producing byte code. On the other hand, those dependencies that are required for the execution of your code are known as Runtime dependencies. So technically (see lazy loading) all runtime dependencies are also compile-time dependencies, but not vice-versa, as shown in the previous section.
Question: When to apply ISP in your code?
The short answer is it depends on the code, and how it's going to change in the future. But two key points could be,
- When you see Fat Interfaces in your code, you know that some expected functional requirement is going to impact them in the future.
- When your compile-time dependencies are growing but your run-time dependencies stay relatively stagnant. This would be a clear indicator that ISP is getting violated in your codebase.
Enjoy learning, Enjoy oops!