Understanding SOLID Principles
concepts

Understanding SOLID Principles

A practical guide to SOLID principles with real-world examples that will improve your object-oriented design skills.

Author

Md Mim Shifat

Full Stack Developer

2023-12-28 10 min read

Understanding SOLID Principles

SOLID is an acronym for five design principles that help developers write maintainable, scalable code.

S - Single Responsibility Principle

A class should have only one reason to change.

Python
# Bad
class User:
    def save_to_database(self):
        pass
    def send_email(self):
        pass
    def generate_report(self):
        pass

# Good
class User:
    pass

class UserRepository:
    def save(self, user):
        pass

class EmailService:
    def send(self, user, message):
        pass

O - Open/Closed Principle

Software entities should be open for extension but closed for modification.

Python
# Using abstraction
from abc import ABC, abstractmethod

class PaymentProcessor(ABC):
    @abstractmethod
    def process(self, amt):
        pass

class CreditCardProcessor(PaymentProcessor):
    def process(self, amt):
        print(f"Processing credit card")

class PayPalProcessor(PaymentProcessor):
    def process(self, amt):
        print(f"Processing PayPal")

L - Liskov Substitution Principle

Objects of a superclass should be replaceable with objects of its subclasses.

Python
class Bird:
    def fly(self):
        pass

# Violates LSP - Penguin can't fly
class Penguin(Bird):
    def fly(self):
        raise Exception("Can't fly!")

# Better design
class Bird:
    pass

class FlyingBird(Bird):
    def fly(self):
        pass

class Penguin(Bird):
    def swim(self):
        pass

I - Interface Segregation Principle

Clients should not be forced to depend on interfaces they don't use.

Python
# Bad - Fat interface
class Worker(ABC):
    @abstractmethod
    def work(self):
        pass
    @abstractmethod
    def eat(self):
        pass

# Good - Segregated interfaces
class Workable(ABC):
    @abstractmethod
    def work(self):
        pass

class Eatable(ABC):
    @abstractmethod
    def eat(self):
        pass

class Human(Workable, Eatable):
    def work(self):
        pass
    def eat(self):
        pass

class Robot(Workable):
    def work(self):
        pass

D - Dependency Inversion Principle

High-level modules should not depend on low-level modules. Both should depend on abstractions.

Python
# Bad
class MySQLDatabase:
    def connect(self):
        pass

class UserService:
    def __init__(self):
        self.db = MySQLDatabase()  # Tight coupling

# Good
class Database(ABC):
    @abstractmethod
    def connect(self):
        pass

class UserService:
    def __init__(self, db: Database):
        self.db = db  # Depends on abstraction

Conclusion

SOLID principles are guidelines that help you write better code. Apply them thoughtfully based on your specific context.

SOLID
OOP
Design Patterns
Clean Code