| name | code-quality |
| description | Provides code quality principles including SOLID, DRY, testing strategies, and best practices for implementation review. Use when reviewing code or applying quality standards. |
| dependencies | [] |
Code Quality
This skill provides code quality principles and best practices for reviewing and improving implementations.
SOLID Principles
Single Responsibility Principle (SRP)
A class/function should have one reason to change.
Bad:
class UserService {
createUser(data) { }
sendEmail(user) { }
generateReport(users) { }
}
Good:
class UserService {
createUser(data) { }
}
class EmailService {
sendEmail(user) { }
}
class ReportService {
generateReport(users) { }
}
Open/Closed Principle (OCP)
Open for extension, closed for modification.
Bad: Adding new payment types requires modifying existing code
function processPayment(type, amount) {
if (type === 'credit') { }
else if (type === 'debit') { }
}
Good: New payment types can be added without modification
interface PaymentProcessor {
process(amount: number): Promise<void>;
}
class CreditProcessor implements PaymentProcessor { }
class DebitProcessor implements PaymentProcessor { }
Liskov Substitution Principle (LSP)
Subtypes must be substitutable for their base types.
Bad:
class Bird {
fly() { }
}
class Penguin extends Bird {
fly() { throw new Error("Can't fly!"); }
}
Good:
class Bird { }
class FlyingBird extends Bird {
fly() { }
}
class Penguin extends Bird { }
Interface Segregation Principle (ISP)
Clients should not depend on interfaces they do not use.
Bad:
interface Worker {
work(): void;
eat(): void;
sleep(): void;
}
Good:
interface Workable { work(): void; }
interface Eatable { eat(): void; }
interface Sleepable { sleep(): void; }
Dependency Inversion Principle (DIP)
Depend on abstractions, not concretions.
Bad:
class UserService {
private db = new PostgresDatabase();
}
Good:
class UserService {
constructor(private db: Database) {}
}
DRY, KISS, YAGNI
DRY (Don't Repeat Yourself)
Every piece of knowledge should have a single representation.
Apply when:
- Same logic appears 3+ times
- Changes to one place require changes to others
- Bug fixes need to be applied in multiple places
Do not over-apply:
- Two similar things might diverge later
- Premature abstraction can be worse than duplication
KISS (Keep It Simple, Stupid)
Prefer simple solutions over clever ones.
Simple code:
- Easy to read and understand
- Easy to debug
- Easy to modify
- Has fewer bugs
YAGNI (You Aren't Gonna Need It)
Do not add functionality until it is needed.
Avoid:
- Building for hypothetical requirements
- Adding "just in case" features
- Over-engineering for scale you do not have
Clean Code Principles
Meaningful Names
const d = new Date();
const arr = users.filter(u => u.a > 18);
const currentDate = new Date();
const adultUsers = users.filter(user => user.age > 18);
Small Functions
- Do one thing well
- Few parameters (ideally 0-3)
- Single level of abstraction
Avoid Side Effects
getUser() {
this.lastAccess = Date.now();
return this.user;
}
getUser() {
return this.user;
}
recordAccess() {
this.lastAccess = Date.now();
}
Error Handling
class ValidationError extends Error {}
class NotFoundError extends Error {}
class AuthorizationError extends Error {}
try {
await processOrder(order);
} catch (error) {
if (error instanceof ValidationError) {
return res.status(400).json({ error: error.message });
}
if (error instanceof NotFoundError) {
return res.status(404).json({ error: error.message });
}
throw error;
}
Testing Strategies
Test Pyramid
/\
/ \ E2E Tests (few)
/────\
/ \ Integration Tests (some)
/────────\
/ \ Unit Tests (many)
/────────────\
Unit Testing
- Test individual functions/classes
- Mock dependencies
- Fast and isolated
describe('calculateTotal', () => {
it('sums item prices', () => {
const items = [{ price: 10 }, { price: 20 }];
expect(calculateTotal(items)).toBe(30);
});
it('applies discount', () => {
const items = [{ price: 100 }];
expect(calculateTotal(items, { discount: 0.1 })).toBe(90);
});
it('handles empty cart', () => {
expect(calculateTotal([])).toBe(0);
});
});
Integration Testing
- Test component interactions
- Use real dependencies (or test doubles)
- Database, API integration
Test Behavior, Not Implementation
it('calls _internalMethod', () => {
const spy = jest.spyOn(service, '_internalMethod');
service.doThing();
expect(spy).toHaveBeenCalled();
});
it('sends welcome email on registration', async () => {
await service.registerUser({ email: 'test@test.com' });
expect(emailSent).toContainEqual({
to: 'test@test.com',
template: 'welcome'
});
});
Edge Cases to Test
- Empty inputs
- Null/undefined
- Boundary values
- Error conditions
- Concurrent operations
- Large inputs
Code Review Checklist
Correctness
Security
Performance
Maintainability
Testing
Common Code Smells
| Smell | Description | Solution |
|---|
| Long Method | Function > 20-30 lines | Extract methods |
| Large Class | Class with too many responsibilities | Split into focused classes |
| Long Parameter List | > 3-4 parameters | Use parameter object |
| Duplicate Code | Same code in multiple places | Extract function |
| Dead Code | Unused code | Delete it |
| Magic Numbers | Unexplained numeric literals | Use named constants |
| Nested Conditionals | Deep if/else nesting | Early returns, extract methods |
| Feature Envy | Method uses another class's data heavily | Move method to that class |
Refactoring Techniques
Extract Function
When a code block can be grouped and named
Inline Function
When the function body is as clear as the name
Extract Variable
When an expression is complex
Rename Variable/Function
When the name does not communicate intent
Replace Conditional with Polymorphism
When you have repeated switch/if statements on type
Introduce Parameter Object
When several parameters travel together
Integration Notes
Capabilities Needed
This skill requires the following capabilities from the host environment:
- File system access: Read files to review code
Adaptation Guidance
- This is a reference/knowledge skill that provides code quality principles and review checklists. It does not require shell execution or parallel delegation.
- When used by other skills (e.g., bug-killer, feature-dev), it supplies quality standards to inform review decisions.