163. SOLID - Open-Closed Principle

July 8, 2020

As part two of our series that explores the SOLID software design principles, this episode dives straight into the topic of the open-closed principle — that’s the ‘O’ of SOLID for those who are counting. As a software principle created in 1988, back in the days of C++, the essence of this principle states that you should create code that’s “open for extension but closed for modification.” Using the example of needing to create a calculator that measures the areas of rectangles, we talk about how the open-closed principle makes it easier to create an extension to your area calculator if you suddenly need to calculate the area of a circle. While this principle makes it easier for developers to add features to your software, we discuss how needing to perform “shotgun surgery” on your code may be a sign that you haven’t adhered to the open-closed principle. For a real-world example, we share how we’ve implemented the open-closed principle into an intranet project that we’re developing. Near the end of the episode, we talk about how following the open-closed principle helps ensure that you’re following the other SOLID principles. Listen to this episode and learn how important the open-closed principle is to writing good code.


Key Points From This Episode:


  • The definition and origins of the open-closed principle, as created by Bertrand Meyer.
  • Reducing the principle to its essence; code should be open for extension but closed for modification.
  • Examples are given to illustrate how important the open-closed principle can be.
  • Avoiding “shotgun surgery” by creating extensions and not modifications.
  • Mike and Dave provide a real-world example of how the open-closed principle informed their code.
  • How adhering to open-close principles ensures that you’re following other SOLID principles

Transcript for Episode 163. SOLID - Open-Closed 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.6] DA: Dave Anderson.


[0:00:10.9] MN: Today, we’re still having SOLID thoughts, we’re talking about the open-closed principle.


[0:00:16.4] DA: It’s part two.


[0:00:18.1] MN: It’s part two of five as you can imagine, there are five letters in SOLID and we’ll go through each one of them.


[0:00:26.0] DA: By most spellings.


[0:00:28.0] MN: By most spellings, yeah, I mean, don’t ask me, I’m not sure, but yes, it’s five letters. Today we’re talking about the open-close principle and we’ll just talk about examples of the principle, how you can kind of look at a piece of code base to understand whether you're following this principle or not and examples about what to do.


[0:00:45.8] DA: You can finally explain to your friends over a beer what the open-close principle actually is. I feel like it’s so mysterious, is it open or is it closed?


[0:00:55.1] MN: Well, we’re going to get into that right now.


[0:00:57.6] DA: No, you got to tell me.


[0:00:59.1] MN: When it’s open and you’re able to open it, but then you have to be able to close it. The idea comes from the engineer, named Bertrand Myer, who has written a book in 1988 called Object Oriented Software Construction and it states; “Software entities,” in parenthesis, clauses modules, functions et cetera — “Should be open for extension but closed for modification.”


The idea being that you want to make sure that the piece of code that you’re writing is easily extendable for the next engineer who wants to add more features to the code base but not completely modifying it where it doesn’t look like the method you first wrote when you first got to this code base.


[0:01:44.1] DA: Right. It’s like yeah, OG software engineering about 1988.


[0:01:50.2] MN: Yeah, I mean, there’s probably a lot of C++ talking there and pointers and all sorts of craziness.


[0:01:56.5] DA: Small talk.


[0:01:58.7] MN: Yeah. But the idea of, like, object-oriented programming will exist regardless of the programming language you use and I have an example. I think we use examples, previously the shapes example and we can dive into that. I have a real-life example that we’re dealing with right now at Stride and I could talk about that as well.


[0:02:20.8] DA: Okay, we have this haiku from 1988, “It’s open for extension but closed for modification”. So that means that I can extend the functionality of the code but I don’t want to change anything about it. I can reduce, maybe, the amount of bugs that I might introduce into the system and I don’t have to like tear it all apart in order to add some more functionality.


[0:02:51.3] MN: that is correct Dave, podcast over, we are done, there goes open-closed, that’s it.


[0:02:56.7] DA: Okay. I still don’t feel like I’m there yet.


[0:03:01.5] MN: I’ll dive in with the example we’ve used before so you know, think about last week and then play the violin. You have an area calculator, someone, suppose Bobby — is a product owner and wants an area calculator that when you give it a rectangle with two sides and you ask for the area, it gives you the area of a rectangle. And the area of rectangle is the width times the length. Classic. And if you have many different rectangles in a list, if you give it a list of rectangles, it will give you the area of all the rectangles. So, yay! Bobby’s happy with this particular piece of code. Bobby now comes up to you and says hey, we have an area calculator and we got a new shape we have to get the area for. Which is the circle.


We use the circle now. One could extend the area calculator so that every time it looks for each item in the array, whatever shape it is, we have to check if the shape is a rectangle or if the shape is a circle. If the shape is a rectangle, then do your area width times height. And if it’s a circle, then you’re going to do the radius squared times pie.


[0:04:29.8] DA: Yeah, I feel like I’ve seen code like this before where it’s like a switch case and it’s like okay, if shape.type is this then you go into this case and this other case and this other case.


[0:04:42.9] MN: Right, that’s one way to do it but the thing is we’re now modifying this area calculator to handle all these different types of shape that makes sense.


[0:04:52.6] DA: Right, we want to be done with that, we never want to write an area calculator again in our types.


[0:04:59.4] MN: In our lives, exactly. What you could do is — the idea of like the open-closed principle is that you have a – like an abstract class for example that has, and we call that a shape, right? That particular abstract class will have one method and it will be the area. Any of the classes that we create that uses the shape abstract class will have to identify, or, like, implement the area for that particular shape. When you create a rectangle, you're going to use a shape and the area of a rectangle is with times height. Same thing goes for circle where you get the radius square. Multiply that by pie.


[0:05:40.4] DA: Favorite number.


[0:05:41.6] MN: Favorite number. 314159265358979, I think. I don’t know. Someone’s going to have to check me on that.


[0:05:51.9] DA: I can’t even remember like, my phone number so —


[0:05:56.4] MN: — Gosh, I can’t laugh, it hurts. The idea is that, in your area calculator, all you have to do is for each shape, you can just call the area method and your shape will have its own implementation on how to print out the area of that shape.


[0:06:13.6] DA: Right, I guess like, you know, if you don’t want to use an inheritance, because like all the cool kids are doing composition these days. And you can use an interface or a duct tape too, as long as you’re passing in a list of shape that is area, has the area capability then you can do that.


[0:06:36.7] MN: Yeah, for like — just make sure that the method responds to area as a method and then you should be able to get the area of any shape that you pass in. The idea is like, if you know, Bobby comes out of nowhere and he’s like, “Hey, we need the area of a triangle,” then you can just create a new shape that takes the triangle as an area and then be able to calculate that and then you’d never have to worry about extending the area calculator for areas anymore, right? And then you could do a football field. You can do all sorts of these different shapes if you really want it to and not have to extend the area calculator anymore.


[0:07:12.4] DA: Right, for even like a football.


[0:07:14.1] MN: Oh yeah, if you want to get the area of a football you can.


[0:07:16.1] DA: I am pretty sure there’s got to be an equation for that but I do not know what it is.


[0:07:22.0] MN: I can’t even throw a football. I am so bad at it.


[0:07:25.4] DA: But yeah that would be something that would be like, so complicated, you know? If you just plan on putting that into the area list calculator and you can imagine the tests we’ve got very complicated as well.


[0:07:40.3] MN: Exactly and then rather than testing the area calculator for every single shape you can just test each shape that it returns the correct answer and when you call area to it and then that’s — it is very isolated from the implementation of the area calculator and you can keep the area calculator closed the whole time as you’re extending the application by creating these new shapes that respond to the area of method.


[0:08:08.3] DA: That actually makes sense and I guess on the other side, when maybe it goes wrong and you can wonder if there is a lack of open-closed adherence, like, if you are making changes to a lot of different existing things like shotgun surgery then that could be counter indication that you’ve not separated things out in a way that you just create new code.


[0:08:38.0] MN: Right, so you definitely want to avoid the shotgun surgery. Don’t ever get shotgun surgery and don’t do it. If you know that you have to constantly change this one particular class to behave in a way that you want it to, then maybe what you are doing is modifying that piece of code and think about what you would need to do to make it so you don’t have to modify it and just be able to extend it a little bit more.


I think we have all seen the examples, Dave as you mentioned, where this is just like a trilling if statement and then you do the next one, there’s another if statement, you do the next one there is another if statement and then think like how do you — how can you abstract that so that you can leave that class alone and then have the method of the objects itself take care of the area of a shape, for example.


[0:09:28.6] DA: Totally.


[0:09:29.5] MN: So another example that I can use probably much more bigger than shapes — Stride has an application called ‘the intranet’ and one of the things that we need to do as a consultancy is to figure out when are people going to be available so that they could go on to the next client. So we created this page and it’s called the ‘availability page’ where we can see the user, we can see what client they’re currently on. And we can see their next available date. Which is very good because then we could see like, “Oh we see that Suzy is going to roll off in three weeks so maybe we could place Suzy and Bobby Core,” for example — just throwing names out there. And one of the other features that we’re required for this is to see any future placements that a person or a consultant may have. So you know people can be up for grabs to go to different places and different engagements, for example.


And you know, one of the things that you want to think about is if we are going to print out the future placements of a user, we don’t want to write that code in the availability page like right in the Javascript. What we could do is just have a method in our getter’s file that can get the list of future placements given a user ID. That way we can definitely extract that information without having all the logic exist in the availability page. We have that calculation happen elsewhere where we can then just fetch that information and then display it to the user. And we can isolate the test a little differently because then we could just test the getter file to ensure, “Hey, given this ID, I expect these multiple placements,” versus testing that through the availability page it will be a little bit more difficult and just like really, really troublesome.


So just like removing, extracting all of that out. So that it does exist and the only in the getter’s file makes it so that it is easier to test and then we can use it and then be able to display the future placements of consultants.


[0:11:33.3] DA: Right. So like the way that availability is calculated is closed to that page, the availability page. Because it just asks the interface for the thing that it cares about and then it gets it back. So it’s like, okay, you do what you got to do to get me this thing.


[0:11:53.0] MN: Right, like, the availability page is extensible and that it can add this new column that says ‘future placements’ but it doesn’t have those calculations in the page that’s somewhere else that’s going to fetch that information and then get it and then do that. Jill is very excited about this. Very excited.


[0:12:10.4] DA: At last, features.


[0:12:14.6] MN: At last yes, oh yeah. Go listen to the five episodes and then be a pro and then start making money around here. That’s what it needs to do.


[0:12:22.8] DA: Just got to make rent.


[0:12:24.1] MN: Yeah, he’s got to pay something. The idea is that the availability page is extensible and that you can add a new column but we are not modifying it in that, “Hey, the availability page is also responsible of calculating the future placements.” We have that done elsewhere, which is — you may hear that like a lot of the principles that we are going to spell out in SOLID depends on other ones. That is going to be a thing that is going to happen.


And I think that the open-close definitely is very, very strict to the single responsibility. You make sure that when you’re following one, you’re definitely going to be doing — following the others as well.


[0:13:02.3] DA: Yeah that makes sense. Some foreshadowing.


[0:13:07.1] MN: Yeah, as we go through — along through the series, I’d love to hear any examples that we may come up. I am sure I am going to run into a lot in the next couple letters that we’ll be working through.


[0:13:16.9] DA: So many letters.


[0:13:19.7] MN: Yeah, we got a lid. Just a lid, just put a lid on it. We put a lid on it in the next three episodes and we’ll see you then.




[0:13:28.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:

The Rabbit Hole on Twitter

Bertrand Meyer

Object Orientated Software Construction 2nd Edition