| name | reuse |
| description | Find opportunities for code reuse in the changed code, both against existing code and within the change itself, without creating bad coupling or contrived abstractions. |
| argument-hint | [extra guidance or files to focus on] |
Find opportunities for code reuse in the changed code, both against existing
code and within the change itself, without creating bad coupling or contrived
abstractions.
Target
jj show --git
Arguments: $ARGUMENTS
Find reuse opportunities in the target named in the arguments if given;
otherwise the changes in the current commit shown above; if there are no
arguments and the commit has no changes, ask the user which code to review and
stop.
Principles
- Duplication is only a problem when the copies must change together. Two pieces
of code that look alike but encode different decisions are coincidentally
similar; merging them couples unrelated change reasons
- The best reuse adds no new code: call something that already exists in the
codebase, the standard library, or an installed dependency
- A little duplication is cheaper than the wrong abstraction. When in doubt,
leave the copies
Workflow
- For each changed function or code chunk, search for code that already does
the job, in order of preference:
- The standard library of the language
- Dependencies already installed (check the manifest, e.g.
package.json;
don't propose new dependencies)
- Utilities and helpers elsewhere in the codebase
- Other code in the same module
- Compare the added chunks against each other: a change often introduces the
same logic twice in different files, and neither copy existed before, so
searching existing code won't surface it
- For each duplication found in steps 1 and 2, decide whether to reuse or
extract, using the tests below
- If nothing passes the tests, say so and stop; don't invent findings
- Report each opportunity (see "Reporting"). Don't apply changes unless the
arguments or a follow-up message ask for it
Tests for a reuse opportunity
Flag an opportunity only when it passes all of these:
- Same reason to change: if a requirement shifts, every call site must want the
new behavior. If one caller might need to diverge, it's coincidental
similarity
- Honest name: the shared code has a precise name describing one job. If the
best available name is vague (
helper, util, process, handleData), the
abstraction is contrived
- No parameter switches: the shared code needs no boolean flags, mode enums, or
callbacks whose only purpose is to make callers behave differently. Each such
knob is the duplication smuggled back in
- Dependencies point downward: callers depend on something at a lower level of
abstraction. Never make a general module import from a specific feature, and
never couple two unrelated features to share a few lines
- Worth its weight: the shared code saves more than it costs. Extracting three
trivial lines into a new shared module fails this; replacing a hand-rolled
deep-clone with an existing utility passes
These aren't exhaustive. Reason from first principles when none fits cleanly.
Reporting
For each opportunity, one paragraph: the duplicated or reimplemented logic (file
path and line range), the call sites it covers, what to reuse or extract
instead, and the test that came closest to failing, with why it still passes.
Order by impact, largest first.