# SOLID Principles — Writing Code That Survives Change

SOLID is five principles for object-oriented design that make software more maintainable and extensible.

```mermaid
mindmap
  root((SOLID))
    S
      Single Responsibility
    O
      Open/Closed
    L
      Liskov Substitution
    I
      Interface Segregation
    D
      Dependency Inversion
```

## S — Single Responsibility Principle (SRP)

**A class should have only one reason to change.**

Each module should own one axis of change. Mixing concerns (e.g., validation + persistence + formatting) means any change to one affects the others.

**Before:**
```typescript
class UserService {
  validate(user: User) { /* ... */ }
  save(user: User) { /* ... */ }
  sendWelcomeEmail(user: User) { /* ... */ }
}
```

**After:**
```typescript
class UserValidator { validate(user: User) { /* ... */ } }
class UserRepository { save(user: User) { /* ... */ } }
class EmailNotifier { sendWelcome(user: User) { /* ... */ } }
```

## O — Open/Closed Principle (OCP)

**Software should be open for extension, closed for modification.**

Add behavior via new code (inheritance, composition, plugins), not by editing existing code.

**Before:** Adding a new shape requires editing a central function.
```typescript
function area(shape: any) {
  if (shape.type === 'circle') return Math.PI * shape.r ** 2;
  if (shape.type === 'rect') return shape.w * shape.h;
  // Must edit here for each new shape
}
```

**After:** Each shape extends behavior without changing others.
```typescript
interface Shape { area(): number; }
class Circle implements Shape { area() { return Math.PI * this.r ** 2; } }
class Rect implements Shape { area() { return this.w * this.h; } }
```

## L — Liskov Substitution Principle (LSP)

**Subtypes must be substitutable for their base types.**

If `B` extends `A`, any code that expects `A` should work with `B` without surprises. Don't weaken preconditions or strengthen postconditions.

**Violation:**
```typescript
class Rectangle { setWidth(w: number) { this.w = w; } setHeight(h: number) { this.h = h; } }
class Square extends Rectangle {
  setWidth(w: number) { this.w = this.h = w; }  // Surprise: changes both!
  setHeight(h: number) { this.w = this.h = h; }
}
// Code expecting Rectangle gets unexpected behavior
```

**Better:** Don't make Square extend Rectangle if it can't honor the contract.

## I — Interface Segregation Principle (ISP)

**Clients should not depend on interfaces they don't use.**

Prefer small, focused interfaces over large "god" interfaces. Fat interfaces force implementers to add no-op methods.

**Before:**
```typescript
interface Worker {
  work(): void;
  eat(): void;
  sleep(): void;
}
class Robot implements Worker {
  work() { /* ... */ }
  eat() { /* no-op */ }   // Robot doesn't eat
  sleep() { /* no-op */ } // Robot doesn't sleep
}
```

**After:**
```typescript
interface Workable { work(): void; }
interface Eatable { eat(): void; }
class Robot implements Workable { work() { /* ... */ } }
class Human implements Workable, Eatable { work() { /* ... */ } eat() { /* ... */ } }
```

## D — Dependency Inversion Principle (DIP)

**Depend on abstractions, not concretions.**

High-level modules should not depend on low-level modules. Both should depend on abstractions (interfaces).

```mermaid
flowchart TB
    subgraph Bad
        A1[OrderService] -->|depends on| B1[MySqlDatabase]
    end
    subgraph Good
        A2[OrderService] -->|depends on| I[Database Interface]
        B2[MySqlDatabase] -->|implements| I
        B3[PostgresDatabase] -->|implements| I
    end
```

**Before:** OrderService directly uses MySqlDatabase.
```typescript
class OrderService {
  private db = new MySqlDatabase();
  save(order: Order) { this.db.insert('orders', order); }
}
```

**After:** Both depend on an abstraction.
```typescript
interface Database { insert(table: string, data: object): void; }
class OrderService {
  constructor(private db: Database) {}
  save(order: Order) { this.db.insert('orders', order); }
}
// Inject MySqlDatabase or PostgresDatabase at runtime
```

## Summary

| Principle | One-Liner |
|-----------|-----------|
| SRP | One reason to change |
| OCP | Extend, don't modify |
| LSP | Subtypes replace base types |
| ISP | Small interfaces |
| DIP | Depend on abstractions |
