🔧 Day 3: SOLID Principles in .NET Web Apps – Explained with Real Code

🔧 Day 3: SOLID Principles in .NET Web Apps – Explained with Real Code
"Bad code works. But good code works for years."

In today's post, we're diving into the SOLID principles — 5 key design rules that help us build maintainable and scalable software.

These principles fit perfectly within Clean Architecture and act like the backbone of writing high-quality .NET code.


💡 What is SOLID?

SOLID is an acronym for:

Principle Meaning
S Single Responsibility Principle
O Open/Closed Principle
L Liskov Substitution Principle
I Interface Segregation Principle
D Dependency Inversion Principle

Let’s break them down with simple real-world .NET examples 👇


🧱 1. Single Responsibility Principle (SRP)

A class should have only one reason to change.

Bad Example:

public class InvoiceService
{
    public void GenerateInvoice() { /* logic */ }
    public void SaveToDatabase() { /* logic */ }
    public void SendEmail() { /* logic */ }
}

Why bad?
One class is handling too many things – business logic, persistence, and notifications.

Refactored (Good Example):

public class InvoiceGenerator { public void Generate() { } }
public class InvoiceRepository { public void Save() { } }
public class EmailSender { public void Send() { } }

Now each class has one responsibility


🔓 2. Open/Closed Principle (OCP)

Software should be open for extension but closed for modification.

Bad Example:

public class NotificationService
{
    public void Notify(string type)
    {
        if (type == "Email") { /* send email */ }
        else if (type == "SMS") { /* send sms */ }
    }
}

Good Example (With Interfaces):

public interface INotifier { void Notify(); }

public class EmailNotifier : INotifier
{
    public void Notify() { /* Email logic */ }
}

public class SMSNotifier : INotifier
{
    public void Notify() { /* SMS logic */ }
}

public class NotificationService
{
    private readonly INotifier _notifier;
    public NotificationService(INotifier notifier) { _notifier = notifier; }
    public void Send() => _notifier.Notify();
}

Now you can add more notification types without modifying the service 👌


🧬 3. Liskov Substitution Principle (LSP)

Derived classes must be substitutable for their base class.

Bad Example:

public class Bird { public virtual void Fly() { } }
public class Ostrich : Bird { public override void Fly() { throw new Exception("Can't fly"); } }

Better:

public interface IBird { }

public interface IFlyingBird : IBird
{
    void Fly();
}

public class Sparrow : IFlyingBird
{
    public void Fly() { }
}

public class Ostrich : IBird
{
    // No Fly method needed
}

Don’t force a child class to implement behavior it doesn’t support 🚫


🪝 4. Interface Segregation Principle (ISP)

Keep interfaces small and focused.

Bad Example:

public interface IWorker
{
    void Work();
    void Eat();
}

Better:

public interface IWorkable { void Work(); }
public interface IFeedable { void Eat(); }

public class Robot : IWorkable { public void Work() { } }
public class Human : IWorkable, IFeedable
{
    public void Work() { }
    public void Eat() { }
}

Clients should not be forced to depend on interfaces they don’t use 💡


🧩 5. Dependency Inversion Principle (DIP)

Depend on abstractions, not concretions.

Bad Example:

public class OrderService
{
    private readonly SqlOrderRepository _repository;
    public OrderService() { _repository = new SqlOrderRepository(); }
}

Good Example:

public interface IOrderRepository { void Save(); }

public class SqlOrderRepository : IOrderRepository
{
    public void Save() { }
}

public class OrderService
{
    private readonly IOrderRepository _repository;
    public OrderService(IOrderRepository repository)
    {
        _repository = repository;
    }
}

Now you can easily swap out the implementation (e.g., for testing or new DB) 🧪


🚀 Final Thoughts

By applying SOLID principles, you build:

  • Flexible systems
  • Easily testable code
  • Maintainable architecture for the long run

They’re not just theory — they help your .NET apps survive years of changes with fewer bugs and better team collaboration.


✍️ End Note

Next up in , we’ll implement Deep Dive Into Layered Architecture , giving you a real project structure you can follow. Stay tuned!

Read more