# Composition Over Inheritance

> Use when tempted to use class inheritance. Use when creating class hierarchies. Use when subclass needs only some parent behavior.

- Skill: `yanko-belov/composition-over-inheritance` (Agent Skill)
- Install (CLI): `npx skillmds@latest add yanko-belov/composition-over-inheritance`
- Raw SKILL.md: https://api.skillmd.com/api/skills/yanko-belov/composition-over-inheritance/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: yanko-belov (https://skillmd.com/u/yanko-belov)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/yanko-belov/composition-over-inheritance

---


# Composition Over Inheritance

## Overview

**Favor object composition over class inheritance.**

Inheritance creates tight coupling and rigid hierarchies. Composition creates flexible, reusable components that can be mixed and matched.

## When to Use

- Designing relationships between classes
- Tempted to use `extends`
- Class needs behavior from multiple sources
- Creating "is-a" relationships
- Building class hierarchies

## The Iron Rule

```
NEVER use inheritance when composition would work.
```

**No exceptions:**
- Not for "it's the OOP way"
- Not for "is-a relationship"
- Not for "code reuse via extends"
- Not for "polymorphism"

**Default to composition. Use inheritance only for true type hierarchies.**

## Detection: The Inheritance Smell

If inheritance feels awkward or forced, use composition:

```typescript
// ❌ VIOLATION: Inheritance hierarchy
class Animal {
  eat(): void { console.log('Eating'); }
}

class FlyingAnimal extends Animal {
  fly(): void { console.log('Flying'); }
}

class SwimmingAnimal extends Animal {
  swim(): void { console.log('Swimming'); }
}

// Duck needs both fly AND swim - inheritance can't do this cleanly
class Duck extends FlyingAnimal {
  swim(): void { console.log('Swimming'); } // Duplicated!
}
```

## Correct Pattern: Composition with Interfaces

Define capabilities as interfaces, compose them:

```typescript
// ✅ CORRECT: Composition
interface Flyable {
  fly(): void;
}

interface Swimmable {
  swim(): void;
}

interface Eatable {
  eat(): void;
}

// Reusable behaviors
const flyingBehavior: Flyable = {
  fly() { console.log('Flying'); }
};

const swimmingBehavior: Swimmable = {
  swim() { console.log('Swimming'); }
};

const eatingBehavior: Eatable = {
  eat() { console.log('Eating'); }
};

// Compose what you need
class Duck implements Flyable, Swimmable, Eatable {
  fly = flyingBehavior.fly;
  swim = swimmingBehavior.swim;
  eat = eatingBehavior.eat;
}

class Fish implements Swimmable, Eatable {
  swim = swimmingBehavior.swim;
  eat = eatingBehavior.eat;
}

class Bird implements Flyable, Eatable {
  fly = flyingBehavior.fly;
  eat = eatingBehavior.eat;
}
```

## Why Inheritance Fails

| Problem | Example |
|---------|---------|
| **Diamond problem** | Duck needs Flying AND Swimming |
| **Tight coupling** | Child knows parent internals |
| **Rigid hierarchy** | Can't change parent without breaking children |
| **Forced inheritance** | Gets methods it doesn't need |
| **Fragile base class** | Parent changes break all children |

## Why Composition Wins

| Benefit | Example |
|---------|---------|
| **Flexible** | Mix any behaviors together |
| **Loose coupling** | Components don't know each other |
| **Easy testing** | Mock individual behaviors |
| **Runtime changes** | Swap behaviors dynamically |
| **No hierarchy lock-in** | Add new combinations freely |

## Pressure Resistance Protocol

### 1. "It's the OOP Way"
**Pressure:** "Object-oriented programming uses inheritance"

**Response:** Modern OOP favors composition. Inheritance is overused.

**Action:** Use interfaces + composition. It's still OOP.

### 2. "It's an Is-A Relationship"
**Pressure:** "A Duck IS-A Bird, so it should extend Bird"

**Response:** "Is-a" often becomes "has-a" when requirements change. Composition handles both.

**Action:** Model as "has behaviors" not "is a type".

### 3. "Code Reuse via Extends"
**Pressure:** "I need the parent's methods"

**Response:** Composition provides better code reuse without coupling.

**Action:** Extract shared behavior into composable units.

### 4. "Polymorphism Requires Inheritance"
**Pressure:** "I need to treat different types uniformly"

**Response:** Interfaces provide polymorphism without inheritance.

**Action:** Define interface, have classes implement it.

## Red Flags - STOP and Reconsider

If you notice ANY of these, use composition instead:

- `extends` keyword in your code
- Class hierarchy deeper than 2 levels
- Child class overriding parent methods
- "Diamond problem" - needs multiple parents
- Subclass doesn't use all parent methods
- Changing parent breaks children
- Hard to test without instantiating parent

**All of these mean: Refactor to composition.**

## When Inheritance IS Appropriate

Use inheritance only when:
- True type hierarchy (rarely)
- Framework requires it (React class components, etc.)
- Extending library classes you don't control

Even then, keep hierarchy shallow (max 2 levels).

## Quick Reference

| Inheritance | Composition |
|-------------|-------------|
| `class Dog extends Animal` | `class Dog implements Animal` + behavior injection |
| Rigid hierarchy | Flexible composition |
| Single parent only | Multiple behaviors |
| Tight coupling | Loose coupling |
| Changes cascade | Changes isolated |

## Common Rationalizations (All Invalid)

| Excuse | Reality |
|--------|---------|
| "It's the OOP way" | Modern OOP prefers composition. |
| "It's an is-a relationship" | "Has behavior" is more flexible. |
| "Need parent's methods" | Compose the behavior instead. |
| "Polymorphism needs it" | Interfaces provide polymorphism. |
| "Less code with extends" | More flexibility with composition. |
| "I noted it's problematic" | Don't do it if it's problematic. |

## The Bottom Line

**Compose behaviors. Don't inherit them.**

When designing classes: define interfaces for capabilities, create composable behaviors, inject what each class needs. Use `extends` only as last resort.

