SOLID Design Principle
Quick reference for the SOLID principles, five foundation stones of maintainable, extensible object-oriented design:
1. Single Responsibility Principle (SRP)
# ❌ Bad: this class both reads config and writes logs
class AppManager:
def load_config(...): …
def write_log(...): …
# ✅ Good: split into two focused classes
class ConfigLoader:
def load(...): …
class Logger:
def log(...): …
2. Open/Closed Principle (OCP)
# ❌ Bad: adding a new shape requires modifying switch
def area(shape):
if shape.type == 'circle': …
elif shape.type == 'square': …
# ✅ Good: use polymorphism
class Shape:
def area(self): pass
class Circle(Shape):
def area(self): …
class Square(Shape):
def area(self): …
def total_area(shapes: List[Shape]):
return sum(s.area() for s in shapes)
3. Liskov Substitution Principle (LSP)
class Bird:
def fly(self): …
class Sparrow(Bird): …
class Penguin(Bird):
def fly(self):
raise Exception("I can't!") # ❌ Violates LSP
# If you need non-flying birds,
# introduce a separate interface (e.g. Swimmable).
4. Interface Segregation Principle (ISP)
# ❌ Fat interface
class Worker:
def code(): …
def test(): …
def deploy(): …
# ✅ Segregated
class Coder:
def code(): …
class Tester:
def test(): …
class Deployer:
def deploy(): …
5. Dependency Inversion Principle (DIP)
# ❌ High-level code instantiates low-level class directly
class UserService:
def __init__(self):
self.repo = SqlUserRepository()
# ✅ Depend on an abstraction
class UserRepository(Protocol):
def get_user(id): …
class SqlUserRepository(UserRepository): …
class InMemoryUserRepository(UserRepository): …
class UserService:
def __init__(self, repo: UserRepository):
self.repo = repo
By applying SRP, OCP, LSP, ISP, and DIP, your code remains modular, testable, and resilient to change, allowing you to evolve features without fear of unintended side effects.