All skills
asyrafhussin avatar

/clean-code-principles

@680deef

SOLID principles, design patterns, DRY, KISS, and clean code fundamentals. Use when reviewing architecture, checking code quality, refactoring, or discussing design decisions. Triggers on "review architecture", "check code quality", "SOLID principles", "design patterns", or "clean code".

Use this Skill: https://skilld.dev/gh/asyrafhussin/agent-skills/clean-code-principles

This session only. Nothing lands on disk.

rulescore-composition.md

≈1.9k tokens on demand. Your agent reads this file only when SKILL.md points to it.

Composition Over Inheritance

Favor composing objects from smaller, focused pieces over building deep inheritance hierarchies. Composition provides more flexibility, better encapsulation, and avoids the fragile base class problem.

Bad Example

// Anti-pattern: Deep inheritance hierarchy

class Animal {
  protected name: string;
  protected energy: number = 100;

  constructor(name: string) {
    this.name = name;
  }

  eat(amount: number): void {
    this.energy += amount;
    console.log(`${this.name} is eating. Energy: ${this.energy}`);
  }

  sleep(hours: number): void {
    this.energy += hours * 10;
    console.log(`${this.name} slept for ${hours} hours. Energy: ${this.energy}`);
  }
}

class Bird extends Animal {
  fly(): void {
    this.energy -= 20;
    console.log(`${this.name} is flying. Energy: ${this.energy}`);
  }
}

class Duck extends Bird {
  swim(): void {
    this.energy -= 5;
    console.log(`${this.name} is swimming. Energy: ${this.energy}`);
  }

  quack(): void {
    console.log(`${this.name} says quack!`);
  }
}

class FlyingFish extends Animal {
  // Problem: Can't inherit from both Bird and Fish
  // Must duplicate flying code or create awkward hierarchy

  swim(): void {
    this.energy -= 5;
    console.log(`${this.name} is swimming. Energy: ${this.energy}`);
  }

  // Duplicated from Bird class!
  fly(): void {
    this.energy -= 20;
    console.log(`${this.name} is flying. Energy: ${this.energy}`);
  }
}

class Penguin extends Bird {
  // Problem: Penguins can't fly but inherit fly()
  // Must override to throw error - LSP violation

  fly(): void {
    throw new Error('Penguins cannot fly!');
  }

  swim(): void {
    this.energy -= 5;
    console.log(`${this.name} is swimming. Energy: ${this.energy}`);
  }
}

// More problems:
// - What about a robot bird? It doesn't eat or sleep.
// - What about a bat? It flies but isn't a bird.
// - Every change to Animal affects all subclasses.
// - Testing requires understanding entire hierarchy.

Good Example

// Correct approach: Composition with focused behaviors

// Define behaviors as interfaces
interface Eater {
  eat(amount: number): void;
}

interface Sleeper {
  sleep(hours: number): void;
}

interface Flyer {
  fly(): void;
}

interface Swimmer {
  swim(): void;
}

interface Speaker {
  speak(): void;
}

// Implement behaviors as standalone classes
class StandardEater implements Eater {
  constructor(private entity: { name: string; energy: number }) {}

  eat(amount: number): void {
    this.entity.energy += amount;
    console.log(`${this.entity.name} is eating. Energy: ${this.entity.energy}`);
  }
}

class StandardSleeper implements Sleeper {
  constructor(private entity: { name: string; energy: number }) {}

  sleep(hours: number): void {
    this.entity.energy += hours * 10;
    console.log(`${this.entity.name} slept for ${hours} hours. Energy: ${this.entity.energy}`);
  }
}

class WingedFlyer implements Flyer {
  constructor(
    private entity: { name: string; energy: number },
    private energyCost: number = 20
  ) {}

  fly(): void {
    this.entity.energy -= this.energyCost;
    console.log(`${this.entity.name} is flying. Energy: ${this.entity.energy}`);
  }
}

class AquaticSwimmer implements Swimmer {
  constructor(
    private entity: { name: string; energy: number },
    private energyCost: number = 5
  ) {}

  swim(): void {
    this.entity.energy -= this.energyCost;
    console.log(`${this.entity.name} is swimming. Energy: ${this.entity.energy}`);
  }
}

// Compose animals from behaviors
class Duck implements Eater, Sleeper, Flyer, Swimmer, Speaker {
  public name: string;
  public energy: number = 100;

  private eater: Eater;
  private sleeper: Sleeper;
  private flyer: Flyer;
  private swimmer: Swimmer;

  constructor(name: string) {
    this.name = name;
    this.eater = new StandardEater(this);
    this.sleeper = new StandardSleeper(this);
    this.flyer = new WingedFlyer(this);
    this.swimmer = new AquaticSwimmer(this);
  }

  eat(amount: number): void {
    this.eater.eat(amount);
  }

  sleep(hours: number): void {
    this.sleeper.sleep(hours);
  }

  fly(): void {
    this.flyer.fly();
  }

  swim(): void {
    this.swimmer.swim();
  }

  speak(): void {
    console.log(`${this.name} says quack!`);
  }
}

// Penguin: swims but doesn't fly - no problem!
class Penguin implements Eater, Sleeper, Swimmer, Speaker {
  public name: string;
  public energy: number = 100;

  private eater: Eater;
  private sleeper: Sleeper;
  private swimmer: Swimmer;

  constructor(name: string) {
    this.name = name;
    this.eater = new StandardEater(this);
    this.sleeper = new StandardSleeper(this);
    this.swimmer = new AquaticSwimmer(this);
  }

  eat(amount: number): void {
    this.eater.eat(amount);
  }

  sleep(hours: number): void {
    this.sleeper.sleep(hours);
  }

  swim(): void {
    this.swimmer.swim();
  }

  speak(): void {
    console.log(`${this.name} says squawk!`);
  }
}

// Flying fish: swims and flies - easy!
class FlyingFish implements Swimmer, Flyer {
  public name: string;
  public energy: number = 100;

  private swimmer: Swimmer;
  private flyer: Flyer;

  constructor(name: string) {
    this.name = name;
    this.swimmer = new AquaticSwimmer(this);
    this.flyer = new WingedFlyer(this, 30); // Different energy cost
  }

  swim(): void {
    this.swimmer.swim();
  }

  fly(): void {
    this.flyer.fly();
  }
}

// Robot bird: flies but doesn't eat or sleep
class RobotBird implements Flyer, Speaker {
  public name: string;
  public energy: number = 100;

  private flyer: Flyer;

  constructor(name: string) {
    this.name = name;
    this.flyer = new WingedFlyer(this, 10); // Efficient robot
  }

  fly(): void {
    this.flyer.fly();
  }

  speak(): void {
    console.log(`${this.name} says BEEP BOOP!`);
  }

  recharge(): void {
    this.energy = 100;
    console.log(`${this.name} recharged to full energy.`);
  }
}

// Functions work with any entity that has the required behavior
function makeEntityFly(flyer: Flyer): void {
  flyer.fly();
}

function feedEntity(eater: Eater, amount: number): void {
  eater.eat(amount);
}

// Works with duck, flying fish, or robot bird
makeEntityFly(new Duck('Donald'));
makeEntityFly(new FlyingFish('Nemo'));
makeEntityFly(new RobotBird('R2D2'));

// Works with duck or penguin, but not robot bird (correctly!)
feedEntity(new Duck('Donald'), 50);
feedEntity(new Penguin('Pingu'), 50);
// feedEntity(new RobotBird('R2D2'), 50); // Type error - RobotBird isn't an Eater

Why

  1. Flexibility: Compose any combination of behaviors. No artificial hierarchy constraints.

  2. Avoids Diamond Problem: No multiple inheritance issues. Just implement multiple interfaces.

  3. LSP Compliance: No need to override methods to throw errors. Types only have methods they actually support.

  4. Reusability: Behaviors can be reused across unrelated types.

  5. Testability: Test behaviors in isolation. Mock specific behaviors easily.

  6. Runtime Flexibility: Can change behaviors at runtime by swapping implementations.

  7. Stable Dependencies: Behavior implementations are stable. Adding new composed types doesn't affect existing code.

Source: SKILL.md on GitHub

1 warning16d5 checks · Risk SAFE
  • Gen Agent Trust Hub16d

    This skill contains language-agnostic guidelines, examples, and reference material for clean code and SOLID principles. It consists purely of static documentation and contains no executable code or security risks.

  • Socket16d

    No alerts

  • Snyk16d

    Risk: LOW · No issues

  • Runlayer6mo

    5/29 files flagged

  • ZeroLeaks5mo

    Score: 93/100 · 2 sections analyzed

Signed by skilld at 680deef. This ties the file your Agent reads to that commit on GitHub. It does not review the instructions.

Last checked against GitHub last month.

Steadyupdated 7 months ago
metadata
{
  "author": "AsyrafHussin",
  "version": "1.0.2"
}

README badge

README badge for asyrafhussin/agent-skills/clean-code-principles