solid-principles

star 0

Five principles for maintainable object-oriented design

daniel-heydari-dev By daniel-heydari-dev schedule Updated 2/14/2026

name: SOLID Principles description: Five principles for maintainable object-oriented design

Skill: SOLID Principles

Design software that is easy to maintain, extend, and understand.

Single Responsibility Principle (SRP)

A class/module should have only one reason to change.

Rules

  • ✅ DO: Keep classes focused on one responsibility
  • ✅ DO: If describing a class requires "and", it does too much
  • ✅ DO: Extract separate concerns into separate modules
  • ❌ DON'T: Create god classes that do everything

Examples

// ❌ Bad - multiple responsibilities
class UserManager {
  createUser(data: UserData) {
    /* ... */
  }
  validateEmail(email: string) {
    /* ... */
  }
  sendWelcomeEmail(user: User) {
    /* ... */
  }
  generateReport(users: User[]) {
    /* ... */
  }
  exportToCSV(users: User[]) {
    /* ... */
  }
}

// ✅ Good - separated responsibilities
class UserService {
  createUser(data: UserData) {
    /* ... */
  }
}

class EmailValidator {
  validate(email: string) {
    /* ... */
  }
}

class EmailService {
  sendWelcome(user: User) {
    /* ... */
  }
}

class UserReportGenerator {
  generate(users: User[]) {
    /* ... */
  }
  exportToCSV(users: User[]) {
    /* ... */
  }
}

Open/Closed Principle (OCP)

Open for extension, closed for modification.

Rules

  • ✅ DO: Use abstractions to allow extension
  • ✅ DO: Use strategy pattern, plugins, or dependency injection
  • ✅ DO: Add new behavior by adding code, not changing existing
  • ❌ DON'T: Modify existing code to add new features

Examples

// ❌ Bad - must modify to add new payment types
class PaymentProcessor {
  process(payment: Payment) {
    if (payment.type === "credit") {
      // process credit
    } else if (payment.type === "debit") {
      // process debit
    } else if (payment.type === "crypto") {
      // had to modify existing code!
    }
  }
}

// ✅ Good - extend without modifying
interface PaymentStrategy {
  process(payment: Payment): Promise<Result>;
}

class CreditPayment implements PaymentStrategy {
  process(payment: Payment) {
    /* ... */
  }
}

class CryptoPayment implements PaymentStrategy {
  process(payment: Payment) {
    /* ... */
  }
}

class PaymentProcessor {
  constructor(private strategies: Map<string, PaymentStrategy>) {}

  process(payment: Payment) {
    const strategy = this.strategies.get(payment.type);
    return strategy.process(payment);
  }
}

Liskov Substitution Principle (LSP)

Subtypes must be substitutable for their base types.

Rules

  • ✅ DO: Ensure derived classes can replace base classes
  • ✅ DO: Maintain expected behavior in subclasses
  • ✅ DO: Favor composition over inheritance when LSP is hard
  • ❌ DON'T: Override methods to throw "not implemented"
  • ❌ DON'T: Violate parent class contracts

Examples

// ❌ Bad - violates LSP
class Rectangle {
  constructor(
    public width: number,
    public height: number,
  ) {}

  setWidth(w: number) {
    this.width = w;
  }
  setHeight(h: number) {
    this.height = h;
  }
  getArea() {
    return this.width * this.height;
  }
}

class Square extends Rectangle {
  setWidth(w: number) {
    this.width = w;
    this.height = w; // Unexpected side effect!
  }
}

// ✅ Good - use composition or separate types
interface Shape {
  getArea(): number;
}

class Rectangle implements Shape {
  constructor(
    public width: number,
    public height: number,
  ) {}
  getArea() {
    return this.width * this.height;
  }
}

class Square implements Shape {
  constructor(public side: number) {}
  getArea() {
    return this.side * this.side;
  }
}

Interface Segregation Principle (ISP)

Many specific interfaces are better than one general interface.

Rules

  • ✅ DO: Create focused, specific interfaces
  • ✅ DO: Split large interfaces into smaller ones
  • ✅ DO: Clients should only depend on methods they use
  • ❌ DON'T: Force implementations to have unused methods

Examples

// ❌ Bad - fat interface
interface Worker {
  work(): void;
  eat(): void;
  sleep(): void;
  attendMeeting(): void;
}

// Robot can't eat or sleep!
class Robot implements Worker {
  work() {
    /* ... */
  }
  eat() {
    throw new Error("Not implemented");
  }
  sleep() {
    throw new Error("Not implemented");
  }
  attendMeeting() {
    throw new Error("Not implemented");
  }
}

// ✅ Good - segregated interfaces
interface Workable {
  work(): void;
}

interface Feedable {
  eat(): void;
}

interface Sleepable {
  sleep(): void;
}

class Human implements Workable, Feedable, Sleepable {
  work() {
    /* ... */
  }
  eat() {
    /* ... */
  }
  sleep() {
    /* ... */
  }
}

class Robot implements Workable {
  work() {
    /* ... */
  }
}

Dependency Inversion Principle (DIP)

Depend on abstractions, not concretions.

Rules

  • ✅ DO: High-level modules should not depend on low-level modules
  • ✅ DO: Both should depend on abstractions
  • ✅ DO: Inject dependencies instead of creating them
  • ❌ DON'T: Instantiate dependencies directly inside classes

Examples

// ❌ Bad - depends on concretion
class UserService {
  private database = new MySQLDatabase(); // Hard dependency

  getUser(id: string) {
    return this.database.query(`SELECT * FROM users WHERE id = ${id}`);
  }
}

// ✅ Good - depends on abstraction
interface Database {
  query<T>(sql: string): Promise<T>;
}

class UserService {
  constructor(private database: Database) {} // Injected

  getUser(id: string) {
    return this.database.query(`SELECT * FROM users WHERE id = ?`, [id]);
  }
}

// Easy to test with mock, easy to swap implementations
const userService = new UserService(new MySQLDatabase());
const testService = new UserService(new MockDatabase());

Summary

Principle Remember
SRP One reason to change
OCP Extend, don't modify
LSP Subtypes are substitutable
ISP Small, focused interfaces
DIP Depend on abstractions
Install via CLI
npx skills add https://github.com/daniel-heydari-dev/personal-ai-skills --skill solid-principles
Repository Details
star Stars 0
call_split Forks 0
navigation Branch main
article Path SKILL.md
More from Creator
daniel-heydari-dev
daniel-heydari-dev Explore all skills →