Lesson 4 of 6 · 12 min · 1 hands-on step

SOLID Principles in Plain English

Five design rules that keep code easy to change, with a hands-on refactor.

SOLID, one sentence each

Letter Principle Plain English
S Single responsibility Each function or class does one job
O Open/closed Add new behavior by adding code, not editing working code
L Liskov substitution A child class should work anywhere its parent does
I Interface segregation Don't force things to depend on methods they don't use
D Dependency inversion Depend on what something does, not which specific thing it is

S: one job each

JavaScript · try it
// ❌ Calculates, formats AND emails. Three reasons to change.
function processOrder(order) { /* ... */ }

// ✅ Each piece can change, and be tested, on its own
const subtotal = (items) => items.reduce((s, i) => s + i.price * i.qty, 0);
const formatReceipt = (total) => `Total: $${total.toFixed(2)}`;

console.log(formatReceipt(subtotal([{ price: 9.99, qty: 2 }, { price: 5, qty: 1 }])));

O: extend without editing

A long if/else chain on a "type" is a warning sign. Every new type means editing (and possibly breaking) it. A lookup table of strategies lets you add without touching what works:

JavaScript · try it
const discounts = {
  none: (total) => total,
  student: (total) => total * 0.8,
  blackFriday: (total) => total * 0.5,
};

const checkout = (total, type) => discounts[type](total);
console.log(checkout(100, "student"));

D: depend on "what", not "which"

JavaScript · try it
// The report doesn't care HOW we notify. Email, SMS, Slack… pass any notifier in.
function sendReport(report, notify) {
  notify(`Daily report: ${report}`);
}

sendReport("42 new users", (msg) => console.log("[email]", msg));
sendReport("42 new users", (msg) => console.log("[sms]", msg));

Passing dependencies in (instead of hard-coding them) is also what makes code testable: in tests you pass a fake notifier.

Don't memorize SOLID like a poem. Notice the pain each rule prevents: code that's scary to change.

🧪 Practice

Every new shipping method means editing this if chain, which risks breaking the others. Refactor shippingCost to look up a strategy object instead:

  • keep the exact same results for standard (5), express (15) and free (0)
  • add a new method overnight costing 25 without writing a new if
  • unknown methods should throw an Error
JavaScript
function shippingCost(method) {
  if (method === "standard") return 5;
  else if (method === "express") return 15;
  else if (method === "free") return 0;
  else throw new Error("Unknown shipping method");
}

Output appears here. Press Run or Ctrl/⌘ + Enter.

✅ Check your understanding

  1. What does the Single Responsibility Principle say?

Create a free account to track your progress.