Code Simplification
Simplify code by reducing complexity while preserving exact behavior. The goal is not fewer lines — it's code that is easier to read, understand, modify, and debug. Every simplification must pass one test: "Would a new team member understand this faster than the original?"
When to use
- After a feature works and tests pass, but the implementation feels heavier than it needs to be
- During code review when readability or complexity issues are flagged
- When you encounter deeply nested logic, long functions, or unclear names
- After merging changes that introduced duplication or inconsistency
- Triggers on "simplify", "too complex", "refactor for clarity"
Not for: code you don't fully understand yet — comprehend before you simplify. Performance-critical code where the "simpler" version would be measurably slower. Throwaway code about to be rewritten entirely. Cross-module structural changes — extracting/moving modules, redrawing dependency boundaries, splitting or merging files → use refactoring. Designing where a seam or deep module should go (producing an audit, not executing) → use codebase-design. Single-file clarity stays here: naming, nesting, dead code.
Steps
1. Understand before touching (Chesterton's Fence)
Before changing or removing anything, understand why it exists. If you see a fence across a road and don't understand why it's there, don't tear it down.
- What is this code's responsibility? What calls it, what does it call?
- What are the edge cases and error paths? Are there tests defining expected behavior?
- Why might it have been written this way — performance? platform constraint? historical reason? Check
git blame for the original context.
If you can't answer these, you're not ready. Read more context first.
2. Identify simplification opportunities
Scan for concrete signals — each is a specific pattern, not a vague smell. The full tables (structural complexity, naming, redundancy) with examples are in references/opportunities.md. Summary:
- Structural: deep nesting (3+ levels), long functions (50+ lines), nested ternaries, boolean parameter flags, repeated conditionals.
- Naming: generic names (
data, temp, result), abbreviations (usr, cfg), misleading names, comments restating "what" instead of "why".
- Redundancy: duplicated logic, dead code, unnecessary abstractions, over-engineered patterns (factory-for-a-factory), redundant type assertions.
3. Apply the five principles
- Preserve behavior exactly. Same output for every input, same error behavior, same side effects and ordering, all existing tests pass without modification. If you're not sure a simplification preserves behavior, don't make it.
- Follow project conventions. Read CLAUDE.md; study how neighboring code handles similar patterns. Simplification that breaks project consistency is churn, not simplification.
- Prefer clarity over cleverness. Explicit code beats compact code when the compact version requires a mental pause to parse. A 1-line nested ternary is not simpler than a 5-line if/else.
- Maintain balance. Over-simplification is a failure mode: inlining too aggressively (removing a concept's name), combining unrelated logic into one complex function, removing abstractions that exist for extensibility or testability, optimizing for line count.
- Scope to what changed. Default to recently modified code. Avoid drive-by refactors of unrelated code unless explicitly asked to broaden scope — unscoped simplification creates noisy diffs and risks regressions.
4. Apply changes incrementally
One simplification at a time. Run the test suite after each change. The incremental-test,
separate-PR, and Rule-of-500 rules are in §9 (behavior-preserving change discipline) of
engineering-principles.md — apply them here.
- Make the change → run the suite + linter/formatter → pass: continue to the next; fail: revert and reconsider.
- Avoid batching multiple simplifications into one untested change. If something breaks, you need to know which simplification caused it.
5. Verify the result
Step back and evaluate the whole. Compare before and after:
- Is the simplified version genuinely easier to understand?
- Did you introduce any patterns inconsistent with the codebase?
- Is the diff clean and reviewable? Would a teammate approve?
If the "simplified" version is harder to understand or review than the original, revert. Not every simplification attempt succeeds.
Verify
Red flags: simplification that requires modifying tests to pass (you likely changed behavior); "simplified" code that is longer and harder to follow than the original; renaming to match personal preferences rather than project conventions; removing error handling because "it makes the code cleaner"; simplifying code you don't fully understand; batching many simplifications into one hard-to-review commit; refactoring outside the current task's scope without being asked.
References
- ${CLAUDE_PLUGIN_ROOT}/references/engineering-principles.md — shared discipline (enforce simplicity, surgical scope, verify don't assume)
- ${CLAUDE_PLUGIN_ROOT}/references/clean-code.md — meaningful names, small functions, comments, error handling (Uncle Bob)
- references/opportunities.md — full simplification-opportunities tables (structural / naming / redundancy) + language-specific examples (TypeScript, Python, React/JSX)
1---2name: simplify3description: Use when the code is too complex — clarity over cleverness, removes speculative abstractions, dead complexity, and earns-its-cost structures. Triggers on "simplify", "too complex", "refactor for clarity", "简化", "太复杂", "重构求清晰". Not for cross-module structural changes (use refactoring) or architecture audit (use codebase-design) — single-file clarity stays here.4---56# Code Simplification78Simplify code by reducing complexity while preserving exact behavior. The goal is not fewer lines — it's code that is easier to read, understand, modify, and debug. Every simplification must pass one test: "Would a new team member understand this faster than the original?"910## When to use1112- After a feature works and tests pass, but the implementation feels heavier than it needs to be13- During code review when readability or complexity issues are flagged14- When you encounter deeply nested logic, long functions, or unclear names15- After merging changes that introduced duplication or inconsistency16- Triggers on "simplify", "too complex", "refactor for clarity"1718**Not for:** code you don't fully understand yet — comprehend before you simplify. Performance-critical code where the "simpler" version would be measurably slower. Throwaway code about to be rewritten entirely. Cross-module structural changes — extracting/moving modules, redrawing dependency boundaries, splitting or merging files → use `refactoring`. Designing where a seam or deep module should go (producing an audit, not executing) → use `codebase-design`. Single-file clarity stays here: naming, nesting, dead code.1920## Steps2122### 1. Understand before touching (Chesterton's Fence)2324Before changing or removing anything, understand why it exists. If you see a fence across a road and don't understand why it's there, don't tear it down.2526- What is this code's responsibility? What calls it, what does it call?27- What are the edge cases and error paths? Are there tests defining expected behavior?28- Why might it have been written this way — performance? platform constraint? historical reason? Check `git blame` for the original context.2930If you can't answer these, you're not ready. Read more context first.3132### 2. Identify simplification opportunities3334Scan for concrete signals — each is a specific pattern, not a vague smell. The full tables (structural complexity, naming, redundancy) with examples are in `references/opportunities.md`. Summary:3536- **Structural:** deep nesting (3+ levels), long functions (50+ lines), nested ternaries, boolean parameter flags, repeated conditionals.37- **Naming:** generic names (`data`, `temp`, `result`), abbreviations (`usr`, `cfg`), misleading names, comments restating "what" instead of "why".38- **Redundancy:** duplicated logic, dead code, unnecessary abstractions, over-engineered patterns (factory-for-a-factory), redundant type assertions.3940### 3. Apply the five principles41421. **Preserve behavior exactly.** Same output for every input, same error behavior, same side effects and ordering, all existing tests pass without modification. If you're not sure a simplification preserves behavior, don't make it.432. **Follow project conventions.** Read CLAUDE.md; study how neighboring code handles similar patterns. Simplification that breaks project consistency is churn, not simplification.443. **Prefer clarity over cleverness.** Explicit code beats compact code when the compact version requires a mental pause to parse. A 1-line nested ternary is not simpler than a 5-line if/else.454. **Maintain balance.** Over-simplification is a failure mode: inlining too aggressively (removing a concept's name), combining unrelated logic into one complex function, removing abstractions that exist for extensibility or testability, optimizing for line count.465. **Scope to what changed.** Default to recently modified code. Avoid drive-by refactors of unrelated code unless explicitly asked to broaden scope — unscoped simplification creates noisy diffs and risks regressions.4748### 4. Apply changes incrementally4950One simplification at a time. Run the test suite after each change. The incremental-test,51separate-PR, and Rule-of-500 rules are in §9 (behavior-preserving change discipline) of52engineering-principles.md — apply them here.5354- Make the change → run the suite + linter/formatter → pass: continue to the next; fail: revert and reconsider.55- Avoid batching multiple simplifications into one untested change. If something breaks, you need to know which simplification caused it.5657### 5. Verify the result5859Step back and evaluate the whole. Compare before and after:6061- Is the simplified version genuinely easier to understand?62- Did you introduce any patterns inconsistent with the codebase?63- Is the diff clean and reviewable? Would a teammate approve?6465If the "simplified" version is harder to understand or review than the original, revert. Not every simplification attempt succeeds.6667## Verify6869- [ ] All existing tests pass without modification70- [ ] Build succeeds with no new warnings; linter/formatter passes (no style regressions)71- [ ] Each simplification is a reviewable, incremental change; the diff is clean — no unrelated changes mixed in72- [ ] Simplified code follows project conventions (checked against CLAUDE.md or equivalent)73- [ ] No error handling removed or weakened; no dead code left behind (unused imports, unreachable branches)74- [ ] The "simplified" code is genuinely easier to understand than the original7576**Red flags:** simplification that requires modifying tests to pass (you likely changed behavior); "simplified" code that is longer and harder to follow than the original; renaming to match personal preferences rather than project conventions; removing error handling because "it makes the code cleaner"; simplifying code you don't fully understand; batching many simplifications into one hard-to-review commit; refactoring outside the current task's scope without being asked.7778## References7980- [${CLAUDE_PLUGIN_ROOT}/references/engineering-principles.md](${CLAUDE_PLUGIN_ROOT}/references/engineering-principles.md) — shared discipline (enforce simplicity, surgical scope, verify don't assume)81- [${CLAUDE_PLUGIN_ROOT}/references/clean-code.md](${CLAUDE_PLUGIN_ROOT}/references/clean-code.md) — meaningful names, small functions, comments, error handling (Uncle Bob)82- [references/opportunities.md](references/opportunities.md) — full simplification-opportunities tables (structural / naming / redundancy) + language-specific examples (TypeScript, Python, React/JSX)