Loading...
Loading...
Write clean, readable, and maintainable code following principles from Robert C. Martin's "Clean Code" and Object Calisthenics. Use when writing, reviewing, or refactoring code to improve naming, function design, formatting, error handling, and class structure. Includes code smell detection and refactoring guidance.
npx skill4agent add fellipeutaka/leon clean-code"Code is clean if it can be understood easily — by everyone on the team." — Dave Thomas
| Priority | Category | Impact |
|---|---|---|
| 1 | Naming | HIGH — affects every line of code |
| 2 | Functions | HIGH — core unit of abstraction |
| 3 | Code Smells | HIGH — early detection prevents rot |
| 4 | Formatting | MEDIUM — readability at a glance |
| 5 | Error Handling | MEDIUM — robustness and clarity |
| 6 | Comments | MEDIUM — most are avoidable |
| 7 | Object Calisthenics | ASPIRATIONAL — exercises for better OO design |
datainfomanagerhandlerutils// Bad
const d = new Date();
const arr = users.filter((u) => u.a);
function process(data: any) {}
// Good
const createdAt = new Date();
const activeUsers = users.filter((user) => user.isActive);
function validatePayment(payment: Payment) {}CustomerOrderRepositoryManagerDataInfocreateOrdervalidateEmailisEligibleisActivehasPermissioncanWithdrawusersorderItemsreferences/NAMING.md// Bad — does too many things, unclear name
function handle(order: Order, sendEmail: boolean, log: boolean) {
// validate, calculate, save, email, log — all in one
}
// Good — small, single-purpose, descriptive
function validateOrder(order: Order): ValidationResult { ... }
function calculateTotal(items: OrderItem[]): Money { ... }
function saveOrder(order: Order): Promise<void> { ... }saveAndNotifysave| Smell | Symptom | Quick Fix |
|---|---|---|
| Long Method | > 20 lines, multiple concerns | Extract methods |
| Large Class | Many responsibilities | Extract class (SRP) |
| Long Parameter List | > 3 parameters | Introduce parameter object |
| Primitive Obsession | Strings/numbers for domain concepts | Wrap in value objects |
| Feature Envy | Method uses another class's data more than its own | Move method |
| Data Clumps | Same group of fields appear together | Extract class |
| Switch Statements | Type-checking switch/if-else across codebase | Replace with polymorphism |
| Divergent Change | One class changed for many reasons | Split by responsibility |
| Shotgun Surgery | One change touches many files | Move related code together |
| Speculative Generality | "Just in case" abstractions | Delete (YAGNI) |
| Dead Code | Unreachable or unused code | Delete |
| Message Chains | | Hide delegate (Law of Demeter) |
references/CODE_SMELLS.mdclass OrderProcessor {
// Public API first — the "headline"
process(order: Order): ProcessResult {
this.validate(order);
const total = this.calculateTotal(order);
return this.save(order, total);
}
// Supporting methods below, in order of appearance
private validate(order: Order) { ... }
private calculateTotal(order: Order): Money { ... }
private save(order: Order, total: Money): ProcessResult { ... }
}nullundefinedResultnullInsufficientFundsErrorError// Bad — null checks cascade through codebase
function getUser(id: string): User | null {
return db.find(id);
}
const user = getUser(id);
if (user === null) { ... } // Every caller must check
// Good — throw at boundary, trust within domain
function getUser(id: string): User {
const user = db.find(id);
if (!user) throw new UserNotFoundError(id);
return user;
}"Don't comment bad code — rewrite it."
// increment counter// constructor// getters// Bad — restates the obvious
// Check if user is active
if (user.isActive) { ... }
// Good — explains a non-obvious business rule
// Users who haven't verified email within 30 days are auto-deactivated
// per compliance requirement GDPR-2024-42
if (user.isAutoDeactivated) { ... }| # | Rule | Goal |
|---|---|---|
| 1 | One level of indentation per method | Extract methods aggressively |
| 2 | Don't use | Early returns, guard clauses, polymorphism |
| 3 | Wrap all primitives with domain meaning | Value objects ( |
| 4 | First-class collections | Wrap arrays in domain-specific classes |
| 5 | One dot per line | Law of Demeter — talk to friends only |
| 6 | Don't abbreviate | If the name is too long, the class does too much |
| 7 | Keep entities small | Classes < 50 lines, methods < 10 lines |
| 8 | Limit instance variables | Strive for 2-3; forces focused classes |
| 9 | No getters/setters | Objects have behavior, not just data |
references/OBJECT_CALISTHENICS.md