Provides code quality principles including SOLID, DRY, testing strategies, and best practices for implementation review. Use when reviewing code or applying quality standards.
Provides code quality principles and best practices for reviewing and improving implementations.
/plugin marketplace add sequenzia/agent-alchemy/plugin install agent-alchemy-dev-tools@agent-alchemyThis skill inherits all available tools. When active, it can use any tool Claude has access to.
This skill provides code quality principles and best practices for reviewing and improving implementations.
A class/function should have one reason to change.
Bad:
class UserService {
createUser(data) { /* creates user */ }
sendEmail(user) { /* sends email */ }
generateReport(users) { /* generates report */ }
}
Good:
class UserService {
createUser(data) { /* creates user */ }
}
class EmailService {
sendEmail(user) { /* sends email */ }
}
class ReportService {
generateReport(users) { /* generates report */ }
}
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') { /* ... */ }
// Must modify to add new types
}
Good: New payment types can be added without modification
interface PaymentProcessor {
process(amount: number): Promise<void>;
}
class CreditProcessor implements PaymentProcessor { /* ... */ }
class DebitProcessor implements PaymentProcessor { /* ... */ }
Subtypes must be substitutable for their base types.
Bad:
class Bird {
fly() { /* ... */ }
}
class Penguin extends Bird {
fly() { throw new Error("Can't fly!"); } // Violates LSP
}
Good:
class Bird { /* ... */ }
class FlyingBird extends Bird {
fly() { /* ... */ }
}
class Penguin extends Bird { /* no fly method */ }
Clients shouldn't depend on interfaces they don't use.
Bad:
interface Worker {
work(): void;
eat(): void;
sleep(): void;
}
Good:
interface Workable { work(): void; }
interface Eatable { eat(): void; }
interface Sleepable { sleep(): void; }
Depend on abstractions, not concretions.
Bad:
class UserService {
private db = new PostgresDatabase();
}
Good:
class UserService {
constructor(private db: Database) {}
}
Every piece of knowledge should have a single representation.
Apply when:
Don't over-apply:
Prefer simple solutions over clever ones.
Simple code:
Don't add functionality until it's needed.
Avoid:
// Bad
const d = new Date();
const arr = users.filter(u => u.a > 18);
// Good
const currentDate = new Date();
const adultUsers = users.filter(user => user.age > 18);
// Bad: side effect hidden in getter
getUser() {
this.lastAccess = Date.now(); // Side effect!
return this.user;
}
// Good: explicit about what it does
getUser() {
return this.user;
}
recordAccess() {
this.lastAccess = Date.now();
}
// Be specific about errors
class ValidationError extends Error {}
class NotFoundError extends Error {}
class AuthorizationError extends Error {}
// Handle at appropriate level
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; // Re-throw unexpected errors
}
/\
/ \ E2E Tests (few)
/────\
/ \ Integration Tests (some)
/────────\
/ \ Unit Tests (many)
/────────────\
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);
});
});
// Bad: tests implementation details
it('calls _internalMethod', () => {
const spy = jest.spyOn(service, '_internalMethod');
service.doThing();
expect(spy).toHaveBeenCalled();
});
// Good: tests behavior
it('sends welcome email on registration', async () => {
await service.registerUser({ email: 'test@test.com' });
expect(emailSent).toContainEqual({
to: 'test@test.com',
template: 'welcome'
});
});
| 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 |
When a code block can be grouped and named
When the function body is as clear as the name
When an expression is complex
When the name doesn't communicate intent
When you have repeated switch/if statements on type
When several parameters travel together
Activates when the user asks about AI prompts, needs prompt templates, wants to search for prompts, or mentions prompts.chat. Use for discovering, retrieving, and improving prompts.
Search, retrieve, and install Agent Skills from the prompts.chat registry using MCP tools. Use when the user asks to find skills, browse skill catalogs, install a skill for Claude, or extend Claude's capabilities with reusable AI agent components.
Expert guidance for Next.js Cache Components and Partial Prerendering (PPR). **PROACTIVE ACTIVATION**: Use this skill automatically when working in Next.js projects that have `cacheComponents: true` in their next.config.ts/next.config.js. When this config is detected, proactively apply Cache Components patterns and best practices to all React Server Component implementations. **DETECTION**: At the start of a session in a Next.js project, check for `cacheComponents: true` in next.config. If enabled, this skill's patterns should guide all component authoring, data fetching, and caching decisions. **USE CASES**: Implementing 'use cache' directive, configuring cache lifetimes with cacheLife(), tagging cached data with cacheTag(), invalidating caches with updateTag()/revalidateTag(), optimizing static vs dynamic content boundaries, debugging cache issues, and reviewing Cache Component implementations.