Skip to content

ivan-escribano/solid-101

Repository files navigation

What Are the SOLID Principles?

  • 5 design principles specifically aimed at Object-Oriented Programming (OOP).
  • Software always changes: new features, bug fixes, refactors... It's in its nature.
  • These principles guide us to adapt to those changes without ending up with unmaintainable, chaotic code.

SOLID Overview

Imagine you're building a house:

  • With LEGO (SOLID code) - You place piece by piece. If something doesn't fit, you remove it and swap it without touching the rest. You can expand, reorganize, and improve on top of what you already have.
  • With stone and cement (non-SOLID code) - Everything is glued together. If you make a mistake on one wall, you have to tear the whole thing down. Changing something small can mean demolishing half the building.

SOLID Analogy


S - Single Responsibility Principle

  • A class should have one responsibility and one reason to change.
  • If you need to describe your class as "it does this AND this AND this"... it's already wrong. A User class shouldn't handle payments, send emails, and validate data.
  • Separate by actors: if the PM needs something, it goes in one class. If Marketing needs something else, it goes in another. Each actor, each responsibility.

SRP Diagram

Analogy - The restaurant:

Imagine a restaurant where the waiter does everything: greets customers, takes orders, cooks, serves food, and handles the bill. Total chaos, nothing is efficient.

That's why in a real restaurant each person has a clear role: the chef cooks, the waiter takes orders, the host greets customers. If the chef gets sick, you hire another chef without touching the waiter. That's Single Responsibility.

SRP Analogy


O - Open/Closed Principle

3 key points:

  • A class should be open for extension but closed for modification. If it already works, don't touch it to add more stuff: more code, more mess, more chance of breaking it.
  • Use the Strategy Pattern: create an interface, implement each strategy in its own class, and inject it via the constructor. This way you extend without modifying.
  • Red flag: if you have a switch or if/else that grows every time you add something new, you need to apply OCP.

OCP Diagram

Analogy - Pizza and toppings:

The pizza base is already made and works. Want pepperoni? Put it on top. Mushrooms? On top. You never tear apart the dough to stuff ingredients inside. The base is closed (you don't touch it), but you can extend it with as many toppings as you want.

Without OCP: you destroy the entire dough every time the customer asks for a new ingredient.

OCP Analogy


L - Liskov Substitution Principle

3 key points:

  • A child class that inherits from a parent must be able to replace it without causing failures. If it inherits, it's supposed to maintain the same properties and behaviors.
  • When inheritance doesn't fit, use composition. Ask yourself: "Does this have an X?" instead of "Is this an X?". Classes are built from properties and behaviors, not just hierarchies.
  • Red flag: if a child class returns null or throws an Error because it can't fulfill the parent's behavior, the inheritance design is wrong.

LSP Diagram

Analogy - The restaurant:

You have a base class Employee with a function serveCustomer(). The Waiter serves customers, the Host does too. Both can replace Employee without issues.

But the Chef doesn't serve customers. If you force him to inherit serveCustomer(), he'll end up with a throw Error("I cook, I don't serve"). That breaks Liskov. The solution: don't force that inheritance, create a different structure for Chef.

LSP Analogy


I - Interface Segregation Principle

3 key points:

  • Don't force classes to implement methods they don't use. Focus them on what they can do, not what they are.
  • Small, focused interfaces are always better than one giant interface with too many responsibilities.
  • Red flag: if a method returns 0, null, undefined, or throws an error because it doesn't apply, the interface is doing too much.

ISP Diagram

Analogy - The remote control:

You buy a universal remote with 100 buttons. You only use 5 for your TV. The rest get in the way, confuse you, and serve no purpose. A remote with just the 5 buttons you need would be much better: power on, power off, volume up, volume down, and change channel. Small, focused, and no junk.

ISP Analogy

LSP vs ISP - The difference

LSP vs ISP Comparison

  • LSP - You implement something you can't do. It's dangerous: it can break in production with throw Error or unexpected behavior.
  • ISP - You implement something you don't need. It doesn't break, but it's noise: methods returning null or 0 for no reason.

In one sentence:

  • LSP - Split so nobody can lie (promise something they can't deliver).
  • ISP - Split so nobody implements junk (carry useless baggage).

Fix for both: smaller, more focused interfaces and classes.


D - Dependency Inversion Principle

3 key points:

  • A class's business logic cannot depend on concrete details like MySQL, Redis, or Postgres directly inside it.
  • Injection: pass dependencies through the constructor. The class doesn't create anything internally, it receives everything from outside. This way, if you switch from Postgres to MySQL or want to test with a FakeDB, you don't touch the class.
  • Inversion: in the constructor, don't use concrete classes, use interfaces. Instead of receiving MongoDB or Redis, receive a DBInterface that any of them can implement.

DIP Diagram

Analogy - The online store:

Your CheckoutService only knows it has a PaymentProcessor. It doesn't care how payment works internally. Want to switch from Stripe to PayPal? Swap the implementation, the checkout doesn't notice. Want to test? Inject a FakeProcessor. Everything works because the logic depends on the abstraction, not the detail.

DIP Analogy


Project Structure

solid/
├── README.md                        ← You are here
│
├── docs/
│   ├── solid-simple.md              Quick SOLID overview (concise)
│   ├── solid-detailed.md            Full practical guide with examples
│   └── mistakes.md                  Common mistakes by round
│
├── images/
│   ├── diagrams/                    Technical diagrams (class/interface relationships)
│   └── analogies/                   Visual metaphors for each principle
│
├── phase-1-refactor-dojo/
│   ├── README.md                    Full guide: 6 rounds + solutions explained
│   ├── round-1-correction.md        Detailed correction for round 1
│   ├── exercises/                   Bad code - the problem to refactor
│   │   ├── exercise-1.ts            Round 1: SRP - The God Method
│   │   ├── exercise-2.ts            Round 2: OCP - The Growing Switch
│   │   ├── exercise-3.ts            Round 3: LSP - The Sneaky Override
│   │   ├── exercise-4.ts            Round 4: ISP - The Swiss Army Interface
│   │   ├── exercise-5.ts            Round 5: DIP - The Concrete Trap
│   │   └── exercise-6.ts            Round 6: MIX - The Real-World Mess
│   └── solutions/                   Refactored code - the correct solution
│       ├── exercise-1.ts
│       ├── exercise-2.ts
│       ├── exercise-3.ts
│       ├── exercise-4.ts
│       ├── exercise-5.ts
│       └── exercise-6.ts
│
├── phase-2-code-review/
│   ├── README.md                    Full guide: 3 PRs + solutions explained
│   ├── exercises/                   Bad code - the PR to review
│   │   ├── exercise-1.ts            PR #1: Notification Manager
│   │   ├── exercise-2.ts            PR #2: Discount Engine
│   │   └── exercise-3.ts            PR #3: User Roles & Permissions
│   └── solutions/                   Refactored code - the correct solution
│       ├── exercise-1.ts
│       ├── exercise-2.ts
│       └── exercise-3.ts
│
├── package.json
└── tsconfig.json

How to use

# Run any exercise
npx tsx phase-1-refactor-dojo/exercises/exercise-1.ts

# Compare with the solution
npx tsx phase-1-refactor-dojo/solutions/exercise-1.ts

# Same for phase 2
npx tsx phase-2-code-review/exercises/exercise-1.ts
npx tsx phase-2-code-review/solutions/exercise-1.ts

About

An open source guide to learn SOLID in a more accessible, simple, and engaging way, using examples, diagrams, and exercises that simulate real day to day work scenarios.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors