There was a post on the Alt.net group today about how a Factory could violate OCP (Open/Closed Principle) if new methods were added. I’ve had discussions on this issue in the past and figured it deserved a post.
The Open/Closed principle is a software design principle that says:
software entities (classes, modules, functions, etc.) should be open for extension, but closed for modification
I first learned of this principle from one of Robert C. Martin’s books, as it makes up the O in the SOLID principles. I respect SOLID and found that if you do nothing but adhere to these principles, you’ll generally design better software. It’s necessary, however, to use good judgment when applying these guidelines.
In general, OCP is the only SOLID principle that I take issue with, specifically the literal interpretation of “closed for modification”. It seems that many developers take this to the extreme and spend unnecessary effort to avoid having to ever modify a class or method after it has been written. The poster in the Alt.net thread was worried that adding an IF block to a method would violate OCP and was asking advice for how to avoid it.
My interpretation of OCP is that the interfaces or API’s should be closed for modification so that any future changes won’t break client or other calling code. That means keeping your method signatures the same and not changing properties and access modifiers. Software projects are typically time and resource sensitive and many design decisions must be weighed against the ROI they achieve. Introducing a more complex design so that a few lines of code don’t have to be added later seems ridiculous to me.
Here’s an example where OCP doesn’t provide the necessary value to make it worth the effort.
Let’s say you have an Order entity and that entity has a Validator class. The Validator class validates that the Order has all the required values in the right format. This is how most of us handle validation, using some IValidator<TEntity> type of pattern. Now let’s say that this Order class goes to production and functions properly for several months. Now the business comes back and says that Credit Card Security Code is required for PCP compliance. If we follow OCP in a literal sense, we can’t just add that validation rule to the Validator class.
If a person is designing with OCP in mind, they may use the Specification pattern to handle validation, which would allow us to add validation rules any time without modifying any existing classes. That is certainly a viable option, but is not as simple and easy to understand as a single Validator class and would certainly be less effort to implement. I would also argue that the quality of my software with a Validator class is no less than an application using Specifications for validation rules. If my Validator is using the Notification Pattern to return validation status and error messages to various layers, adding this additional validation rule will require no modification by the rest of the application, which is what OCP means to me.
The SOLID principles and OCP are guidelines to help us deliver more extensible and maintainable software. However, being a rigid and literal follower of OCP and the “closed for modification” philosophy can lead to over engineering. Adding complexity for the sake of never touching a class or method again after it’s been written may have its place in some software projects, but chances are in most cases your quality won’t suffer by adding an IF block.