SOLID Design Principles: Learn the Open-Closed Principle
Tags: solidprinciples, python, cleancode, programming
Published: 2023-11-19 14:13:25

👋 Hey there, fellow software enthusiasts! 
I'm Revisto, a passionate software engineer, and I want to dive into the exciting world of SOLID principles. 

**SOLID** is a set of rules and principles that can help us create maintainable, reusable, and flexible software designs. Essentially, it provides guidelines for building software that can help our projects grow easily.

So, what does SOLID stand for? Let's break it down:

- S: [Single Responsibility Principle](https://dev.to/revisto/solid-design-principles-learn-the-single-responsibility-principle-3cb1)
- **O: Open-Closed Principle**
- L: Liskov Substitution Principle
- I: Interface Segregation Principle
- D: Dependency Inversion Principle


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9f32dnl5irxax39nd7q3.png)



✨ One of the fundamental principles of SOLID is the Open-Closed Principle (OCP). It states that **a class, method, or function should be open for extension but closed for modification**. In other words, w**e should be able to easily extend the functionality of a software component without having to modify its existing code.**

So, what does it mean for a component to be open for extension? It means that we can add new features or behaviors to the component without modification. This can be achieved through techniques like **inheritance**, where we can create new classes or functions that build upon the existing ones.


By adhering to the Open-Closed Principle, we create software components that are **flexible and adaptable🤩**. When new requirements or features arise, we can simply extend the existing codebase rather than modify it. This reduces the risk of introducing bugs and makes our software more maintainable in the long run.

Let's take a look at a couple of examples to illustrate the Open-Closed Principle in action:

## 👨‍💻 Example: Inheritance

```python
def calculate(income, deduction, country):
    # tax_amount variable is defined
    # in each calculation
    tax_amount = int()
    taxable_income = income - deduction
    if country == "India":
        # calculation here
        pass
    elif country == "US":
        # calculation here
        pass
    elif country == "UK":
        # calculation here
        pass
    return tax_amount
```
❌ The `calculate` function doesn't adhere to the Open-Closed Principle. When we think about scaling and users from several countries start using the app, then there would be a problem.
When that happens, the TaxCalculator class needs to change to support the new countries and their rules. Thus, the current design violates OCP.

```python
from abc import ABC, abstractmethod

class CountryTaxCalculator(ABC):
    @abstractmethod
    def calculate_tax_amount(self):
        pass
    
class TaxCalculatorForUS(CountryTaxCalculator):
    def __init__(self, total_income, total_deduction):
        self.total_income = total_income
        self.total_deduction = total_deduction

    def calculate_tax_amount(self):
        taxable_income = self.total_income - self.total_deduction
        # calculation here 
        return taxable_income 


class TaxCalculatorForUK(CountryTaxCalculator):
    def __init__(self, total_income, total_deduction):
        self.total_income = total_income
        self.total_deduction = total_deduction

    def calculate_tax_amount(self):
        taxable_income = self.total_income - self.total_deduction
        # calculation here 
        return taxable_income
```

More examples at [my GitHub](https://github.com/Revisto/SOLID/tree/master/open-closed)


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9n7mu7r9rnlj7bho62md.png)


Adhering to the single responsibility principle is crucial. Make sure that each class or module has a clear and distinct responsibility. If a class becomes responsible for multiple tasks, it's a sign that it should be broken down into smaller, more focused units.

## Open-Closed Principle VS Single-Responsibility Principle

Here I quote from this [post](https://stackoverflow.com/questions/31018554/open-closed-vs-single-responsibility) from [sanderarts](https://stackoverflow.com/users/4989498/sanderarts):

> The Single Responsibility Principle deals with the fact that if a class has multiple responsibilities, these responsibilities will be tightly coupled if they're in a single class. So if an interface or algorithm changes for one responsibility it will likely also affect the other responsibility, an undesired effect.
> In the Open/Closed Principle a class should be able to extend its behavior without the need to modify the class itself. The only need to modify the class should be because it has a bug/error in it, not because you would like to change or add functionality.

By embracing the Open-Closed Principle, we create software that is more flexible, maintainable, and extensible. We can easily add new features without modifying existing code, promoting code reuse and reducing the risk of introducing bugs. So, let's strive to keep our software open for extension but closed for modification!

🚀 Stay tuned for more articles where we'll explore the other SOLID principles and delve into the exciting world of software engineering.

Thanks for reading. Feel free to comment your thoughts😊. Hope this post was helpful. You can hit me up on [Linked In](https://www.linkedin.com/in/revisto/) and [Github](https://www.github.com/revisto/).

Happy coding!