This is the third in a series of (hopefully) amusing posts into Robert Martin’s SOLID principles. It’s written as a dialog between Socrates and a student named Loej in the spirit of the dialectic method popularized by Plato. In this post, the principle explored is the “Open / Closed Principle”. I hope you find this enjoyable.
Socrates, who is the narrator of the dialogue.
Loej, who is but a bit of sand in the maelstrom of software development.
Socrates: Welcome again Loej. Last time we discussed the Single Responsibility principle.
Loej: Yes. We agreed that, in general, each class should have one responsibility; each class should have only one reason to change.
Socrates: Excellent. My question today is this. Have you ever experienced technological 20/20 hindsight?
Loej: You mean regret a technical decision? Of course. I think all software developers have.
Socrates: I’m talking more about clarity, not regret. Have you ever had a better understanding of the domain or a customer’s needs as you progress through development.
Loej: That usually happens as we go along during our iterations.
Socrates: What about after deployment?
Loej: That happens to. Often times once a product is in the wild we gain a lot of insight and get a lot of feedback from customers. If we can, we try and refactor the code to incorporate feedback.
Socrates: Let’s clarify something. You can’t refactor code to incorporate change. Refactoring is a transformation of code that improves software design but does not change software behavior.
Socrates: Anyway, So what you are saying is to use your newfound clarity, you rewrite the code to change its behavior. That’s fine during a fluid design of new code, but what about existing code that has stabilized, like after you have deployed?
Loej: Well, it’s usually no biggie. You just need to look over the whole project and make sure you don’t break anything when you rewrite.
Socrates: How are you sure you didn’t break anything?
Loej: You have to check all of the dependent classes.
Socrates: Check? You mean test?
Loej: Right. Check, test, just make sure it still works right. And you may have to do some rewrite some tests too.
Socrates: But doesn’t this risk breaking your existing functionality?
Loej: Well, you can’t change existing behavior in a class without rewriting its code.
Socrates: That is true, but you risk breaking something.
Loej: Then what are you supposed to do? You said we are changing the behavior of the program.
Socrates: Well, if you can’t change existing code in an existing class?
Loej: I get it. You want me to say create a new class. But then you’ve got all these dependencies pointing to the old class. You will have to recode those dependencies to point to the new class. You are still rewriting lots of existing code.
Socrates: What a conundrum. I propose instead of scurrying to cover new functionality here and there you incorporate the Open/Closed principle into your design.
Loej: OK I’ll bite. Just what is the Open/Closed principle?
Socrates: The Open/Closed principle states that Software Entities (classes, modules, functions, etc.) should be open for extension, but closed for modification. A modern interpretation would say that a class’s public facing interface should never change.
Loej: That sounds like Poppycock. Every time you want to make a small change you would have to create a new class. That’s a whole lot of work.
Socrates: Ah, but we lucky .NET programmers have the luxury of interfaces.
Loej: How does that help?
Socrates: By using interfaces the parts that shouldn’t change don’t need to We solidify the public facing parts in interfaces and agree to only use those interfaces.
Loej: OK, let me think about this. You’re saying if I need to change behavior I create a new class and implement the existing interface?
Loej: And if I need to add functionality to an interface?
Socrates: You don’t change the interface. You create a new interface, possibly deriving from the old one.
Loej: I’m not convinced. You still have to change that code somewhere – the bit that bind classes to interfaces. I mean somewhere you have to wire everything together and new up the instances.
Socrates: You’re right. There is a problem of tying everything together, and that opens up a whole new discussion about abstract factories and dependency injection.
Loej: OK, I can put that aside for a second. But you still haven’t convinced me. I see a maintenance nightmare. I see ICustomer1, ICustomer2, ICustomer3…
Socrates: Which brings us back to the single responsibility principle we discussed yesterday. If each class truly has a single responsibility, a single reason to change, that won’t happen.
Loej: Hmm… I’ll have to ponder it.
Socrates: I see this as a technical debt mitigation technique. During initial development interfaces are rightfully in flux and should be more fluid. As things stabilize though, this principle becomes important. Still, it doesn’t take much additional effort to correctly apply this principle.
Loej: Well, interesting as always.
Socrates: Indeed. Until next time.