Principles and practices for writing readable, maintainable, and testable code
npx skills add https://github.com/cosmicstack-labs/mercury-agent-skills --skill clean-code
Write code that humans can read, understand, and change with confidence.
Code is communication. Every name, structure, and abstraction should reveal intent. If you need a comment to explain *what* the code does, the code is failing at communication.
Small functions, small classes, small files. Each unit of code should have one clear responsibility and do it well. Composability beats complexity.
Leave the code cleaner than you found it. Every commit should improve the codebase incrementally — even if it's just renaming one variable or extracting one function.
If code is hard to test, it has a design problem. Testable code is modular, decoupled, and honest about its dependencies.
Use this rubric to evaluate code quality on a scale of 1-5 for each dimension:
| Dimension | 1 (Poor) | 3 (Adequate) | 5 (Excellent) |
|-----------|----------|---------------|----------------|
| Naming | Single-letter vars, ambiguous abbreviations | Descriptive but occasionally redundant | Reveals intent, consistent, searchable |
| Function Size | Monolithic 500+ line functions | 50-100 line functions with mixed concerns | <20 lines, one clear level of abstraction |
| Comments | Outdated or redundant comments | Comments explain *what* not *why* | Minimal comments, code is self-documenting |
| Error Handling | Silent catches, magic error codes | Basic try/catch, some error types | Rich error types, graceful degradation |
| Testing | No tests or brittle tests | Tests exist but tightly coupled to implementation | Tests specify behavior, not implementation |
| Duplication | Copy-paste everywhere | Some reuse, some DRY violations | DRY with well-abstracted patterns |
Target: 4+ in every dimension for production-grade code.
Rules:
isActive, hasPermission, shouldRetry). Avoid negated names like isNotDisabled.calculateTotal(), validateInput(), fetchUser()).UserAccount, PaymentProcessor, HttpClient).MAX_RETRY_COUNT, DEFAULT_TIMEOUT_MS).# Bad
def proc(d):
r = []
for i in d:
if i.get('a') == True:
r.append(i.get('n'))
return r
# Good
def extract_active_user_names(users):
active_users = [user for user in users if user['is_active']]
return [user['name'] for user in active_users]
Searchable names: Avoid single-letter variables except in trivial loops. Use names that can be found with grep.
Rules:
setX(), updateY()).// Bad: Mixed abstraction levels
function processOrder(order) {
const tax = order.total * 0.08; // Low-level calc
order.totalWithTax = order.total + tax; // Mutation
fs.writeFileSync(`orders/${order.id}.json`, JSON.stringify(order)); // Side effect
sendEmailNotification(order.userEmail, 'Order processed'); // Side effect
return order.totalWithTax;
}
// Good: Clear single responsibility
function calculateTotalWithTax(total, taxRate) {
return total + (total * taxRate);
}
When to comment:
// FIXME: This endpoint is rate-limited to 100 req/minWhen NOT to comment:
// Increment counter)Patterns:
# Prefer specific exception types
def get_user(user_id):
try:
return database.fetch_user(user_id)
except DatabaseConnectionError:
logger.error(f"Database unavailable when fetching user {user_id}")
raise ServiceUnavailableError("User service temporarily unavailable")
except UserNotFoundError:
logger.info(f"User {user_id} not found")
return None # Expected case, not exceptional
Guidelines:
Result[T, E] types (Rust, Swift) or Either (functional languages) instead of exceptions for expected failures.catch blocks are a code smell. At minimum, log and re-raise.The Testing Trophy (not pyramid):
E2E Tests (few)
Integration (some)
Unit Tests (many)
Static Analysis (all code)
Guidelines:
it() blocks rather than multiple asserts in one."foo" and 123 don't catch edge cases.# Bad: Tests implementation details
def test_get_user():
mock_db = MagicMock()
service = UserService(mock_db)
result = service._fetch_and_transform_user(42) # Testing private method
assert mock_db.execute.called_once_with("SELECT * FROM users WHERE id=42")
# Good: Tests behavior
def test_get_user_returns_user_when_found():
user_repo = InMemoryUserRepository([User(id=42, name="Alice")])
service = UserService(user_repo)
result = service.get_user(42)
assert result.name == "Alice"
def test_get_user_returns_none_when_not_found():
user_repo = InMemoryUserRepository([])
service = UserService(user_repo)
result = service.get_user(99)
assert result is None
| Smell | Symptom | Fix |
|-------|---------|-----|
| Long Method | >20 lines doing multiple things | Extract methods, compose |
| Switch/Types | Switch on type enum, then dispatch | Polymorphism or strategy pattern |
| Feature Envy | Method uses more of another class's data than its own | Move method to the right class |
| Shotgun Surgery | One change requires edits in many files | Consolidate related logic |
| Data Clumps | Same 3-4 fields appear together repeatedly | Extract into a value object |
| Primitive Obsession | Using strings/ints where types belong | Create domain types |
| Inappropriate Intimacy | Class knows too much about another's internals | Reduce coupling, use interfaces |
goto in C error handling is fine. Single-letter variables in math-heavy code are fine. Context matters.Guide for creating high-quality MCP (Model Context Protocol) servers that enable LLMs to interact with external services through well-designed tools. Use when building MCP servers to integrate external APIs or services, whether in Python (FastMCP) or Node/TypeScript (MCP SDK).
Automatically creates user-facing changelogs from git commits by analyzing commit history, categorizing changes, and transforming technical commits into clear, customer-friendly release notes. Turns hours of manual changelog writing into minutes of automated generation.
Use when implementation is complete, all tests pass, and you need to decide how to integrate the work - guides completion of development work by presenting structured options for merge, PR, or cleanup
Guide for creating high-quality MCP (Model Context Protocol) servers that enable LLMs to interact with external services through well-designed tools. Use when building MCP servers to integrate external APIs or services, whether in Python (FastMCP) or Node/TypeScript (MCP SDK).
React Native and Expo best practices for building performant mobile apps. Use when building React Native components, optimizing list performance, implementing animations, or working with native modules. Triggers on tasks involving React Native, Expo, mobile performance, or native platform APIs.
React and Next.js performance optimization guidelines from Vercel Engineering. This skill should be used when writing, reviewing, or refactoring React/Next.js code to ensure optimal performance patterns. Triggers on tasks involving React components, Next.js pages, data fetching, bundle optimization, or performance improvements.
Next.js best practices - file conventions, RSC boundaries, data patterns, async APIs, metadata, error handling, route handlers, image/font optimization, bundling
Use when starting feature work that needs isolation from current workspace or before executing implementation plans - creates isolated git worktrees with smart directory selection and safety verification
Take cosmicstack-labs/clean-code from the repository into ~/.claude/skills for personal
use, or into .claude/skills inside a project.
The agent identifies a skill by the name field in its header. Two skills with the
same name cannot sit side by side — one of them will be ignored.