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, or prettier/black instead.
- Algorithmic complexity / performance tuning — use
complexity-optimizer for 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/.reduce before writing loops
reinvent-date-and-time — Stop hand-rolling date and time arithmetic
reinvent-deep-equality — Use a real deep-equal instead of hand-recursing objects
reinvent-explicit-state-machine — Surface a state machine instead of boolean flag juggling
reinvent-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 identity
frame-manager-noun-is-a-verb — Rename Manager/Helper/Util classes until the real verb appears
frame-composition-over-inheritance-for-shared-fields — Compose shared fields instead of inheriting
frame-data-over-procedure — Model the problem as data before writing procedure
frame-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 shape
dup-near-twin-functions — Parameterize two functions that differ by a literal
dup-mirrored-branches — Lift shared lines out of mirrored if/else branches
dup-config-not-copies — Replace many hardcoded copies with one table
dup-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't
derive-single-source-of-truth — Pick one source of truth; derive the rest
derive-boolean-from-data — Derive booleans from the data, don't track them separately
derive-cache-as-getter-not-field — Turn cached fields into getters until profiling proves otherwise
derive-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 intent
proc-if-chain-as-lookup — Replace if/elif returning constants with a lookup table
proc-manual-recursion-of-walk — Use a recognised tree/object walk, not hand-coded recursion
proc-build-vs-declarative-template — Use the declarative form when the framework provides one
proc-sequential-awaits-could-be-parallel — Parallelise independent awaits
6. Speculative Generality (MEDIUM)
spec-interface-of-one — Avoid defining an interface for a single implementation
spec-options-bag-of-one — Avoid options bags where every caller passes the same values
spec-flag-driven-paths — Split a function that a boolean flag has made into two
spec-no-extension-point-without-extender — Delete extension points that have no second user
spec-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 out
defense-validate-once-at-boundary — Validate once at the boundary, trust inside
defense-let-it-throw — Let exceptions propagate; don't catch what you can't handle
defense-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 + tags
types-literal-union-over-string — Narrow string down to a literal union when the set is closed
types-no-any-to-silence — Avoid reaching for any/as to silence a type error
types-branding-over-runtime-checks — Brand a validated value so you don't validate it twice
types-exhaustive-switch-not-default — Use exhaustiveness checks instead of a catch-all default
types-readonly-and-immutable-by-default — Mark data readonly until 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 --noUnusedLocals will 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.
1---
2name: same-results-less-code
3description: Same behaviour in fewer, clearer lines — covers the judgment gaps that linters cannot catch (reinvention, wrong frame, hidden duplication, derived state, procedural rebuilds, speculative generality, defensive excess, type-system underuse). Trigger when reviewing, refactoring, or simplifying code — and even when the user doesn't explicitly ask for "simplification" but is reviewing code, refactoring, or asking "is there a shorter way to write this?". Complements knip/eslint/ruff/tsc by focusing on the conceptual modelling layer those tools cannot see.
4---
5
6# Community Refactoring Best Practices: Same Results, Less Code
7
8Code-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?
9
10## Core Principles
11
121. **Preserve behaviour.** Every transformation must produce identical observable behaviour — same outputs, same errors, same side effects, same API surface.
132. **Earlier mistakes cascade.** A wrong frame multiplies into wrong shapes, which multiply into duplicate logic. Optimise from the top of the lifecycle.
143. **Explain why, not just what.** Each rule explains the cost of the anti-pattern so judgment can transfer to novel cases.
154. **Quantify where possible.** Prefer "eliminates N lines / prevents X bug class" over "cleaner."
165. **Don't over-refactor.** Rule of three: extract abstractions when duplication has actually appeared three times, not in anticipation.
17
18## When to Apply
19
20Use this skill when:
21
22- Reviewing a PR for "could this be simpler?" (the question linters can't answer)
23- Refactoring code that has grown in volume without growing in capability
24- Auditing a module that "feels heavy" — many flags, many layers, many checks
25- Onboarding to an unfamiliar codebase and trying to spot the parts that are accidental volume vs essential complexity
26- Designing a new module and wanting to avoid the common over-abstraction traps
27- Working alongside knip / eslint / ruff and wanting the layer of judgment those tools can't supply
28
29**Don't use this skill for:**
30
31- Mechanical cleanup that a linter or formatter already does (unused imports, dead exports, style) — use `knip`, `eslint`, `ruff`, or `prettier`/`black` instead.
32- Algorithmic complexity / performance tuning — use [`complexity-optimizer`](../complexity-optimizer/) for that.
33- General cleanup of recently modified code regardless of mental-model gaps — use [`code-simplifier`](../../.curated/code-simplifier/).
34
35## Rule Categories by Priority
36
37| # | Category | Prefix | Impact | Rules | Gist |
38|---|----------|--------|--------|-------|------|
39| 1 | Reinvention | `reinvent-` | CRITICAL | 5 | You wrote what the platform/stdlib already provides |
40| 2 | Wrong Frame | `frame-` | CRITICAL | 5 | Wrong abstraction shape — class where a function fits, manager nouns, OO over data |
41| 3 | Hidden Duplication | `dup-` | HIGH | 5 | Semantic copies hiding behind syntactic differences |
42| 4 | Derived State Stored | `derive-` | HIGH | 5 | Storing what should be computed |
43| 5 | Procedural Rebuilds | `proc-` | MEDIUM-HIGH | 5 | Imperative reimplementation of declarative concepts |
44| 6 | Speculative Generality | `spec-` | MEDIUM | 5 | Generality built for a second user who never arrived |
45| 7 | Defensive Excess | `defense-` | MEDIUM | 4 | Checks for states the type/flow already rules out |
46| 8 | Type System Underuse | `types-` | LOW-MEDIUM | 6 | Runtime guards that should be types |
47
48## Quick Reference
49
50### 1. Reinvention (CRITICAL)
51
52- [`reinvent-stdlib-collection-ops`](references/reinvent-stdlib-collection-ops.md) — Reach for `.map`/`.filter`/`.reduce` before writing loops
53- [`reinvent-date-and-time`](references/reinvent-date-and-time.md) — Stop hand-rolling date and time arithmetic
54- [`reinvent-deep-equality`](references/reinvent-deep-equality.md) — Use a real deep-equal instead of hand-recursing objects
55- [`reinvent-explicit-state-machine`](references/reinvent-explicit-state-machine.md) — Surface a state machine instead of boolean flag juggling
56- [`reinvent-builtin-data-structures`](references/reinvent-builtin-data-structures.md) — Recognise when a custom container is just a Map, Set, or Queue
57
58### 2. Wrong Frame (CRITICAL)
59
60- [`frame-function-not-class`](references/frame-function-not-class.md) — Use a function when the class has no identity
61- [`frame-manager-noun-is-a-verb`](references/frame-manager-noun-is-a-verb.md) — Rename Manager/Helper/Util classes until the real verb appears
62- [`frame-composition-over-inheritance-for-shared-fields`](references/frame-composition-over-inheritance-for-shared-fields.md) — Compose shared fields instead of inheriting
63- [`frame-data-over-procedure`](references/frame-data-over-procedure.md) — Model the problem as data before writing procedure
64- [`frame-monolith-by-cohesive-axis`](references/frame-monolith-by-cohesive-axis.md) — Split a god-function along its cohesive axis, not by line count
65
66### 3. Hidden Duplication (HIGH)
67
68- [`dup-parallel-types-same-shape`](references/dup-parallel-types-same-shape.md) — Collapse parallel types that share a shape
69- [`dup-near-twin-functions`](references/dup-near-twin-functions.md) — Parameterize two functions that differ by a literal
70- [`dup-mirrored-branches`](references/dup-mirrored-branches.md) — Lift shared lines out of mirrored if/else branches
71- [`dup-config-not-copies`](references/dup-config-not-copies.md) — Replace many hardcoded copies with one table
72- [`dup-cross-layer-shape`](references/dup-cross-layer-shape.md) — Collapse identical DTOs, DB rows, and domain objects
73
74### 4. Derived State Stored (HIGH)
75
76- [`derive-dont-store-computed`](references/derive-dont-store-computed.md) — Compute what you can compute; store only what you can't
77- [`derive-single-source-of-truth`](references/derive-single-source-of-truth.md) — Pick one source of truth; derive the rest
78- [`derive-boolean-from-data`](references/derive-boolean-from-data.md) — Derive booleans from the data, don't track them separately
79- [`derive-cache-as-getter-not-field`](references/derive-cache-as-getter-not-field.md) — Turn cached fields into getters until profiling proves otherwise
80- [`derive-url-as-state`](references/derive-url-as-state.md) — Let the URL or route be the state, not a mirror of it
81
82### 5. Procedural Rebuilds (MEDIUM-HIGH)
83
84- [`proc-mutation-builder-over-pipeline`](references/proc-mutation-builder-over-pipeline.md) — Compose pipelines when the mutation-builder hides the intent
85- [`proc-if-chain-as-lookup`](references/proc-if-chain-as-lookup.md) — Replace if/elif returning constants with a lookup table
86- [`proc-manual-recursion-of-walk`](references/proc-manual-recursion-of-walk.md) — Use a recognised tree/object walk, not hand-coded recursion
87- [`proc-build-vs-declarative-template`](references/proc-build-vs-declarative-template.md) — Use the declarative form when the framework provides one
88- [`proc-sequential-awaits-could-be-parallel`](references/proc-sequential-awaits-could-be-parallel.md) — Parallelise independent awaits
89
90### 6. Speculative Generality (MEDIUM)
91
92- [`spec-interface-of-one`](references/spec-interface-of-one.md) — Avoid defining an interface for a single implementation
93- [`spec-options-bag-of-one`](references/spec-options-bag-of-one.md) — Avoid options bags where every caller passes the same values
94- [`spec-flag-driven-paths`](references/spec-flag-driven-paths.md) — Split a function that a boolean flag has made into two
95- [`spec-no-extension-point-without-extender`](references/spec-no-extension-point-without-extender.md) — Delete extension points that have no second user
96- [`spec-generic-over-one-type`](references/spec-generic-over-one-type.md) — Drop the generic parameter when only one concrete type uses it
97
98### 7. Defensive Excess (MEDIUM)
99
100- [`defense-guard-against-impossible`](references/defense-guard-against-impossible.md) — Stop guarding against states the type/flow already rules out
101- [`defense-validate-once-at-boundary`](references/defense-validate-once-at-boundary.md) — Validate once at the boundary, trust inside
102- [`defense-let-it-throw`](references/defense-let-it-throw.md) — Let exceptions propagate; don't catch what you can't handle
103- [`defense-null-pollution-from-bad-modelling`](references/defense-null-pollution-from-bad-modelling.md) — Fix the type that makes the null checks necessary
104
105### 8. Type System Underuse (LOW-MEDIUM)
106
107- [`types-discriminated-union-over-flags`](references/types-discriminated-union-over-flags.md) — Use a discriminated union instead of optional fields + tags
108- [`types-literal-union-over-string`](references/types-literal-union-over-string.md) — Narrow `string` down to a literal union when the set is closed
109- [`types-no-any-to-silence`](references/types-no-any-to-silence.md) — Avoid reaching for `any`/`as` to silence a type error
110- [`types-branding-over-runtime-checks`](references/types-branding-over-runtime-checks.md) — Brand a validated value so you don't validate it twice
111- [`types-exhaustive-switch-not-default`](references/types-exhaustive-switch-not-default.md) — Use exhaustiveness checks instead of a catch-all default
112- [`types-readonly-and-immutable-by-default`](references/types-readonly-and-immutable-by-default.md) — Mark data `readonly` until mutation is actually needed
113
114## How to Apply (Workflow)
115
116When asked to review or refactor code with this skill:
117
1181. **Run the mechanical pass first.** `knip`/`eslint`/`ruff`/`tsc --noUnusedLocals` will catch dead code, unused imports, style. Don't duplicate that work here.
1192. **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.
1203. **Walk the categories in priority order.**
121 - Start with [Reinvention](references/reinvent-stdlib-collection-ops.md) and [Frame](references/frame-function-not-class.md) — the biggest wins live there.
122 - Then [Duplication](references/dup-parallel-types-same-shape.md) and [Derived state](references/derive-dont-store-computed.md).
123 - Then [Procedural rebuilds](references/proc-loop-to-collection-method.md) and [Speculative generality](references/spec-interface-of-one.md).
124 - Defensive and type-system issues last — they're high frequency but localised.
1254. **Propose minimal-diff transformations.** Each rule shows incorrect → correct as a tight diff; preserve that property in suggestions.
1265. **Verify behaviour.** Outputs, errors, and side effects must be identical. Tests must still pass.
1276. **Don't bundle unrelated changes.** Each transformation should map to one category. Mixing them makes the change hard to review.
128
129## When NOT to Apply
130
131- Code is younger than the rule of three (one or two duplicates) — extracting is premature.
132- The pattern is genuinely a known exception (see each rule's "When NOT to use this pattern" section).
133- The refactor would be a large, risky rewrite without a clear test safety net — propose, don't execute.
134- Performance-critical hot paths where the "simpler" form has measurable cost — measure first.
135
136## Reference Files
137
138| File | Description |
139|------|-------------|
140| [references/_sections.md](references/_sections.md) | Category definitions and ordering |
141| [assets/templates/_template.md](assets/templates/_template.md) | Template for new rules |
142| [metadata.json](metadata.json) | Version and reference information |
143
144## Related Skills
145
146- [`code-simplifier`](../../.curated/code-simplifier/) — Mechanical simplification (naming, dead code, nesting). Complementary first pass.
147- [`complexity-optimizer`](../complexity-optimizer/) — Algorithmic/performance complexity. Different axis.
148- [`refactor`](../refactor/) — General-purpose refactoring workflow.
149- [`clean-code`](../clean-code/) — Broader clean-code principles. This skill is the narrower, judgment-focused subset.