# SOLID Principles — Overview

The SOLID principles are five design guidelines that make object-oriented software easier to understand, maintain, and extend. They were promoted by Robert C. Martin (Uncle Bob) and have become foundational to professional software engineering.

## Quick-Reference Table

| Principle | Abbr. | One-Liner | Key Question |
|---|---|---|---|
| **Single Responsibility** | SRP | A class should have only one reason to change. | "Does this class do more than one job?" |
| **Open/Closed** | OCP | Open for extension, closed for modification. | "Can I add behavior without editing existing code?" |
| **Liskov Substitution** | LSP | Subtypes must be substitutable for their base types. | "Can I swap in a subclass without breaking anything?" |
| **Interface Segregation** | ISP | No client should depend on methods it does not use. | "Is any implementer forced to stub out unused methods?" |
| **Dependency Inversion** | DIP | Depend on abstractions, not concretions. | "Does my high-level logic import low-level details?" |

## Decision Tree

Use the following decision tree when reviewing or designing code:

```
START: You are looking at a class / module / struct
│
├─ Does it have more than one reason to change?
│   YES → Apply SRP. Split into focused units.
│   NO  ↓
│
├─ To add a new variant / behavior, must you edit existing code?
│   YES → Apply OCP. Introduce polymorphism or strategy.
│   NO  ↓
│
├─ Can every subtype replace its parent without breaking callers?
│   NO  → Apply LSP. Fix the inheritance hierarchy or use composition.
│   YES ↓
│
├─ Are implementers forced to depend on methods they don't use?
│   YES → Apply ISP. Break the interface into smaller, focused ones.
│   NO  ↓
│
├─ Do high-level modules import / instantiate low-level concretions?
│   YES → Apply DIP. Introduce an abstraction and inject dependencies.
│   NO  ↓
│
└─ Design looks solid. Review for other concerns (DRY, KISS, etc.)
```

## How the Principles Relate

```
SRP ──► keeps units small and focused
         │
OCP ──► lets you extend those units safely
         │
LSP ──► guarantees substitutability in those extensions
         │
ISP ──► prevents bloated contracts between units
         │
DIP ──► decouples the wiring so everything stays flexible
```

- **SRP + ISP** often work together: splitting a fat class (SRP) usually means splitting its interface too (ISP).
- **OCP + DIP** are natural partners: depending on abstractions (DIP) is *how* you achieve extension without modification (OCP).
- **LSP** is the safety net: it ensures that the polymorphism you rely on for OCP actually works correctly.

## When to Apply SOLID

**Apply aggressively when:**
- The codebase is long-lived and maintained by a team
- Requirements change frequently
- You are building libraries or frameworks consumed by others
- Testability is a priority

**Apply with restraint when:**
- Writing a one-off script or prototype
- The domain is tiny and unlikely to change
- Over-abstraction would add complexity without benefit
- You are in the earliest exploratory phase of a project

## Files in This Directory

| File | Principle |
|---|---|
| [single-responsibility.md](single-responsibility.md) | Single Responsibility Principle |
| [open-closed.md](open-closed.md) | Open/Closed Principle |
| [liskov-substitution.md](liskov-substitution.md) | Liskov Substitution Principle |
| [interface-segregation.md](interface-segregation.md) | Interface Segregation Principle |
| [dependency-inversion.md](dependency-inversion.md) | Dependency Inversion Principle |
