clean-code-reviewPragmatic coding standards for writing clean, maintainable code β naming, functions, structure, anti-patterns, and pre-edit safety checks. Use when writing new code, refactoring existing code, reviewing code quality, or establishing coding standards.
Install via ClawdBot CLI:
clawdbot install wpank/clean-code-reviewBe concise, direct, and solution-focused. Clean code reads like well-written prose β every name reveals intent, every function does one thing, and every abstraction earns its place.
npx clawhub@latest install clean-code
| Principle | Rule | Practical Test |
|-----------|------|----------------|
| SRP | Single Responsibility β each function/class does ONE thing | "Can I describe what this does without using 'and'?" |
| DRY | Don't Repeat Yourself β extract duplicates, reuse | "Have I written this logic before?" |
| KISS | Keep It Simple β simplest solution that works | "Is there a simpler way to achieve this?" |
| YAGNI | You Aren't Gonna Need It β don't build unused features | "Does anyone need this right now?" |
| Boy Scout | Leave code cleaner than you found it | "Is this file better after my change?" |
Names are the most important documentation. A good name eliminates the need for a comment.
| Element | Convention | Bad | Good |
|---------|------------|-----|------|
| Variables | Reveal intent | n, d, tmp | userCount, elapsed, activeUsers |
| Functions | Verb + noun | user(), calc() | getUserById(), calculateTotal() |
| Booleans | Question form | active, flag | isActive, hasPermission, canEdit |
| Constants | SCREAMING_SNAKE | max, timeout | MAX_RETRY_COUNT, REQUEST_TIMEOUT_MS |
| Classes | Noun, singular | Manager, Data | UserRepository, OrderService |
| Enums | PascalCase values | 'pending' string | Status.Pending |
Rule: If you need a comment to explain a name, rename it.
| Anti-Pattern | Problem | Fix |
|--------------|---------|-----|
| Cryptic abbreviations (usrMgr, cfg) | Unreadable in 6 months | Spell it out β IDE autocomplete makes long names free |
| Generic names (data, info, item, handler) | Says nothing about purpose | Use domain-specific names that reveal intent |
| Misleading names (getUserList returns one user) | Actively deceives readers | Match name to behavior, or change the behavior |
| Hungarian notation (strName, nCount, IUser) | Redundant with type system | Let TypeScript/IDE show types; names describe purpose |
| Rule | Guideline | Why |
|------|-----------|-----|
| Small | Max 20 lines, ideally 5-10 | Fits in your head |
| One Thing | Does one thing, does it well | Testable and nameable |
| One Level | One level of abstraction per function | Readable top to bottom |
| Few Args | Max 3 arguments, prefer 0-2 | Easy to call correctly |
| No Side Effects | Don't mutate inputs unexpectedly | Predictable behavior |
Flatten nested conditionals with early returns. Never nest deeper than 2 levels.
// BAD β 5 levels deep
function processOrder(order: Order) {
if (order) {
if (order.items.length > 0) {
if (order.customer) {
if (order.customer.isVerified) {
return submitOrder(order);
}
}
}
}
throw new Error('Invalid order');
}
// GOOD β guard clauses flatten the structure
function processOrder(order: Order) {
if (!order) throw new Error('No order');
if (!order.items.length) throw new Error('No items');
if (!order.customer) throw new Error('No customer');
if (!order.customer.isVerified) throw new Error('Customer not verified');
return submitOrder(order);
}
When a function needs more than 3 arguments, use an options object.
// BAD β too many parameters, order matters
createUser('John', 'Doe', 'john@example.com', 'secret', 'admin', 'Engineering');
// GOOD β self-documenting options object
createUser({
firstName: 'John',
lastName: 'Doe',
email: 'john@example.com',
password: 'secret',
role: 'admin',
department: 'Engineering',
});
| Pattern | When to Apply | Benefit |
|---------|--------------|---------|
| Guard Clauses | Edge cases at function start | Flat, readable flow |
| Flat > Nested | Any nesting beyond 2 levels | Reduced cognitive load |
| Composition | Complex operations | Small, testable pieces |
| Colocation | Related code across files | Easier to find and change |
| Extract Function | Comments separating "sections" | Self-documenting code |
// BAD β god function doing everything
async function processOrder(order: Order) {
// Validate... (15 lines)
// Calculate totals... (15 lines)
// Process payment... (10 lines)
// Send notifications... (10 lines)
// Update inventory... (10 lines)
return { success: true };
}
// GOOD β composed of small, focused functions
async function processOrder(order: Order) {
validateOrder(order);
const totals = calculateOrderTotals(order);
const payment = await processPayment(order.customer, totals);
await sendOrderConfirmation(order, payment);
await updateInventory(order.items);
return { success: true, orderId: payment.orderId };
}
Functions should return consistent types. Use discriminated unions for multiple outcomes.
// BAD β returns different types
function getUser(id: string) {
const user = database.find(id);
if (!user) return false; // boolean
if (user.isDeleted) return null; // null
return user; // User
}
// GOOD β discriminated union
type GetUserResult =
| { status: 'found'; user: User }
| { status: 'not_found' }
| { status: 'deleted' };
function getUser(id: string): GetUserResult {
const user = database.find(id);
if (!user) return { status: 'not_found' };
if (user.isDeleted) return { status: 'deleted' };
return { status: 'found', user };
}
| Anti-Pattern | Problem | Fix |
|--------------|---------|-----|
| Comment every line | Noise obscures signal | Delete obvious comments; comment why, not what |
| Helper for one-liner | Unnecessary indirection | Inline the code |
| Factory for 2 objects | Over-engineering | Direct instantiation |
| utils.ts with 1 function | Junk drawer file | Put code where it's used |
| Deep nesting | Unreadable flow | Guard clauses and early returns |
| Magic numbers | Unclear intent | Named constants |
| God functions | Untestable, unreadable | Split by responsibility |
| Commented-out code | Dead code confusion | Delete it; git remembers |
| TODO sprawl | Never gets done | Track in issue tracker, not code |
| Premature abstraction | Wrong abstraction is worse than none | Wait for 3+ duplicates before abstracting |
| Copy-paste programming | Duplicated bugs | Extract shared logic |
| Exception-driven control flow | Slow and confusing | Use explicit conditionals |
| Stringly-typed code | Typos and missed cases | Use enums or union types |
| Callback hell | Pyramid of doom | Use async/await |
Before changing any file, answer these questions to avoid cascading breakage:
| Question | Why |
|----------|-----|
| What imports this file? | Dependents might break on interface changes |
| What does this file import? | You might need to update the contract |
| What tests cover this? | Tests might fail β update them alongside code |
| Is this a shared component? | Multiple consumers means wider blast radius |
File to edit: UserService.ts
βββ Who imports this? β UserController.ts, AuthController.ts
βββ Do they need changes too? β Check function signatures
βββ What tests cover this? β UserService.test.ts
Rule: Edit the file + all dependent files in the SAME task. Never leave broken imports or missing updates.
Before marking any task complete, verify:
| Check | Question |
|-------|----------|
| Goal met? | Did I do exactly what was asked? |
| Files edited? | Did I modify all necessary files, including dependents? |
| Code works? | Did I verify the change compiles and runs? |
| No errors? | Do lint and type checks pass? |
| Nothing forgotten? | Any edge cases or dependent files missed? |
Detailed guides for specific clean code topics:
| Reference | Description |
|-----------|-------------|
| Anti-Patterns | 21 common mistakes with bad/good code examples across naming, functions, structure, and comments |
| Code Smells | Classic code smells catalog with detection patterns β Bloaters, OO Abusers, Change Preventers, Dispensables, Couplers |
| Refactoring Catalog | Essential refactoring patterns with before/after examples and step-by-step mechanics |
Generated Feb 25, 2026
Development teams use the skill during peer reviews to enforce coding standards, ensuring new code adheres to clean principles like SRP and DRY. It helps identify anti-patterns and improve maintainability in software projects.
Engineers apply the skill to modernize outdated codebases by refactoring functions, improving naming conventions, and reducing nesting. This enhances readability and reduces technical debt in enterprise applications.
Companies integrate the skill into developer onboarding programs to establish consistent coding practices. It teaches new hires to write clean, testable code from the start, speeding up team integration.
Teams use the skill when designing APIs and microservices to ensure functions are small, focused, and have consistent return types. This improves scalability and reduces bugs in distributed systems.
Maintainers leverage the skill to review contributions, enforcing naming rules and guard clauses. This keeps codebases accessible and reduces merge conflicts in collaborative environments.
Offer the skill as part of a subscription-based developer tool suite, integrating it into IDEs or CI/CD pipelines. Revenue comes from monthly fees per user or team, targeting enterprises seeking code quality improvements.
Provide expert consulting to help companies adopt clean code practices, including workshops and code audits. Revenue is generated through project-based fees or hourly rates, focusing on industries with legacy systems.
Distribute the skill as a free open-source package with premium features like advanced analytics or team dashboards. Revenue comes from upsells to paid tiers for larger organizations needing collaboration tools.
π¬ Integration Tip
Integrate the skill into code review workflows using pre-commit hooks or CI checks to automatically flag violations, ensuring consistent application across teams.
Guide for creating effective skills. This skill should be used when users want to create a new skill (or update an existing skill) that extends Claude's capabilities with specialized knowledge, workflows, or tool integrations.
Provides a 7-step debugging protocol plus language-specific commands to systematically identify, verify, and fix software bugs across multiple environments.
A comprehensive skill for using the Cursor CLI agent for various software engineering tasks (updated for 2026 features, includes tmux automation guide).
Write, run, and manage unit, integration, and E2E tests across TypeScript, Python, and Swift using recommended frameworks.
Control and operate Opencode via slash commands. Use this skill to manage sessions, select models, switch agents (plan/build), and coordinate coding through Opencode.
Coding style memory that adapts to your preferences, conventions, and patterns for consistent coding.