Claude-skill-registry cleanCode
Refactor/clean/simplify code - eliminate duplication, small functions, readable names. USE WHEN user says "clean", "simplify", "refactor", "readable", "messy", "complex", or code has >15 line functions or copy-paste.
git clone https://github.com/majiayu000/claude-skill-registry
T=$(mktemp -d) && git clone --depth=1 https://github.com/majiayu000/claude-skill-registry "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/data/cleanCode" ~/.claude/skills/majiayu000-claude-skill-registry-cleancode && rm -rf "$T"
skills/data/cleanCode/SKILL.mdCode Simplification
Core principle: Code reads like English prose.
Influences: Douglas Crockford's "JavaScript: The Good Parts", Robert C. Martin's "Clean Code"
🚨 TypeScript: Before writing TypeScript, run
/cleanTypes for type annotation best practices.
1. Small Functions, Clear Names
Target: 3-15 lines per function. Name describes exactly what it does.
// Bad: Generic name, does multiple things (40 lines) function process(filename) { ... } // Good: Small functions with precise names const extractExtension = (filename) => filename.replace(/.*symlink/, '') const removeSymlinkAndExtension = (filename) => filename.replace(/\.symlink.*$/, '') const replaceDOTWithDot = (str) => str.replace(/DOT/g, '.')
Naming rules:
- Verbs for actions:
,createLink()handleExistingFile() - Booleans:
,isSymlink()
,hasExtension()canWrite() - No generic names:
,process()
,handle()
→ What specifically?do()
2. No Duplication
If you copy-paste code, stop. Extract a function.
// Bad: 3 similar blocks, 40 lines each function renderIdentity(json) { /* extract fields, print */ } function renderCard(json) { /* extract fields, print */ } function renderLogin(json) { /* extract fields, print */ } // Good: Extract common pattern function renderEntry(json) { const fields = extractFields(json) fields.forEach(field => printField(field)) }
3. Iterate the Source, Not Type Dispatch
Red flag: Multiple
extractTypeA(), extractTypeB(), extractTypeC() functions.
Instead: Iterate the data structure directly.
// Bad: Type-specific extractors + dispatch const extractIdentity = (json) => [/* hardcode identity fields */] const extractCard = (json) => [/* hardcode card fields */] const extractLogin = (json) => [/* hardcode login fields */] if (isIdentity(json)) return extractIdentity(json) if (isCard(json)) return extractCard(json) return extractLogin(json) // Good: Generic extraction - iterate what exists const extractFields = (json) => Object.entries(json.data || {}) .filter(([key, value]) => value && typeof value === 'string') .map(([key, value]) => ({ label: humanizeKey(key), displayValue: shouldMask(key) ? '•••' : value })) // Works for all types, no type checking
Key insight: Don't ask "what type is this?" Ask "what data exists?"
4. Module Splitting: ~250 Lines
When a file exceeds 250 lines, look for natural module boundaries.
// Before: links.ts - 247 lines (path utils + file ops + handlers + class + orchestration) // After: Split by responsibility // symlink/path-transform.ts - 23 lines // symlink/file-ops.ts - 40 lines // symlink/handlers.ts - 43 lines // symlink/operation.ts - 76 lines // links.ts - 77 lines (orchestration only)
Don't split prematurely: 200-line focused file > 5 poorly-abstracted 40-line files.
5. Fluent APIs for Sequential Operations
Chain methods to describe operations in natural language.
// Bad: Imperative control flow, needs comments function safeLink(src: string, dest: string | null) { // Handle unparseable destination if (!dest) return { ... } // Handle existing symlink if (isSymlink(dest)) { ... } // Handle existing file if (fileExists(dest)) { ... } // Create symlink fs.mkdirSync(...) return createLink(src, dest) } // Good: Reads like English, no comments needed const safeLink = (src: string, dest: string | null) => new SymlinkOperation(src, dest) .handleNullDestination() .handleSymlink() .handleExistingFile() .createSymlink() .result()
Implementation pattern:
class Operation { private result: Result | null = null step1() { if (this.result) return this // Short-circuit if done // Check condition, maybe set this.result return this } result() { return this.result! } }
When to use: Sequential operations with decision points, each step is a clear named concern.
6. Explicit Failures Over Silent Filtering
Make failures visible with error results, don't silently skip.
// Bad: Silent failure - lost information function buildPlan() { return files.map(transformPath).filter(path => path !== null) } // Which files failed? Unknown. // Good: Explicit failure - trackable function buildPlan() { return files.map(file => ({ from: file, to: transformPath(file) })) } function executePlan(plan: Array<{from: string, to: string | null}>) { return plan.map(({ from, to }) => safeLink(from, to)) } function safeLink(src: string, dest: string | null) { if (!dest) return { from: src, to: '<unparseable>', success: false } // ... continue } // Now: results.filter(r => !r.success).length shows exactly what failed
7. Eliminate Special Cases
Every special case must justify its existence. Default to uniform handling.
// Bad: Unnecessary special case if (files.length === 1) { return handleSingleFile(files[0]) } else { return handleMultipleFiles(files) } // Good: Unified handling (works for n=1 too) return files.map(handleFile)
Ask: "What if I handle both cases uniformly?"
8. Arrow Functions for Simple Transformations
// Bad: Verbose function executeSymlinkPlan(plan: SymlinkPlan[]): LinkResult[] { const results: LinkResult[] = [] for (const { from, to } of plan) { results.push(safeLink(from, to)) } return results } // Good: Concise const executeSymlinkPlan = (plan: SymlinkPlan[]) => plan.map(({ from, to }) => safeLink(from, to))
Note side effects: Add comment if
.map() has side effects (creates files, mutates state).
Refactoring Checklist
Before code is "done":
- Function names read like English? Should describe exactly what they do
- Any copy-pasted code? Extract to function
- Multiple extractType functions? Replace with
Object.entries(source).map() - Any function >20 lines? Break into subfunctions
- File >250 lines? Look for natural module boundaries
- Sequential operations with branches? Consider fluent API
- Silently filtering failures? Make them explicit with error results
- Special cases that can be unified? Handle uniformly when possible
Complexity Limits
- Function >25 lines → Extract subfunctions
- File >250 lines → Consider splitting by responsibility
- Nested blocks >2 deep → Extract function
Self-prompt: "Do I have extractTypeA/B/C functions? Can I iterate the source instead? Would a fluent API make this read better? Are failures explicit? Does the code read like English?"