Community Refactoring Best Practices: Same Results, Less Code
Code-review and refactoring guide focused on the parts of code volume that come from judgment and modelling gaps — wrong abstraction choices, hidden semantic duplication, defensive habits, premature generality. This skill deliberately skips what linters and tools like knip, eslint, ruff, tsc --noUnusedLocals, or formatters already catch. It is the second pass: after the mechanical cleanup, what remains?
Core Principles
- Preserve behaviour. Every transformation must produce identical observable behaviour — same outputs, same errors, same side effects, same API surface.
- Earlier mistakes cascade. A wrong frame multiplies into wrong shapes, which multiply into duplicate logic. Optimise from the top of the lifecycle.
- Explain why, not just what. Each rule explains the cost of the anti-pattern so judgment can transfer to novel cases.
- Quantify where possible. Prefer "eliminates N lines / prevents X bug class" over "cleaner."
- Don't over-refactor. Rule of three: extract abstractions when duplication has actually appeared three times, not in anticipation.
When to Apply
Use this skill when:
- Reviewing a PR for "could this be simpler?" (the question linters can't answer)
- Refactoring code that has grown in volume without growing in capability
- Auditing a module that "feels heavy" — many flags, many layers, many checks
- Onboarding to an unfamiliar codebase and trying to spot the parts that are accidental volume vs essential complexity
- Designing a new module and wanting to avoid the common over-abstraction traps
- Working alongside knip / eslint / ruff and wanting the layer of judgment those tools can't supply
Don't use this skill for:
- Mechanical cleanup that a linter or formatter already does (unused imports, dead exports, style) — use
knip,eslint,ruff, orprettier/blackinstead. - Algorithmic complexity / performance tuning — use
complexity-optimizerfor that. - General cleanup of recently modified code regardless of mental-model gaps — use
code-simplifier.
Rule Categories by Priority
| # | Category | Prefix | Impact | Rules | Gist |
|---|---|---|---|---|---|
| 1 | Reinvention | reinvent- | CRITICAL | 5 | You wrote what the platform/stdlib already provides |
| 2 | Wrong Frame | frame- | CRITICAL | 5 | Wrong abstraction shape — class where a function fits, manager nouns, OO over data |
| 3 | Hidden Duplication | dup- | HIGH | 5 | Semantic copies hiding behind syntactic differences |
| 4 | Derived State Stored | derive- | HIGH | 5 | Storing what should be computed |
| 5 | Procedural Rebuilds | proc- | MEDIUM-HIGH | 5 | Imperative reimplementation of declarative concepts |
| 6 | Speculative Generality | spec- | MEDIUM | 5 | Generality built for a second user who never arrived |
| 7 | Defensive Excess | defense- | MEDIUM | 4 | Checks for states the type/flow already rules out |
| 8 | Type System Underuse | types- | LOW-MEDIUM | 6 | Runtime guards that should be types |
Quick Reference
1. Reinvention (CRITICAL)
reinvent-stdlib-collection-ops— Reach for.map/.filter/.reducebefore writing loopsreinvent-date-and-time— Stop hand-rolling date and time arithmeticreinvent-deep-equality— Use a real deep-equal instead of hand-recursing objectsreinvent-explicit-state-machine— Surface a state machine instead of boolean flag jugglingreinvent-builtin-data-structures— Recognise when a custom container is just a Map, Set, or Queue
2. Wrong Frame (CRITICAL)
frame-function-not-class— Use a function when the class has no identityframe-manager-noun-is-a-verb— Rename Manager/Helper/Util classes until the real verb appearsframe-composition-over-inheritance-for-shared-fields— Compose shared fields instead of inheritingframe-data-over-procedure— Model the problem as data before writing procedureframe-monolith-by-cohesive-axis— Split a god-function along its cohesive axis, not by line count
3. Hidden Duplication (HIGH)
dup-parallel-types-same-shape— Collapse parallel types that share a shapedup-near-twin-functions— Parameterize two functions that differ by a literaldup-mirrored-branches— Lift shared lines out of mirrored if/else branchesdup-config-not-copies— Replace many hardcoded copies with one tabledup-cross-layer-shape— Collapse identical DTOs, DB rows, and domain objects
4. Derived State Stored (HIGH)
derive-dont-store-computed— Compute what you can compute; store only what you can'tderive-single-source-of-truth— Pick one source of truth; derive the restderive-boolean-from-data— Derive booleans from the data, don't track them separatelyderive-cache-as-getter-not-field— Turn cached fields into getters until profiling proves otherwisederive-url-as-state— Let the URL or route be the state, not a mirror of it
5. Procedural Rebuilds (MEDIUM-HIGH)
proc-mutation-builder-over-pipeline— Compose pipelines when the mutation-builder hides the intentproc-if-chain-as-lookup— Replace if/elif returning constants with a lookup tableproc-manual-recursion-of-walk— Use a recognised tree/object walk, not hand-coded recursionproc-build-vs-declarative-template— Use the declarative form when the framework provides oneproc-sequential-awaits-could-be-parallel— Parallelise independent awaits
6. Speculative Generality (MEDIUM)
spec-interface-of-one— Avoid defining an interface for a single implementationspec-options-bag-of-one— Avoid options bags where every caller passes the same valuesspec-flag-driven-paths— Split a function that a boolean flag has made into twospec-no-extension-point-without-extender— Delete extension points that have no second userspec-generic-over-one-type— Drop the generic parameter when only one concrete type uses it
7. Defensive Excess (MEDIUM)
defense-guard-against-impossible— Stop guarding against states the type/flow already rules outdefense-validate-once-at-boundary— Validate once at the boundary, trust insidedefense-let-it-throw— Let exceptions propagate; don't catch what you can't handledefense-null-pollution-from-bad-modelling— Fix the type that makes the null checks necessary
8. Type System Underuse (LOW-MEDIUM)
types-discriminated-union-over-flags— Use a discriminated union instead of optional fields + tagstypes-literal-union-over-string— Narrowstringdown to a literal union when the set is closedtypes-no-any-to-silence— Avoid reaching forany/asto silence a type errortypes-branding-over-runtime-checks— Brand a validated value so you don't validate it twicetypes-exhaustive-switch-not-default— Use exhaustiveness checks instead of a catch-all defaulttypes-readonly-and-immutable-by-default— Mark datareadonlyuntil mutation is actually needed
How to Apply (Workflow)
When asked to review or refactor code with this skill:
- Run the mechanical pass first.
knip/eslint/ruff/tsc --noUnusedLocalswill catch dead code, unused imports, style. Don't duplicate that work here. - Read the file or PR for intent. Ask: what is this code trying to do? The judgment skill is recognising when the implementation overshoots the intent.
- Walk the categories in priority order.
- Start with Reinvention and Frame — the biggest wins live there.
- Then Duplication and Derived state.
- Then Procedural rebuilds and Speculative generality.
- Defensive and type-system issues last — they're high frequency but localised.
- Propose minimal-diff transformations. Each rule shows incorrect → correct as a tight diff; preserve that property in suggestions.
- Verify behaviour. Outputs, errors, and side effects must be identical. Tests must still pass.
- Don't bundle unrelated changes. Each transformation should map to one category. Mixing them makes the change hard to review.
When NOT to Apply
- Code is younger than the rule of three (one or two duplicates) — extracting is premature.
- The pattern is genuinely a known exception (see each rule's "When NOT to use this pattern" section).
- The refactor would be a large, risky rewrite without a clear test safety net — propose, don't execute.
- Performance-critical hot paths where the "simpler" form has measurable cost — measure first.
Reference Files
| File | Description |
|---|---|
| references/_sections.md | Category definitions and ordering |
| assets/templates/_template.md | Template for new rules |
| metadata.json | Version and reference information |
Related Skills
code-simplifier— Mechanical simplification (naming, dead code, nesting). Complementary first pass.complexity-optimizer— Algorithmic/performance complexity. Different axis.refactor— General-purpose refactoring workflow.clean-code— Broader clean-code principles. This skill is the narrower, judgment-focused subset.