SOLID: Open Closed Principle

dutch-door

In my last entry I introduced the S of the SOLID principles: Single Responsibility Principle. Today I will move to the next letter, the O which stands for Open Closed Principle. In an agile environment, teams and projects have to be responsive to change (4th value of the agile manifesto) in order to steadily add value (2nd value of the software craftsmanship manifesto). But respecting these values can be really hard if the code of your application is not easily extensible. This is where this second principle come in play.

Software entities (classes, modules, functions, etc…) should be open for extension but closed for modification.

This is the rule for the Open Closed Principle. There are 2 key attributes in this statement and in the name of the principle as well: open & close. Even if they are in opposition this does not imply that they block each other.

The module is open for extension, this means that it can be extended with new behaviors as the requirements for the application change. Yet the module is also closed for modification, in other words it implies that you should be able to extend the functionalities of this module without modifying its source code. I know it might sound confusing and this is why I’ll show an example to explain how this principle can be used.

public class User
{
    // some properties
}
 
public class NotificationCenter
{
    public void NotifyByEmail(User user, string message)
    {
        // some email related logic
    }
 
    public void NotifyByText(User user, string message)
    {
        // some texting relating logic
    }
}

In this piece of code I created a class that allows me to send notifications to a user by email or by text. Now imagine that I want my application to notify my users using social networks… I will have to modify the source code of this class to add new behaviors and it clearly violates the OCP. I will update my class in order to change this “mistake”:

public interface INotificationService
{
    void SendMessage(User user, string message);
}
 
public class EmailNotificationService : INotificationService
{
    public void SendMessage(User user, string message)
    {
        // some email related logic
    }
}
 
public class TextNotificationService : INotificationService
{
    public void SendMessage(User user, string message)
    {
        // some texting related logic
    }
}

public class FacebookNotificationService : INotificationService
{
    public void SendMessage(User user, string message)
    {
        // some facebook related logic
    }
}
 
public class TwitterNotificationService : INotificationService
{
    public void SendMessage(User user, string message)
    {
        // some twitter related logic
    }
}
 
public class NotificationCenter
{
    public void Notify(User user, string message, INotificationService service)
    {
        // some logic
        service.SendMessage(user, message);
    }
}

My NotificationCenter now use a specific interface to do its work and I am able to add functionalities to it without changing the code. All I have to do is to implement the INotificationService to add a new behavior. By doing this I can even separate each implementation in a specific assembly and I avoid putting Facebook or Twitter dependencies in my class. For instance if the Twitter API changes and I have to change the code, I can only package and deliver the TwitterNotificationService, I don’t have to redeploy everything.

The key to the OCP is abstraction. Yet this does not mean that you have to use it everywhere, the context is important and premature abstraction may add complexity to your source code where it is not needed.

I hope you like this presentation of the Open Closed Principle for the SOLID series. You can also check this great article by Joel Abrahamsson about this principle.

See you next time!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s