Of the handful of programming principles that I live by, the Open-Closed Principle is perhaps the most important. I consider the Open-Closed Principle to be the central goal of all software development and what we should be striving for when doing development, beyond just getting our features to work.
I was talking with Jim Shore, co-author of the book The Art of Agile Development, a few years ago about the Open-Closed Principle and he said that he felt it was outdated. It is true that the Open-Closed Principle was first created at a time where you might have to wait overnight to get your program compiled, and without advanced refactoring tools or integrated development environments. The way we build software today is very different, but I believe that the Open-Closed Principle has tremendous application even in today’s environments.
The Open-Closed Principle says that entities (methods, classes, modules) should be “open for extension but closed for modification.” What does this mean? It’s basically saying: We want to build code in such a way that it won’t need to be changed very often.
When I asked developers what they would rather do, write a new feature or take a feature and integrate it into an existing system, invariably they respond that they’d rather write the new feature. When I ask why, they give me all sorts of examples: it’s more fun to implement something new, the existing system may be difficult to understand or poorly written, and integration is typically where the really nasty bugs show up. In fact, it’s almost universally true that bugs are more prevalent when we modify existing code than when we write new code.
If this is the case, that it’s safer to write new code than change existing code and that developers prefer to write new code over changing existing code, then why not set ourselves up to succeed? After all, we’re the developers and we can create code any way we want. This is exactly what the open-closed principle is saying.
Of course, it would be wonderful if moving from version one of a product to version two only required us to add new code and not change any existing code, but that’s not usually possible, so the question becomes: how to minimize changing code and maximize writing new code.
Ideally, for any new feature or change of an existing feature, I would like to change code in only one place and then add new code. This is what open-closed-ness means to me. If I can add a new feature by simply adding new code and perhaps updating a factory then I consider my design to be open to that new feature.
This is a question I ask over and over again in design reviews and code reviews: “How Open-Closed is your design?” By this I mean how open are you for extending behavior and where do you have to change code to implement new behavior? Adding new features should require minimal changes to existing code.
When we think about building software in this way, it has a huge impact on our approach. We suddenly see that there are different ways to extend behavior. For example, we may want to add a new variation to an existing system such as a new form of encryption. We may want to change the sequence of steps in an algorithm or we may want to change the number of steps in an algorithm or any number of other kinds of changes. If we’re able to encapsulate these kinds of changes so that when we need to make them later we can do so without affecting the rest of the system, then we would say we’ll be open for that change.
Following the Open-Closed Principle, we are forced to write code that’s more cohesive, less redundant, and of overall higher quality.