75

How does the SOLID "Interface Segregation Principle" differ from "Single Responsibility Principle"?

The Wikipedia entry for SOLID says that

ISP splits interfaces which are very large into smaller and more specific ones so that clients will only have to know about the methods that are of interest to them

However, to me that sounds like just applying the SRP to interfaces as well as classes. After all, if an interface is only responsible for just one conceptual thing, than you wouldn't be able to break it down further.

Am I missing something, or is ISP sort of redundant with SRP? If not, then what does ISP imply that SRP does not?

Dave Schweisguth
  • 36,475
  • 10
  • 98
  • 121
Sled
  • 18,541
  • 27
  • 119
  • 168
  • 1
    Possible duplicate for http://stackoverflow.com/questions/8099010/is-interface-segregation-principle-only-a-substitue-for-single-responsibility-pr – Michael Freidgeim Apr 13 '13 at 18:31
  • I suppose technically, but this question is IMHO better written and the answers more fleshed out. – Sled Apr 14 '13 at 16:20
  • 1
    They are the same thing, but it's not the same saying "SOLID principles" than "SOLD principles". We needed another char to create a bombastic word. – Cequiel Apr 07 '20 at 19:50
  • @Cequiel, the acronym was created years after the five principles were published, and the acronym was created by a different person (Michael Feathers) than the principles (Bob Martin). – jaco0646 Jun 17 '20 at 03:01

5 Answers5

50

SRP tells us that you should only have a single responsibility in a module.

ISP tells us that you should not be forced to be confronted with more than you actually need. If you want to use a print() method from interface I, you shouldn't have to instantiate a SwimmingPool or a DriveThru class for that.

More concretely, and going straight to the point, they are different views on the same idea -- SRP is more focused on the designer-side point-of-view, while ISP is more focused on the client-side point-of-view. So you're basically right.

It all came from

The ISP was first used and formulated by Robert C. Martin when doing some consulting for Xerox. Xerox had created a new printer system that could perform a variety of tasks like stapling a set of printed papers and faxing. The software for this system was created from the ground up and performed its tasks successfully. As the software grew, making modification became more and more difficult so that even the smallest change would take a redeployment cycle to an hour. This was making it near impossible to continue development. The design problem was that one main Job class was used by almost all of the tasks. Anytime a print job or a stapling job had to be done, a call was made to some method in the Job class. This resulted in a huge or 'fat' class with multitudes of methods specific to a variety of different clients. Because of this design, a staple job would know about all the methods of the print job, even though there was no use for them.

so

The solution suggested by Martin is what is called the Interface Segregation Principle today. Applied to the Xerox software, a layer of interfaces between the Job class and all of its clients was added using the Dependency Inversion Principle. Instead of having one large Job class, a Staple Job interface or a Print Job interface was created that would be used by the Staple or Print classes, respectively, calling methods of the Job class. Therefore, one interface was created for each job, which were all implemented by the Job class.

@ http://en.wikipedia.org/wiki/Interface_segregation_principle#Origin

Leaky
  • 3,088
  • 2
  • 26
  • 35
devoured elysium
  • 101,373
  • 131
  • 340
  • 557
  • 4
    Hmm, the only distinction I see from your post is `"If you want to use a print() method from interface I, you shouldn't have to instantiate a SwimmingPool or a DriveThru class for that."` which frankly sounds a lot like "[You wanted a banana but what you got was a gorilla holding the banana and the entire jungle.](http://www.johndcook.com/blog/2011/07/19/you-wanted-banana/)". Are you saying that the banana comment is a paraphrase of ISP? – Sled Jan 17 '13 at 21:31
  • 1
    You often see badly designed code in which for making use of some feature, you have to first turn on the logging, then turn on A, B and C services, while all you wanted to do was to calculate the area of an ellipsis which is something you'd expect to not require all that ado. – devoured elysium Jan 17 '13 at 21:33
  • Can you give me source to this article? – Daniel Kaplan Jan 17 '13 at 21:59
  • Rightly or wrongly, I downvoted as I think SWeko's answer is a lot more powerful and easier to understand. – AJP Sep 27 '18 at 15:05
23

SRP is concerned with what a module does, and how it is done, disallowing any mix of abstraction levels. Basically, as long as a component can be extensively defined with a single sentence, it will not break SRP.

On the other hand ISP is concerned with how a module should be consumed, whether it makes sense to consume just part of the module, while ignoring some aspect.

As an example of a code that keeps the spirit or SRP, but can break ISP is the Facade pattern. It has a single responsibility, "providing simplified access to a larger subsystem", but if the underlying subsystem needs to expose wildly different thinks, it does break ISP.

That said, usually when a piece of code breaks a SOLID principle, it often breaks the whole lot. Concrete examples that break a specific principle, while preserving the rest are rare in the wild.

SWeko
  • 30,434
  • 10
  • 71
  • 106
17

Robert Martin tweeted the following on May 16, 2018.

ISP can be seen as similar to SRP for interfaces; but it is more than that. ISP generalizes into: “Don’t depend on more than you need.” SRP generalizes to “Gather together things that change for the same reasons and at the same times.”

Imagine a stack class with both push and pop. Imagine a client that only pushes. If that client depends upon the stack interface, it depends upon pop, which it does not need. SRP would not separate push from pop; ISP would.

jaco0646
  • 15,303
  • 7
  • 59
  • 83
  • 6
    On the other hand, [Mark Seemann](https://blog.ploeh.dk/2009/09/29/SOLIDorCOLDS/) thinks the SRP and ISP are close enough to be redundant. – jaco0646 Mar 09 '19 at 01:52
5

SRP and ISP ultimately boils down to the same things. Implementing, either of them, needs a split of classes or interfaces.

However there are differences on other fronts.

  1. Violation of SRP can have a far reaching effects on the entire design structure, giving rise to poor maintainability, reuse and of course low cohesion and coupling.
  2. SRP has an impact on both the behavioral and structural components of an object structure.
  3. Re designing on SRP violation needs a much deeper analysis, require looking at the different components of design in a holistic way.

Violation of ISP is mostly about poor readability ( and to some degree, low cohesion ). But the impact on maintenance and code re-use is far less sinister than SRP.

Moreover, refactoring code to ISP conformation, seems to be just a structural change.

See also my blog for SRP and ISP

Sled
  • 18,541
  • 27
  • 119
  • 168
aknon
  • 1,408
  • 3
  • 18
  • 29
  • The point I've come to take is that SRP is one responsibility in the domain, whereas ISP is a single behaviour. So in a library having one class for `Book`s and one for `Movie`s is a SRP, but then the `getDueDate()` and `getMexRenewal()` being their own interface (eg `Rentable`) from `getId()` (eg `Identifiable`) is ISP, even if all `Rentable` classes will be `Identifiable` as well. It's almost as it if the definition of "atomic" or "separate" is different for interfaces than it is for classes. – Sled Dec 18 '13 at 18:02
  • There is no formal definition for 'atomic' or 'separate'. In that respect the design considerations for building a class are the same as that of interface. – aknon Dec 19 '13 at 04:29
  • Will it be wrong to say that methods of interface define a responsibility for the implementing class ? It must be, otherwise there are some overridden methods of interface having a 'NIL' implementation in the implemented class. To put in your words, Interface methods ( put together ) define an 'atomic' behaviour of a type. Classes 'atomic' behaviour, or the so called 'responsibility' is an aggregate of many such behaviours. ( And ofcourse, for a non final class, all the public methods must be substitutable with different implementations ) – aknon Dec 19 '13 at 04:42
  • `In that respect the design considerations for building a class are the same as that of interface.` I disagree, I find in clean code the scope of responsibilities of an interface much narrower than that of an entire class. You will find an interface that defines a single `getId()` method but you'll *never* find a class with *just* a `getId()` method. Interfaces usually have narrower scopes. – Sled Dec 19 '13 at 21:25
  • 2
    Yes, definitely. Interfaces just define a unit behaviour. Multiple unit behaviours may be one responsibility for a class. – aknon Dec 20 '13 at 04:28
  • That comment is probably the best answer for why and how SRP and ISP differ. – Sled Dec 20 '13 at 19:46
  • Yes, but well there is another important point of concerns. How to define a responsibility of a class ... Attempts to find a objective answer brings forth some subtle differences – aknon Dec 21 '13 at 07:22
  • Is there a blog post that defines "unit behaviour" and "responsibility" more precisely? – Sled Dec 22 '13 at 17:55
  • Not sure if this can be of any use : http://design-principle-pattern.blogspot.in/2013/12/single-responsibility-principle.html – aknon Dec 23 '13 at 04:28
0

From the point of my understanding, both principles are complementary, i.e. they need to be combined.

The ultimate consequence of violating ISP is becoming fragile, "shotgun surgury" or a "butterfly effect". A lot of code can break or require code updates because they depend onto some interface or objects which provide more than they needed. Changes become excessive.

The consequence of violating SRP is mainly decreased readability and maintentance. The lack of clear code structure may require people to search across the code base (a single responsibility is too distributed) or within a single large unit (multiple responsibilities scrammed together) to make a coherent change. In General, it is increased overhead to fully understand the concern (purpose) of some code snippet. Changes are prevented.

In that way, both principles act like a lower and upper bound for sane change management.

Examples for satisfying RSP without ISP – as provided by the other answers – express that there can be code which truly would belong together (like the stack example quote from Robert C. Martin). But it may do too much, is overengineered, etc. Maybe in very small examples, the effect is not visible, but if it grows large, it may be more comfortable to have a depending class still compile correctly after some unrelated part in the (indirect) dependency was changed. Rather than not compile anymore because unrelated things were changed.

ChrisoLosoph
  • 459
  • 4
  • 8