We’re back on SOLID ground. Today we explore the ‘I’ in SOLID, A.K.A the interface segregation principle or ISP. After debating how inappropriately the principle is named, we dive into what it means, that “no client should be forced to depend on methods it does not use.” We drill even further into what this means by using the metaphor of a Swiss Army knife and what it would take to code an athlete in Java. We discuss why you should apply the ISP and later share experiences where we’ve abandoned the principle, intentionally or not. After talking about how Go’s standard library and I/O interface serve as the poster for the principle, we focus on the benefits that the ISP can bring to your code — even to pure duck typers who don’t enjoy the feedback provided by code interfaces. Tune in to hear more about writing smoother code by applying the interface segregation principle.
Key Points From This Episode:
- A discussion on if ‘the interface segregation principle’ (ISP) is an appropriate name.
- Defining the principle; “That no client should be forced to depend on methods it does not use.”
- Exploring the principle through the metaphor of a Swiss Army knife.
- Using the example of an athlete to explain the ISP.
- How Go has integrated the ISP into its standard libraries and I/O interface.
- Situations where you might ignore the ISP — when having clean code is secondary.
- Dreaming of the day when code can infer what your interface should be.
- Code interfaces versus pure duck typing and why we still need the ISP.
- Summarizing the importance of the ISP in helping your code run as smoothly as it can.
- And much more!
Transcript for Episode 168. SOLID - Interface specificity principle
[0:00:01.9] MN: Hello and welcome to The Rabbit Hole, the definitive developer’s podcast. Live from the boogie down Bronx. I’m your host, Michael Nunez. Our co-host today.
[0:00:09.3] DA: Dave Anderson.
[0:00:10.1] MN: And our producer.
[0:00:11.3] WJ: William Jeffries.
[0:00:13.3] MN: Today, we’re continuing on the SOLID conversation with the interface segregation principle.
[0:00:20.7] DA: Yup, all aboard the SOLID train.
[0:00:24.8] MN: That is a mouthful and we’re all aboard the interface train. We’ll get right to it, we still have this letter, the ‘I’ in SOLID and one more that we’re planning to give, of course we had interviews and stuff like that but we’re back in the SOLID business. We’re going to finish it, I promise you, we will complete SOLID together.
[0:00:45.2] DA: This is number four of five. Right, what is the interface segregation principle. IT sounds smart.
[0:00:54.9] MN: It sounds very smart.
[0:00:56.8] WJ: It sounds bad. Shouldn’t we be desegregating? I feel like we did this back in the 60s. Let all the interfaces ride wherever they want on the bus.
[0:01:05.8] DA: Maybe this is, like, kind of one of those terms that needs to get updated for the 2020.
[0:01:12.1] MN: Yes.
[0:01:13.1] DA: got to refactor the SOLID principle. I feel like you could also call it ‘interface specificity principle’.
[0:01:22.4] MN: Let’s do that, we’re not calling it what we called it before, it is now the interface specificity principle.
[0:01:28.9] WJ: I think it’s worse yeah, it’s even hard to say.
[0:01:31.2] DA: Yeah, that’s the point, that’s supposed to be awful. I’m going to refer to this particular principle as the ISP from now on.
[0:01:41.7] WJ: But that’s the internet service provider.
[0:01:44.1] MN: No, I will use the internet service provider when I need to but for now, ISP will be the interface specificity principle from now, moving forward.
[0:01:54.0] WJ: Or ‘interface separateness principle’? ‘Separation principle’, no.
[0:01:59.8] MN: ‘The interface separates’—
[0:02:01.0] WJ: It’s still a mouthful. ‘The interface don’t mix it up principle.’
[0:02:06.9] MN: There you go. 2020 has been forever. We got till forever to figure out a better name for this before the end of the year. According to Robert Martin, a friend of the show, I guess. The quote is that, “It states that no client should be forced to depend on methods it does not use.” Does anyone have any thoughts on that particular definition of the ISP? The interface specificity principle?
[0:02:33.9] DA: I guess it’s like telling you that you shouldn’t have a Swiss Army knife if you’re just trying to cut a block of cheese, you should just use a knife.
[0:02:43.1] MN: You should use a cheese knife for cheese.
[0:02:46.0] WJ: I like the idea of the objects rebelling against being forced to implement methods that they don’t use.
[0:02:52.1] MN: Wait, you're saying that you like the idea of that? I mean, the way he phrased it, it sounds like there’s protests happening, stop forcing us to implement these methods.
[0:03:04.2] DA: Object rights.
[0:03:06.7] MN: Exactly.
[0:03:08.2] WJ: I think the object really cares whether it implements the method or not but —
[0:03:12.8] MN: But it’s the developer who has to implement things that aren’t forced to be implemented. You're forcing developers to throw an exception when it’s never going to use it anyway.
[0:03:24.3] DA: Right, it’s like if my knife interface is, like, modeled after the swiss army knife, then it needs to have a pliers method, it needs to have a toothpick method.
[0:03:34.8] MN: And a scissors method.
[0:03:36.1] DA: The scissors method, the tweezers method, the tiny knife method, the big knife method, the nail file. If your aunt who bought you this, thinks you're mature enough, then it has the corkscrew method. But, like, my aunt didn’t think I was mature enough when she got me one so I do not have the corkscrew method on mine. I threw an exception for the corkscrew.
[0:03:56.9] MN: Yeah, you would have to throw an exception for the corkscrew method and that’s crazy.
[0:04:01.3] WJ: This is too many methods stacked to implement.
[0:04:04.5] MN: If you were only using knives to cut what Dave mentioned before which is you want to cut a block of cheese, you wouldn’t need tweezers and a nail file for that.
[0:04:16.7] DA: Maybe it’s your motive, maybe you’re trying to grate some Romano. It will probably be a little messy.
[0:04:23.7] MN: It would be messy.
[0:04:26.2] DA: Yeah, I guess the idea is like, if you got to cut something, then just have a method to cut. And then maybe the Swiss Army knife could implement cut or it could be like, the brie knife, you know, which has like the, I don’t know, it’s like a flat thing that you got to get in there and it’s not very sharp but you can still cut with it.
[0:04:52.4] MN: Right. Through our journey of the SOLID principle, I’ve been leaning on the DZone.com, you write in Java, the Java is very verbose and I think it’s really good to pick some of the examples especially from this language. I think the example that they use to explain the interface specificity principle is like the idea of an athlete.
An athlete can compete in many things. The interface athlete would have something, like, compete. But it also has a method for ‘swim’, a method for ‘high-jump’, any method for ‘long-jump’. The issue is that, what if you are an athlete, say, John Doe is a swimming athlete. But you wouldn’t implement the high jump and the long jump if, you know, John Doe just swims.
Throw an exception I guess for the other two. Which becomes a problem because then you still have to implement this method for John Doe even though you would never participate in any high-jump or long-jump related offense. What are some ways to not get caught up in that? Just to create smaller interfaces for the athlete, say, a swimmer athlete or jumping athlete?
I’m not too familiar with the high and long-jump in the Olympics where athletes would do that so I don’t know if that’s part of the same event. Correct me if I’m wrong if those are two different sporting events. You would implement them differently, essentially.
[0:06:17.5] DA: Yeah, there’s even maybe — they’re all different and maybe even ‘swim’ is too specific, Michael Phelps with 20 something gold medals because there’s just so many swimming events.
[0:06:30.1] MN: Yeah, because there’s like the breast stroke race and then the side stroke and then there’s backstroke, there’s underwater. I don’t particularly know the Olympics at all but he won mad medals, that’s all I know. He has long arms and he wins. Even then, you would have to break it down depending on what kind of swimming this athlete is going to do. The idea is just to break it down.
[0:06:57.0] DA: Have the smallest, most specific possible interface that the application needs. I think Go does this really good in their standard library with the I/O interfaces. I was reading the docs for this a while back when I was working on a Go project and so for I/O, input and output, you have a couple of different basic interfaces with just, like, one method on it.
You could have a reader interface where the — it just implements the read method where they’ll give you some bytes. Or you could have a writer interface where you write some bytes. Or it could be like a closer interface where you close it or an opener interface where you open it. And then, it takes these like really granular interfaces and combines them into all different combinations. Like read-writer or read-write-closer. And then your code that you actually write is only coupled to that really specific thing that you actually need. If you don’t need to write to permit, you just need to read and then you can just accept a reader. And in some cases that is all you need. Like, if you are receiving distribute packets, you are not going to be writing to the body of the request that you are receiving. You’re only going to be reading from it.
Being specific makes the code more clear, at least from the consumer perspective. On top of the perspective that you were talking about. Where, I guess whoever is writing the HTTP library, they don’t need to put a write method onto their body because you don’t write to a HTTP body, you only read from it.
[0:08:42.9] MN: And I imagine that just keeps the — you know exactly what the interface is doing and what methods are expected of that interface. Because if it was just the library where it’s like, “Oh HTTP.” And it does all of these different things and you are only using one part of it, then it makes it — there is so much code that you are not using them as opposed to being really specific to the thing that you want to do just like just read or just write. And then using that makes it a lot more cleaner.
[0:09:09.6] DA: Yeah, totally.
[0:09:10.4] WJ: Have you guys ever violated this principle?
[0:09:12.6] MN: I like to think that I have. I think that there may have been times where, I mean, like even reading what I mentioned before — the idea of you have this interface and then you are just going to — you throw an exception, whatever this method gets called. Like, I think in my old Java of days, I feel like that has happened in the past. Yes.
Did I have good reasoning? Probably not, if I am being honest here but it was just like, “Oh I can’t implement this, boom, oh well, we’re never going to call that.” So just throw in everything, if it happens, kind of deal.
[0:09:42.8] WJ: I feel like a lot of times you can sort of rationalize like, “Well you know maybe, someday, I will want this method.” And it would be a pain the ass to make a whole new interface.
[0:09:53.6] MN: It’s just one line, right? Just one throw-exception, who is looking at it? Don’t worry about it. I mean I imagine when it gets to seven or eight different methods that you are throwing exceptions for, where you have to kind of look at the code and say, “Okay, well if this interface is not doing half of these methods, then we should figure out how to split it up.” I guess is the idea.
[0:10:19.3] DA: Yeah, sometimes if you are trying to really slot a bunch of different behavior into objects that you are using in a really general way — sometimes it can be tough to figure out what the right abstraction is. When you have more and more methods, like, it becomes harder to think about, “Okay, well, what actually it is the thing?” The example of the reader, it is really clear — that this thing just — you can read with it. But when you start adding more and more methods, then — I felt like that’s when you get in that situation. Where you need to start throwing exceptions of having forced or weird default behaviors that maybe don’t make sense.
[0:11:03.5] WJ: When are we going to get to the point where the code can just infer from usage what the interface should be? We’ve got implicit typing, right? Where the code can tell, “Oh because you are assigning an interjector in this variable, this variable should be typed integer, right?” And that technology has gotten better so that more and more things are implicit. Why couldn’t the code also check and see what methods are called or what methods could be called on an object? And then just implicitly infer what methods should be in the interface.
[0:12:15.1] WJ: Yeah, I mean I think it would be cool though if they did have an interface so that the editor could complain if you, through static analysis, could determine that there could potentially be an error.
[0:12:27.6] DA: Yeah that’s true.
Well now, I think it’s tree-shaking, some weird nonsense name they gave for this. But the idea that if you take like — if you only use four or five different methods within Lodash, then it will actually, even though you have it in your system, it will only actually build the four or five methods that actually use it. So I think there is some kind of tech for this kind of inferring what interface methods can and cannot be used. But in terms of developing an interface ourselves, we need to make sure that we don’t allow it to happen I guess.
[0:13:27.6] DA: Yeah, I haven’t seen it where it will automatically infer what the interface is. There are some like tools for the Ruby-type checker. I haven’t looked too closely into it but like, the people who are working on that were, like, coming up with tooling that monitors your code in production and figures out what types are going through. And what it might be but in Go, we would just define an interface alongside the thing that was using it.
And just make it as specific as possible to what we were trying to do. Which has the downside of potentially being duplicated if it was used in multiple places and being a little bit separated from the actual implementation. But if you have a nice editor then that can help you with that. Definitely a believer in JetBrains for their static flow types.
[0:14:22.7] MN: Oh yeah JetBrains definitely helped me with that. I thought people escape to languages like Ruby and Python to escape from all of the type checking and the screaming that you get from your other editors, which is why people like the duck typing aspect of Ruby.
Don’t violate the interface specificity principle to ensure that your code runs well as well as it can. Just that it is clear for the developer who has to implement and use the interface to ensure that’s not cluttered with all of these methods that you may and may not use to create a new object that extends from it.
[0:15:00.3] DA: Yeah, even if you don’t like an interface in the code, explicitly, it still makes it easier, if the duck type that you’re going for is consistent and focused and specific.
[0:15:12.6] MN: All right, are we going to actually change the name to interface specificity principle? I’m down. I think I have gotten used to saying that. I think I’m ready.
[0:15:22.5] DA: Are we going to edit Wikipedia now?
[0:15:24.1] MN: Yeah, I think we should do that. We should definitely change it right now. Anyone who is listening if you want to go and try to change and see what happens.
[0:15:32.1] DA: Yeah, let’s leave it to them. You guys go change it if you like it.
[0:15:35.9] MN: Oh man.
[END OF INTERVIEW]
[0:15:37.3] MN: Follow us now on Twitter @radiofreerabbit so we can keep the conversation going. Like what you hear? Give us a five star review and help developers like you find their way into The Rabbit Hole and never miss an episode, subscribe now however you listen to your favorite podcast. On behalf of our producer extraordinaire, William Jeffries and my amazing co-host, Dave Anderson and me, your host, Michael Nunez, thanks for listening to The Rabbit Hole.
Links and Resources:
Our seasoned cross-functional agilists work with you to develop technology, ship product and deliver value. We leverage our diverse expertise across industries and throughout the organizational growth cycle to your benefit. We bring best practices, emergent practices and creative solutions to your problems.