Why SOLID Principles
Writing code not only involves proper syntax, reaching customer requirements, applying large algorithms but also includes maintaining the code for long run, writing code understandable, structuring the code.
The SOLID principles are a set of five design principles in object-oriented programming (OOP). They’re meant to make software:
Easier to understand
More flexible
Less error-prone when changing or extending
Software systems or application grow over time — new features, bug fixes, changing business needs. Without discipline, the codebase turns into spaghetti code.
Hard to understand
Risky to change
Expensive to maintain
The SOLID principles is a guideline to write code that is:
Maintainability
Code written with SOLID is easier to maintain because responsibilities are clear and separated.
class Notification: def send(self, message, type): if type == "email": print(f"Sending Email: {message}") elif type == "sms": print(f"Sending SMS: {message}")For example, imagine you write one class that sends all kinds of notifications
Say need to add “Add WhatsApp notifications”, you must open this class and change it.
Risk: You might break Email or SMS code while adding WhatsApp.
Testing becomes harder because everything is mixed together.
Reusability
Write code once and reuse it everywhere without rewriting the same logic again and again. This makes software faster to build, easier to maintain, and less error prone.
# ❌ Bad: Duplicated logic
class Rectangle:
def area(self, width, height):
return width * height
class Square:
def area(self, side):
return side * side
Problem:
Every shape writes its own
area()method differently.If you add a
Circle, you must repeat code again.No shared structure → harder to maintain.
Smaller, well-defined classes/methods are easier to reuse across projects.
Scalability
System/application requirements keep on growing on one feature. To handle growth safely, we need a design that allows
Adding new feature easily
Keeping existing classes untouched
Testing each part separately
When requirements change you can extend existing code instead of rewriting it.
elif type == "whatsapp":
print(f"WhatsApp: {message}")
Considering the same example given to maintainability, if the business wants ‘WhatsApp notifications’, and again for Slack, Telegram, Teams… → this class keeps growing
Each time you edit this class, there’s a chance of breaking existing email/SMS logic.
Bugs creep in when requirements grow.
You can’t test email separately from SMS — everything is mixed inside one method.
The more types you add, the harder testing becomes.
The service is directly tied to all notification types.
You can’t reuse “just email” or “just SMS” in another project without copying everything.
Flexibility & Adaptability
In real projects, requirements always change (new features, new APIs, new rules). If your code is rigid, every small change means breaking things.
class ReportGenerator:
def generate(self, data, format):
if format == "pdf":
print("Generating PDF Report...")
elif format == "excel":
print("Generating Excel Report...")
elif format == "html":
print("Generating HTML Report...")
Why is this not flexible?
Every time a new format (e.g., CSV, JSON) is needed → you must edit this class.
Old code keeps changing → risk of breaking existing functionality.
Hard to adapt → you can’t reuse just “PDF report” somewhere else.
Reduced Complexity
Complexity = when code is hard to read, understand, and reason about.
Reduced complexity = breaking problems into smaller, understandable pieces.
class Order:
def __init__(self, items):
self.items = items
def process_order(self):
# calculate total
total = 0
for item in self.items:
total += item["price"] * item["qty"]
# apply discount
if total > 500:
total *= 0.9
# save to database
print("Saving order to database...")
# send confirmation email
print("Sending confirmation email...")
Why is this complex?
Too many responsibilities (calculation, discount, DB, email).
Hard to read — must scroll through everything.
Hard to maintain — changing discount logic risks breaking email sending.
Hard to test — can’t test discount separately.