DEV Community

Cover image for Understanding the Open/Closed Principle (OCP) from SOLID: Keep Code Flexible Yet Stable
Daniel Azevedo
Daniel Azevedo

Posted on

Understanding the Open/Closed Principle (OCP) from SOLID: Keep Code Flexible Yet Stable

When we talk about writing clean, maintainable, and scalable code, one of the first principles that comes to mind is the Open/Closed Principle (OCP) from the SOLID principles. It’s a concept that encourages developers to design systems that are flexible enough for future changes while minimizing the impact on existing functionality.

But how does it work in practice?

What is the 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 simple terms, this means that your code should be structured in a way that allows new functionality to be added without altering existing code. Why is this so important? It helps prevent bugs or issues from being introduced when making changes, especially in large codebases.

Real-World Example: Payroll System

Imagine you have a payroll system that calculates salaries for employees. You start by calculating a basic salary. Now, what happens when a new requirement comes in to calculate bonuses or commissions? Instead of modifying the core logic of your salary calculation (which could lead to bugs), you could apply the OCP principle to extend the functionality.

Here’s an example in C# to demonstrate this:

// Base class for salary calculation
public abstract class SalaryCalculator
{
    public abstract decimal CalculateSalary(decimal baseSalary);
}

// Extension for basic salary calculation
public class BasicSalaryCalculator : SalaryCalculator
{
    public override decimal CalculateSalary(decimal baseSalary)
    {
        return baseSalary;
    }
}

// Extension for bonus salary calculation
public class BonusSalaryCalculator : SalaryCalculator
{
    private readonly SalaryCalculator _baseSalaryCalculator;
    private readonly decimal _bonus;

    public BonusSalaryCalculator(SalaryCalculator baseSalaryCalculator, decimal bonus)
    {
        _baseSalaryCalculator = baseSalaryCalculator;
        _bonus = bonus;
    }

    public override decimal CalculateSalary(decimal baseSalary)
    {
        return _baseSalaryCalculator.CalculateSalary(baseSalary) + _bonus;
    }
}

// Usage example
var basicSalary = new BasicSalaryCalculator();
var bonusSalary = new BonusSalaryCalculator(basicSalary, 500);

Console.WriteLine($"Basic Salary: {basicSalary.CalculateSalary(3000)}"); // 3000
Console.WriteLine($"Salary with Bonus: {bonusSalary.CalculateSalary(3000)}"); // 3500
Enter fullscreen mode Exit fullscreen mode

In this example, we’ve applied OCP by extending the salary calculator with a bonus feature without modifying the existing logic. This way, if more features come in (like taxes, overtime, etc.), we can simply extend the functionality through new classes rather than touching the existing ones.

Why Does OCP Matter?

  • Flexibility: It allows systems to grow without affecting existing functionality.
  • Maintainability: Makes your code easier to understand and modify.
  • Scalability: Encourages systems that can handle new requirements seamlessly.

Potential Pitfalls

While OCP is incredibly powerful, it’s important not to over-engineer a solution. If you apply too many layers of abstraction too soon, you could end up with a complex codebase that's hard to follow. So, always consider the current and foreseeable needs of the application when deciding how to apply OCP.

Conclusion

The Open/Closed Principle helps us build flexible and robust systems that can evolve with changing requirements. By keeping classes open for extension but closed for modification, we can write code that’s easier to maintain, extend, and scale over time.

What are your thoughts on applying OCP? Have you found it challenging to implement in certain scenarios? Let’s discuss in the comments!

Speedy emails, satisfied customers

Postmark Image

Are delayed transactional emails costing you user satisfaction? Postmark delivers your emails almost instantly, keeping your customers happy and connected.

Sign up

Top comments (1)

Collapse
 
isocroft profile image
Okechukwu Ifeora

This is not very good code because

  1. There really is not reason why the basic-salary calculator cannot calculate the bonuses.

  2. The 2 classes are not very different in behavior as well.

  3. The parent class (correctly an abstract class) is created prematurely whilst it ought to be extracted from an existing class

Finally, OCP is a half-baked principle as currently described by Uncle Robert Martin.

See:
a) x.com/isocroft/status/187826697311...
b) codeofrob.com/entries/my-relations...
c) codeblog.jonskeet.uk/2013/03/15/th...

Billboard image

The Next Generation Developer Platform

Coherence is the first Platform-as-a-Service you can control. Unlike "black-box" platforms that are opinionated about the infra you can deploy, Coherence is powered by CNC, the open-source IaC framework, which offers limitless customization.

Learn more

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay