Claude-skill-registry backend-simplicity-engineer
Backend engineer focused on simplicity, bug elimination, and clean code. Use when user mentions "simplify backend", "fix backend bugs", "clean up code", or "make backend perfect".
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/backend-simplicity-engineer" ~/.claude/skills/majiayu000-claude-skill-registry-backend-simplicity-engineer && rm -rf "$T"
skills/data/backend-simplicity-engineer/SKILL.mdBackend Simplicity Engineer
Philosophy: Simple, bug-free, maintainable code. Zero complexity for complexity's sake.
When to Use
Invoke this skill when:
- User mentions: "simplify backend", "fix bugs", "clean up code"
- Backend has complex, hard-to-understand code
- Too many abstractions or over-engineering
- Bug reports or error logs
- Performance issues
- Code review before deployment
Simplicity-First Methodology
Core Principles
- KISS - Keep It Simple, Stupid
- YAGNI - You Aren't Gonna Need It
- DRY - Don't Repeat Yourself (but don't over-abstract)
- Zero Bugs - Test everything, fix immediately
- Readable - Code is read 10x more than written
Phase 1: Code Complexity Audit
1A. Cyclomatic Complexity Check
# Find overly complex functions # Complexity > 10 = needs refactoring # Simple check: count if/else/while/for/switch grep -rn "if\|else\|while\|for\|switch" src/ --include="*.ts" | \ awk -F: '{print $1}' | uniq -c | sort -rn | head -20 # Look for deeply nested code (>3 levels) grep -rn " if.*if.*if" src/ --include="*.ts"
1B. Code Duplication Detection
# Find duplicate code blocks # Use: jscpd (install: npm i -g jscpd) npx jscpd src/ --min-lines 5 --min-tokens 50 # Manual check for similar patterns grep -rn "export.*function" src/ --include="*.ts" | \ awk -F: '{print $3}' | sort | uniq -c | sort -rn
1C. Dependency Graph Analysis
// Check for circular dependencies // Use: madge (install: npm i -g madge) // npx madge --circular src/ // Check for God Objects (too many dependencies) // File with >10 imports = probably doing too much grep -c "^import" src/**/*.ts | awk -F: '$2 > 10 {print $1 " has " $2 " imports"}'
Phase 2: Research Simplification Patterns
Launch codex-deep-research agent:
Invoke Task tool with subagent_type="codex-deep-research" Prompt: "Research the best code simplification patterns and refactoring techniques for a TypeScript + Express.js backend. Context: - Project Conductor has 12 APIs, 100+ endpoints - Uses: Express.js, PostgreSQL, Redis, Socket.io - Current issues: Too many 'any' types, console.log usage, complex controllers - Goal: Simple, maintainable, bug-free code Provide refactoring patterns for: 1. **Controller Simplification** - How to keep controllers thin (max 20 lines per method) - Single responsibility principle - Proper error handling without try-catch hell - Input validation patterns 2. **Service Layer Organization** - When to create a service vs inline logic - Avoiding God Services - Dependency injection patterns - Testing strategies 3. **Error Handling** - Centralized error handling - Custom error classes vs generic - Error logging best practices - User-friendly error messages 4. **Database Queries** - Query builders vs raw SQL - Connection pool management - Transaction patterns - Avoiding N+1 queries 5. **Code Organization** - File structure conventions - Module boundaries - When to split vs combine - Import/export patterns 6. **TypeScript Best Practices** - Eliminating 'any' types - Proper type inference - Generics vs type assertions - Interface vs type 7. **Testing for Simplicity** - Unit test patterns - Mocking strategies - Integration test boundaries - Test coverage targets Provide before/after code examples for each pattern."
Check for AI code analysis tools:
Invoke Task tool with subagent_type="gemini-research-analyst" Prompt: "Research if Google's Gemini AI provides any code simplification, refactoring, or quality analysis tools for TypeScript backends. Investigate: 1. Gemini-powered code review 2. Automated refactoring suggestions 3. Complexity analysis 4. Bug detection 5. Performance profiling 6. Security vulnerability scanning 7. Code generation (to replace boilerplate) If available: - How to integrate with TypeScript + Express.js - Accuracy compared to ESLint/SonarQube - Cost and performance - Production readiness"
Phase 3: Bug Hunting & Elimination
3A. Runtime Error Detection
# Check logs for errors if [ -f logs/error.log ]; then echo "Recent errors:" tail -100 logs/error.log | grep -i "error\|exception\|failed" fi # Check for unhandled promise rejections grep -rn "Promise\|async" src/ --include="*.ts" | \ xargs -I {} sh -c 'echo {}; grep -A 5 "{}" | grep -c "catch"' # Find missing await keywords grep -rn "async function" src/ --include="*.ts" -A 10 | \ grep -v "await" | grep -B 1 "Promise"
3B. Type Safety Issues
# Find all 'any' types (must be eliminated) grep -rn ": any" src/ --include="*.ts" | wc -l # Goal: 0 # Find implicit any npx tsc --noImplicitAny --noEmit # Find non-null assertions (! operator - dangerous) grep -rn "!" src/ --include="*.ts" | grep -v "!=" | grep -v "!==" | wc -l # Goal: <5
3C. Common Bug Patterns
// Pattern 1: Missing null checks // Bad function getUser(id: string) { const user = users.find(u => u.id === id); return user.name; // Error if user is undefined } // Good function getUser(id: string) { const user = users.find(u => u.id === id); if (!user) { throw new NotFoundError(`User ${id} not found`); } return user.name; } // Pattern 2: Async/await missing // Bad function loadData() { fetchData().then(data => { processData(data).then(result => { saveData(result); // Callback hell }); }); } // Good async function loadData() { const data = await fetchData(); const result = await processData(data); await saveData(result); } // Pattern 3: Error swallowing // Bad try { await riskyOperation(); } catch (error) { // Silently fails - very bad! } // Good try { await riskyOperation(); } catch (error) { logger.error('Risky operation failed', { error }); throw new OperationError('Failed to complete operation', { cause: error }); } // Pattern 4: Race conditions // Bad let counter = 0; async function increment() { const current = counter; await delay(100); counter = current + 1; // Lost updates! } // Good let counter = 0; const lock = new Mutex(); async function increment() { await lock.acquire(); try { counter++; } finally { lock.release(); } }
Phase 4: Simplification Refactoring
4A. Controller Simplification
// BEFORE: Complex controller (60 lines, multiple responsibilities) export class RequirementsController { async getRequirements(req: Request, res: Response) { try { const page = parseInt(req.query.page as string) || 1; const limit = parseInt(req.query.limit as string) || 10; const sortBy = (req.query.sortBy as string) || 'createdAt'; const sortOrder = (req.query.sortOrder as 'asc' | 'desc') || 'desc'; if (page < 1) { return res.status(400).json({ error: 'Invalid page' }); } if (limit < 1 || limit > 100) { return res.status(400).json({ error: 'Invalid limit' }); } const offset = (page - 1) * limit; const result = await this.db.query( 'SELECT * FROM requirements ORDER BY $1 $2 LIMIT $3 OFFSET $4', [sortBy, sortOrder, limit, offset] ); const total = await this.db.query('SELECT COUNT(*) FROM requirements'); res.json({ success: true, data: result.rows, pagination: { page, limit, total: total.rows[0].count, pages: Math.ceil(total.rows[0].count / limit) } }); } catch (error: any) { console.error(error); res.status(500).json({ error: 'Internal server error' }); } } } // AFTER: Simple controller (15 lines, single responsibility) export class RequirementsController { constructor(private service: RequirementsService) {} async getRequirements(req: Request, res: Response) { const params = validatePaginationParams(req.query); const result = await this.service.getRequirements(params); res.json({ success: true, data: result.requirements, pagination: result.pagination }); } } // Validation moved to middleware function validatePaginationParams(query: any): PaginationParams { const schema = z.object({ page: z.coerce.number().int().min(1).default(1), limit: z.coerce.number().int().min(1).max(100).default(10), sortBy: z.string().default('createdAt'), sortOrder: z.enum(['asc', 'desc']).default('desc') }); return schema.parse(query); } // Business logic moved to service class RequirementsService { async getRequirements(params: PaginationParams) { const requirements = await this.repo.findAll(params); const total = await this.repo.count(); return { requirements, pagination: { page: params.page, limit: params.limit, total, pages: Math.ceil(total / params.limit) } }; } }
4B. Eliminate 'any' Types
// BEFORE: any types everywhere async function createRequirement(data: any): Promise<any> { const result = await db.query('INSERT INTO requirements ...', data); return result.rows[0]; } // AFTER: Proper types interface CreateRequirementRequest { title: string; description: string; priority: 'low' | 'medium' | 'high'; assigneeId?: string; } interface Requirement extends CreateRequirementRequest { id: string; status: 'draft' | 'approved' | 'rejected'; createdAt: Date; updatedAt: Date; } async function createRequirement( data: CreateRequirementRequest ): Promise<Requirement> { const result = await db.query<Requirement>( 'INSERT INTO requirements (title, description, priority, assignee_id) VALUES ($1, $2, $3, $4) RETURNING *', [data.title, data.description, data.priority, data.assigneeId] ); return result.rows[0]; }
4C. Replace console.log with Logger
// BEFORE: console.log everywhere console.log('User logged in:', userId); console.error('Failed to save:', error); // AFTER: Structured logging import logger from './logger'; logger.info('User logged in', { userId }); logger.error('Failed to save requirement', { error: error.message, stack: error.stack, requirementId }); // logger.ts - Simple Pino setup import pino from 'pino'; export const logger = pino({ level: process.env.LOG_LEVEL || 'info', transport: { target: 'pino-pretty', options: { colorize: true, translateTime: 'SYS:standard', ignore: 'pid,hostname' } } });
4D. Centralized Error Handling
// BEFORE: try-catch in every controller async handler(req: Request, res: Response) { try { const result = await service.doSomething(); res.json(result); } catch (error) { res.status(500).json({ error: 'Something went wrong' }); } } // AFTER: Centralized error middleware // Custom error classes export class AppError extends Error { constructor( message: string, public statusCode: number = 500, public isOperational: boolean = true ) { super(message); Object.setPrototypeOf(this, AppError.prototype); } } export class NotFoundError extends AppError { constructor(message: string) { super(message, 404); } } export class ValidationError extends AppError { constructor(message: string) { super(message, 400); } } // Error middleware export function errorHandler( error: Error, req: Request, res: Response, next: NextFunction ) { if (error instanceof AppError) { return res.status(error.statusCode).json({ success: false, message: error.message }); } // Unexpected errors logger.error('Unexpected error', { error: error.stack }); res.status(500).json({ success: false, message: 'Internal server error' }); } // Controllers become simple async handler(req: Request, res: Response) { const result = await service.doSomething(); res.json({ success: true, data: result }); } // Errors propagate to middleware automatically
Phase 5: Code Quality Automation
5A. ESLint Configuration
// .eslintrc.json - Enforce simplicity { "extends": [ "eslint:recommended", "@typescript-eslint/recommended" ], "rules": { "@typescript-eslint/no-explicit-any": "error", "@typescript-eslint/explicit-function-return-type": "warn", "complexity": ["error", 10], "max-depth": ["error", 3], "max-lines-per-function": ["warn", 50], "max-params": ["error", 4], "no-console": "error", "no-duplicate-imports": "error", "prefer-const": "error", "no-var": "error" } }
5B. Pre-commit Hooks
# Install husky npm install --save-dev husky # Add pre-commit hook cat > .husky/pre-commit << 'EOF' #!/bin/sh . "$(dirname "$0")/_/husky.sh" # Run linting npm run lint # Run type checking npm run typecheck # Run tests npm test # Block commit if any fail EOF chmod +x .husky/pre-commit
5C. Automated Testing
// Simple, readable tests describe('RequirementsService', () => { describe('createRequirement', () => { it('should create requirement with valid data', async () => { const data = { title: 'New Feature', description: 'Add user authentication', priority: 'high' as const }; const result = await service.createRequirement(data); expect(result).toMatchObject(data); expect(result.id).toBeDefined(); expect(result.status).toBe('draft'); }); it('should throw ValidationError for invalid priority', async () => { const data = { title: 'Feature', description: 'Description', priority: 'invalid' as any }; await expect(service.createRequirement(data)) .rejects .toThrow(ValidationError); }); it('should throw ValidationError for empty title', async () => { const data = { title: '', description: 'Description', priority: 'medium' as const }; await expect(service.createRequirement(data)) .rejects .toThrow(ValidationError); }); }); });
Phase 6: Performance Simplification
6A. Database Query Optimization
// BEFORE: N+1 query problem async function getProjectsWithRequirements() { const projects = await db.query('SELECT * FROM projects'); for (const project of projects.rows) { project.requirements = await db.query( 'SELECT * FROM requirements WHERE project_id = $1', [project.id] ); // N queries! } return projects.rows; } // AFTER: Single JOIN query async function getProjectsWithRequirements() { const result = await db.query(` SELECT p.*, json_agg(r.*) as requirements FROM projects p LEFT JOIN requirements r ON r.project_id = p.id GROUP BY p.id `); return result.rows; }
6B. Caching Strategy
// Simple Redis caching wrapper class CachedService { constructor( private redis: Redis, private ttl: number = 300 // 5 minutes ) {} async get<T>(key: string, fetcher: () => Promise<T>): Promise<T> { // Try cache first const cached = await this.redis.get(key); if (cached) { return JSON.parse(cached); } // Cache miss - fetch and cache const data = await fetcher(); await this.redis.setex(key, this.ttl, JSON.stringify(data)); return data; } async invalidate(key: string) { await this.redis.del(key); } } // Usage async getRequirements(params: PaginationParams) { const cacheKey = `requirements:${JSON.stringify(params)}`; return this.cache.get(cacheKey, async () => { return this.repo.findAll(params); }); }
Phase 7: Documentation & Maintainability
7A. Self-Documenting Code
// BEFORE: Needs comments async function processReqs(data: any) { // Validate input if (!data.title || data.title.length < 3) { throw new Error('Invalid'); } // Save to DB const result = await this.db.query('INSERT INTO...'); // Send notification await this.sendEmail(data.assignee, 'New req'); return result; } // AFTER: Self-explanatory names, no comments needed async function createRequirement(request: CreateRequirementRequest) { validateRequirementRequest(request); const requirement = await this.repository.save(request); await this.notifier.notifyAssignee(requirement); return requirement; }
7B. API Documentation
/** * Create a new requirement * * @param request - Requirement data * @returns Created requirement with ID and timestamps * @throws ValidationError if request is invalid * @throws DatabaseError if save fails * * @example * ```typescript * const requirement = await service.createRequirement({ * title: 'Add authentication', * description: 'Implement JWT-based auth', * priority: 'high' * }); * ``` */ async createRequirement( request: CreateRequirementRequest ): Promise<Requirement> { // Implementation }
Validation Checklist
Before marking backend as "simple and bug-free":
Code Quality
- Zero 'any' types (all properly typed)
- Zero console.log (use logger)
- Zero try-catch blocks in controllers (use error middleware)
- No functions >50 lines
- No files >300 lines
- No circular dependencies
- Cyclomatic complexity <10 per function
Bug Prevention
- All async functions have await or return Promise
- All Promises have .catch() or try-catch
- All user input is validated
- All database queries use parameterized queries (SQL injection safe)
- All null/undefined cases handled
- No race conditions
- No memory leaks (event listeners cleaned up)
Testing
- >75% code coverage
- All critical paths have tests
- All error cases have tests
- Integration tests for all APIs
- No flaky tests
Performance
- No N+1 queries
- Caching implemented where appropriate
- Database indexes on query columns
- Connection pooling configured
- API response time <200ms (p95)
Maintainability
- Clear file structure
- Consistent naming conventions
- Self-documenting code
- API documentation complete
- README up to date
- No dead code
Output Format
After backend audit, provide:
## Backend Simplicity Audit Report **Status**: [SIMPLE ✅ / NEEDS REFACTORING ⚠️ / COMPLEX ❌] ### Complexity Metrics - Total 'any' types: [count] (target: 0) - console.log usage: [count] (target: 0) - Functions >50 lines: [count] (target: 0) - Files >300 lines: [count] (target: <3) - Cyclomatic complexity: [avg] (target: <10) - Test coverage: [%] (target: >75%) ### Bugs Found #### Critical Bugs 🔴 1. [Bug description] - Location: [file:line] - Impact: [What breaks] - Fix: [Code change needed] #### Potential Bugs 🟡 1. [Issue description] - Location: [file:line] - Risk: [What could break] - Prevention: [Code change] ### Simplification Opportunities #### High Priority 1. [Complex code section] - Current complexity: [metric] - Suggested refactoring: [pattern] - Estimated effort: [hours] #### Medium Priority 1. [Optimization opportunity] - Current approach: [description] - Simpler approach: [alternative] - Benefit: [why simpler is better] ### Code Quality Score - Simplicity: [X/10] - Bug-Free: [X/10] - Maintainability: [X/10] - Performance: [X/10] - Test Coverage: [X/10] **Overall**: [X/50] - [Grade: A+ to F] ### Refactoring Plan #### Phase 1: Bug Fixes (Week 1) - [ ] Fix critical bugs - [ ] Add missing error handling - [ ] Fix type safety issues #### Phase 2: Simplification (Week 2) - [ ] Eliminate 'any' types - [ ] Replace console.log with logger - [ ] Refactor complex functions - [ ] Add missing tests #### Phase 3: Optimization (Week 3) - [ ] Fix N+1 queries - [ ] Add caching - [ ] Optimize database indexes - [ ] Performance profiling ### Code Examples [Provide specific before/after refactoring examples]
Example Usage
User: "Simplify the backend and eliminate bugs"
This skill will:
- Audit all TypeScript files for complexity
- Find all bugs (null checks, async/await, race conditions)
- Research simplification patterns
- Detect code duplication
- Check type safety (eliminate 'any')
- Validate error handling
- Test coverage analysis
- Generate refactoring plan with specific code changes
- Implement fixes if requested
- Verify with automated tests