| name | oop-principles |
| description | Evaluate code against Dave Thomas's OO principles, SOLID principles, and the Tell Don't Ask rule. Routes to `design-patterns/` and `solid/` sub-skills.
TRIGGER when: class has only static methods; class has a single public method + constructor; code uses GoF pattern names (Decorator/Factory/Strategy/Builder/Command/Observer); class is invalid until setters are called; data class with only constructor + properties; external code reads getters to make decisions (Tell Don't Ask); user asks "is this OOP design smell?", "is this a class design issue?", "is this an OOP anti-pattern?", "should this be a class or a function?", or "why does my code feel procedural?".
DO NOT USE when: the smell is at the function/method level (long method, primitive obsession, feature envy on values, etc.) — that is `refactoring`'s domain. Activate here only for *class-shape* issues.
|
| user-invocable | false |
OO Principles
Distinguish true object-oriented design from class-oriented anti-patterns.
Route to Sub-skills
→ Design patterns (Strategy, Factory, Builder, Decorator, Mixin…) → design-patterns/ sub-skill
→ SOLID principles (SRP, OCP, LSP, ISP, DIP) → solid/ sub-skill
Core rule: Use a class only when it creates multiple instances with their own state. Otherwise prefer functions, object literals, or types.
The Seven Rules
For each rule below, full code examples live in references/anti-patterns.md.
-
Not an object factory → don't use a class. Class with only static methods is just a namespace. → use standalone functions or const X = { ... } as const. (anti-patterns.md §1)
-
Named after a design pattern → don't use a class. GoF patterns (Decorator/Factory/Strategy/Command) collapse to plain functions or higher-order functions. (anti-patterns.md §3)
-
Abstract base classes are rarely necessary. Prefer composition + structural typing over inheritance. (anti-patterns.md §5)
-
No state, no class. A class with one public method (perform/call/execute) instantiated only to call it once is just a function. (anti-patterns.md §2)
-
Invalid after construction → don't use a class. Builders requiring setters before use → take all required args in one function or constructor. (anti-patterns.md §4, §9)
-
Stop writing data classes. Constructor + properties + no behavior → use a plain data structure (record, struct, type alias). (anti-patterns.md §6)
-
Test-first implications:
| Pattern | Setup | Testing |
|---|
| Pure functions | Pass args | Isolated, no mocks |
| Stateful classes | Factories, mocks | Tangled |
| Inheritance chains | Heavy fixtures | Nightmare |
Tell Don't Ask
When you do use a class, don't let callers query state and decide externally — move the decision into the object. Watch for getter chains, if (obj.getX()) obj.setY() patterns, and decision logic scattered across callers.
→ Full guide, refactoring steps, nuance, and review checklist: references/tell-dont-ask.md
Workflow
- Decision tree:
references/refactoring-checklist.md
- Anti-pattern catalog with fixes:
references/anti-patterns.md
- Tell Don't Ask:
references/tell-dont-ask.md
"If it's not making multiple instances, it's not a class." — Dave Thomas