## The Problem with How SOLID Is Usually Taught

Most articles explain SOLID with shapes — circles, rectangles, and flying penguins. Useful for understanding the concept, useless for applying it to real work. Here's SOLID as I actually use it.

## S — Single Responsibility Principle

**One class, one reason to change.**

Early in my career, I wrote services like this:

```csharp
public class UserService
{
    public User GetUser(int id) { }
    public void SaveUser(User user) { }
    public void SendWelcomeEmail(User user) { } // wrong
    public string GenerateUserReport() { }      // wrong
    public void LogUserActivity(string action) { } // wrong
}
```

This class has five reasons to change. Email logic changes? Modify UserService. Report format changes? Modify UserService. This creates fragile code.

**Better:**
```csharp
public class UserRepository { /* data access only */ }
public class EmailService { /* email only */ }
public class ReportService { /* reports only */ }
public class ActivityLogger { /* logging only */ }
```

## O — Open/Closed Principle

**Open for extension, closed for modification.**

When building the package management system at Traviyo, I needed to support multiple discount types. The wrong approach:

```csharp
public decimal CalculateDiscount(string type, decimal price)
{
    if (type == "seasonal") return price * 0.1m;
    if (type == "agent") return price * 0.15m;
    // Adding new type = modifying this method
}
```

**The right approach:**
```csharp
public interface IDiscountStrategy
{
    decimal Calculate(decimal price);
}

public class SeasonalDiscount : IDiscountStrategy
{
    public decimal Calculate(decimal price) => price * 0.1m;
}

public class AgentDiscount : IDiscountStrategy
{
    public decimal Calculate(decimal price) => price * 0.15m;
}

// New discount type? Add a new class. Don't touch existing code.
```

## L — Liskov Substitution Principle

**Child classes must be usable wherever the parent class is expected.**

The classic violation — overriding a method and throwing NotImplementedException. If your subclass can't fully honor the parent's contract, your inheritance hierarchy is wrong.

## I — Interface Segregation Principle

**Don't force classes to implement methods they don't need.**

```csharp
// Bad — one fat interface
public interface IRepository<T>
{
    T GetById(int id);
    IEnumerable<T> GetAll();
    void Add(T entity);
    void Update(T entity);
    void Delete(int id);
    IEnumerable<T> Search(string query); // not all repos need this
    byte[] ExportToCsv(); // definitely not all repos need this
}

// Better — focused interfaces
public interface IReadRepository<T> { T GetById(int id); IEnumerable<T> GetAll(); }
public interface IWriteRepository<T> { void Add(T entity); void Update(T entity); void Delete(int id); }
public interface ISearchable<T> { IEnumerable<T> Search(string query); }
```

## D — Dependency Inversion Principle

**Depend on abstractions, not concretions.**

This is the one that unlocks everything else. In my portfolio project:

```csharp
// All services depend on interfaces, not implementations
public class ExperienceController : Controller
{
    private readonly IExperienceRepository _repo;
    
    public ExperienceController(IExperienceRepository repo)
    {
        _repo = repo;
    }
}

// Registered in Program.cs
builder.Services.AddScoped<IExperienceRepository, ExperienceRepository>();
```

Now I can swap implementations without touching the controller.

## The Real Benefit

After applying SOLID consistently across my projects, I noticed:
- Adding features stopped breaking existing code
- Unit testing became actually possible
- Onboarding new developers to the codebase was faster
- Bug fixes were isolated and predictable

## Conclusion

SOLID isn't about following rules — it's about building systems that survive contact with changing requirements. Start with Single Responsibility and Dependency Inversion. The rest will follow naturally.