← Back to Next.js project starter

Skill · Version 1.0.0

Review duplication and abstraction

Distinguishes repeated business rules from coincidentally similar code before introducing shared helpers or frameworks.

duplication-abstraction-review

Agents using this skill

See how it helps

When is it useful?

Use when deciding whether similar functions or screens should be consolidated.

What does it help you do?

  • Asks whether the copies must change together for the same domain reason.
  • Finds genuine rule duplication that risks inconsistent calculations or permissions.
  • Keeps independent workflows separate when sharing would require growing conditional options.

Try asking this

Compare our quote and invoice calculations and propose only abstractions representing the same rule, leaving unrelated presentation code independent. Change the shared rounding rule in a small prototype. Demonstrate which consumers genuinely need the same change and which only look structurally similar.

Detailed documentation

Read the skill’s original instructions, examples and checks in their authored language.

Details…Show less

Duplication & Abstraction Review

Not all code repetition is the same, and not every abstraction improves maintainability. Follow Sandi Metz's maxim: duplication is far cheaper than the wrong abstraction. Before extracting a shared helper or base class, determine whether the repeated code represents a single domain rule or merely a temporary coincidence of shape.

1. Essential vs. Accidental Duplication

Classify repeated code by why it changes (Single Source of Truth), not just how similar the lines look today:

  • True (Essential) Duplication — Consolidate:
    • The same business calculation, permission check, state transition rule, tax/discount formula or retry policy is copy-pasted across multiple places.
    • Whenever that business rule changes, every copy must change identically or the system becomes inconsistent.
    • Action: extract into a single, well-named domain function or policy module and route all call sites through it.
  • Accidental (Coincidental) Similarity — Keep Separate:
    • Two forms, DTOs, controllers or view components happen to have three similar-looking fields or steps today, but belong to independent workflows or domain concepts that evolve on different schedules.
    • Action: keep them independent. Coupling two unrelated features through a shared abstraction forces every future change in one feature to thread conditional flags through the other.

2. Rule of Three & Evidence-Driven Extraction

  • Wait for concrete cases: resist building a generic framework, plugin registry or multi-layer inheritance hierarchy from a single use case or two slightly different callers.
  • Extract what is genuinely shared: when three or more concrete occurrences share an invariant, extract the pure common mechanism (as a composable function or narrow collaborator) while letting each caller pass its specific policy or configuration explicitly.
  • Prefer composition and data over inheritance: favor plain functions, parameter objects and small strategy callbacks over deep base-class hierarchies (BaseController -> AbstractCrudController -> AuditedResourceController) that hide control flow across parent/child methods.

3. Healing the Wrong Abstraction

When you encounter an existing shared function or class that has accumulated boolean mode flags (processItem(data, isLegacy, skipValidation, forExport, useV2)), caller-type switches and partial overrides:

  1. Re-inline (Unroll) the abstraction: copy the relevant code back into each caller or specialized path and delete the branches that do not apply to that specific caller.
  2. Simplify each path independently: remove dead parameters and redundant conditionals once each caller only contains the logic it actually executes.
  3. Re-extract narrow, honest helpers: if a smaller, genuinely identical pure calculation remains across the simplified paths, extract just that cohesive helper without the conditional tangle.

Included files 1

  • SKILL.md