Skip to main content

Command Palette

Search for a command to run...

Why SOLID Principles

Published
•3 min read•View as Markdown

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?

  1. Every time a new format (e.g., CSV, JSON) is needed → you must edit this class.

  2. Old code keeps changing → risk of breaking existing functionality.

  3. 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.

SOLID Principles

Part 1 of 1

Writing code is not just about correct syntax, meeting requirements, or implementing complex algorithms. True software development goes beyond “making it work” — it’s about ensuring the code is maintainable, scalable, and understandable over time.