I am under the impression that every time I come across a SOLID post, LSP and ISP are not given the same amount of attention as the other three. I guess its because they are the easiest to grasp but make no mistake, they are also the easiest to violate!
Liskov Substitution Principle (LSP)
In essence, LSP proposes that we create sub-classes that can be used wherever their parents are being used without breaking or changing the client’s behavior.
This means that in the code snippet below:
we should be able to pass instances from all sub-classes of
SoftwareEngineer without worrying that
calculateSeniority will break or change the behavior of
Ways that we tend to violate LSP
- By throwing an exception
This is the obvious one. If, for example, the subclass adds a check that will eventually throw an exception then the client will break.
- By returning undocumented results
In other words, the subclass returns something that the its parent never will.
This forces the client to know about the subclass which makes the code less scalable.
- By having side effects
This is the subtle one since it does not change the client’s code but it does change the expected behavior.
printSeniority is expected to make a calculation and then print the result but know it also makes a network call!
Interface Segregation Principle (ISP)
In essence, ISP proposes that interfaces should not play the role of “methods bucket” because eventually there will be a client that will not need to implement all of them.
This means that interfaces like this:
should break in more meaningful parts and allow every client to implement only the part that it needs:
Its worth mentioning that this way, in addition from avoiding ISP violation we also:
- Keep our code from violating the SRP.
In the first implementation, our cache depends in two things so it has more that one reasons to change (ex: a new parameter in the post method would force us to change our cache too)
- Keep our code from violating the LSP. By having one interface, the first implementation of our cache couldn’t be used in code that expects repositories since its API methods would break the client.
- Keep our code clean and scalable (the cache does not have to know about talking to the API)
Ways that we tend to violate ISP
Although there is not much to say here, since the only way to do it is by creating those buckets we mentioned above, beware of the creation since it comes in two flavors.
The first is by having all methods in one file. Easy to catch it in a PR review. The second though is by having an hierarchy in our interfaces.
By the time there is an implementation that does not need all methods, it might too late!