How I Broke 13 Endpoints and Learned the Hard Way About SOLID’s Open/Closed Principle
As developers, we often take our systems for granted. We build, we test, and sometimes, we break things. I recently found myself in a situation where I broke not just one, but 13 endpoints, and the reason? A simple violation of a core principle of object-oriented design: the Open/Closed Principle (OCP), one of the five principles that make up SOLID.
What is SOLID?
Before I dive into how I learned about the importance of OCP, let’s briefly go over what SOLID stands for:
S: Single Responsibility Principle (SRP)
O: Open/Closed Principle (OCP)
L: Liskov Substitution Principle (LSP)
I: Interface Segregation Principle (ISP)
D: Dependency Inversion Principle (DIP)
Each principle is a guideline that helps developers design software that is easier to maintain, extend, and scale. But one principle stood out during my recent experience: the Open/Closed Principle.
Understanding Open/Closed Principle
The Open/Closed Principle states that software entities (classes, modules, functions, etc.) should be open for extension but closed for modification. In other words, you should be able to add new functionality to a system without changing the existing code.
Why is this important?
If we don't respect this principle, we risk introducing errors into areas of the code that were previously working fine. Imagine a situation where you're working with a function that is referenced in multiple parts of your system—what happens if you change its behavior or return value? If those references expect the function to behave in a certain way, you can easily break the whole system.
My Experience
: The Case of the Broken 13 Endpoints I was working on a system with several endpoints that relied heavily on a function to return specific data. One day, I was tasked with making a change to the return value of this function. It seemed like a simple fix—one change to improve the code.
However, I didn't stop to think about the impact this would have. This function was referenced in 13 different places across various endpoints. Without considering the OCP, I modified the function's return structure, assuming it wouldn't cause any issues.
What happened next was a mess: 13 endpoints stopped working. Each endpoint relied on the previous behavior of that function, and by changing its return value, I broke the contract that these endpoints were built on. This mistake cost a lot of time to fix and even affected the overall system stability.
How OCP Could Have Saved Me
Had I adhered to the Open/Closed Principle, the change would have been different. Instead of modifying the function's return type directly, I could have extended the function’s behavior—keeping the original functionality intact while adding the new behavior in a way that didn’t affect the existing system.
In practice, I could have:
Created a new method to handle the new behavior.
Used polymorphism to extend the functionality.
Made use of strategy or decorator patterns to change the behavior dynamically without breaking existing code.
The key takeaway here is that by thinking through the principle of open for extension, closed for modification, I could have avoided the huge impact that this change had.
Conclusion:
Learn From My Mistake In the end, this was a painful but valuable lesson. It reinforced the importance of defending your code by respecting principles like OCP. By keeping systems open for extension and closed for modification, you avoid unintentionally breaking things that other parts of the system depend on. Always think about the bigger picture before making changes that might seem small at the time.
So, to all the developers out there—don’t be like me. Respect the Open/Closed Principle. It will save you from breaking everything when you least expect it!