--- name: refactorability description: > Review code for refactorability — surface concrete, prioritized refactoring opportunities grounded in Martin Fowler's smell catalog and SOLID, augmented with static analysis tools (gocyclo, gocognit, dupl, etc.) when available. Go-first, polyglot-aware. Defaults to the current diff. Produces a High/Med/Low report with specific refactoring moves and a "Do NOT refactor" section to prevent over-eager suggestions. Triggers: /refactorability, "review for refactorability", "what should I refactor", "refactorability review", "find refactoring opportunities", "is this refactorable", "review this code for refactoring" metadata: author: meain version: "1.0.0" --- # /refactorability — Refactorability Review Surface **concrete, prioritized** refactoring opportunities in code. The goal is not generic "clean code" feedback — it is to point at specific smells, name the refactoring move that fixes them, and rank by impact so the user knows what to actually touch. The review is **opinionated about restraint**: it must call out cases where refactoring would be premature, speculative, or net-negative. ## Process ### 1. Pick the scope In order of preference: 1. **Explicit target** the user named (file, function, package). 2. **Current diff** (default when no target given): - `jj` repo: `jj diff --name-only -r @` (fallback to `jj diff --name-only`) - `git` repo: `git diff --name-only HEAD` (plus `--cached` if there's nothing unstaged) - PR context: `gh pr diff` if a PR is being reviewed 3. **Whole package/module** only if the user explicitly asks for it. Print the resolved scope before continuing so the user can correct it. ### 2. Detect language and tools Look at file extensions in scope. For each language present, check which of the tools below are on `PATH` and run them only on **files in scope** (not the whole repo). #### Go (primary) | Tool | Invocation (per file or dir) | What it gives you | |------------|--------------------------------------------------------|------------------------------| | `gocyclo` | `gocyclo -over 15 ` | Cyclomatic complexity > 15 | | `gocognit` | `gocognit -over 15 ` | Cognitive complexity > 15 | | `dupl` | `dupl -threshold 50 ` | Duplicated token sequences | | `revive` | `revive -formatter friendly ` | Style + some smell rules | | `golangci-lint` | `golangci-lint run --no-config --disable-all --enable=gocyclo,gocognit,dupl,gocritic,revive ` | Aggregated, if standalone tools are missing | Also do a quick `grep`/AST scan for: functions > ~80 lines, > 5 params, deep nesting (> 3 levels), `interface{}`/`any` over-use, and large switch/`if` ladders on type. #### Python `ruff check`, `radon cc -s -a `, `radon mi `, `vulture `, `pylint --disable=all --enable=R ` for refactor-class warnings. #### JS/TS `eslint` with `eslint-plugin-sonarjs` if configured, `jscpd ` for duplication, `tsc --noEmit` for type smells. #### Polyglot fallback `semgrep --config=p/code-smells` if installed; otherwise lean on LLM reading. **If no tools are available**, proceed with LLM-only reading and say so in the report (so the user knows the quantitative pass was skipped). ### 3. Apply the lens Read the code in scope and map findings to the Fowler smell catalog + SOLID. Use [`references/code-smells.md`](references/code-smells.md) as the authoritative list. Do **not** invent smell names — pick from the catalog. For each finding, pick a concrete refactoring move from the same catalog (e.g. "Extract Method", "Replace Conditional with Polymorphism", "Introduce Parameter Object"). ### 4. Score severity Assign each finding a severity: - **High** — actively blocks change/test/understand. Examples: function with cyclomatic > 20 in a hot path, duplicated business logic across files, god-object that everything imports, shotgun-surgery pattern around a single concept. - **Medium** — measurable maintenance tax but localized. Examples: long parameter list on a helper, feature envy across two files, modest duplication. - **Low** — taste / future-proofing. Examples: primitive obsession on one type, slightly long method, comments hiding an obvious extract. If a finding could be either, **prefer the lower severity**. The bar for High is "the next person changing this will get hurt." ### 5. Decide what NOT to refactor Before writing the report, explicitly identify code that *could* look refactorable but **should be left alone** for this review. Put these in a dedicated section (see below). Common cases: - Working, stable code with no upcoming change — refactoring is pure risk. - Code that's verbose because of a clear API contract (e.g. protobuf gen, handler boilerplate). - A single duplication (rule of three not met). - Abstraction that would only have one caller. - Tests — they're allowed to be repetitive and explicit. - Generated code. ### 6. Write the report Use the output format below. Keep it **terse and scannable** — bullets, tables, file:line references. No motivational filler. ## Output format ```markdown # Refactorability Review **Scope:** **Tools run:** gocyclo, gocognit, dupl (or: "none — LLM-only pass") **Overall:** ## High ### 1. — `path/to/file.go:123` - **What:** <1 sentence describing the smell concretely> - **Signal:** - **Why it matters:** <1–2 sentences on change/test/understand cost> - **Move:** — <1–2 sentence sketch> - **Effort / Risk:** S/M/L — <1 short note on risk> ### 2. ... ## Medium ### 1. ... ## Low ### 1. ... ## Do NOT refactor - `path/to/file.go:45` — Looks like primitive obsession, but it's a single call site behind a stable API. Wait until a second caller appears. - `path/to/gen_pb.go` — Generated. - ... ## Notes (optional) Anything the user should know but isn't a finding (e.g. "gocognit not installed, skipped cognitive complexity pass"). ``` ## Guidelines - **Cite the catalog.** Every finding's smell name and refactoring move must come from `references/code-smells.md`. If you want to flag something not in the catalog, call it a "Note" instead of a finding. - **Always include file:line.** No "in some handler somewhere". - **Quote a signal.** A metric (`gocyclo=24`), a count (`6 parameters`), or 2–4 lines of code. Without a signal it's just opinion. - **One paragraph per finding, max.** This is a triage tool, not a design doc. - **Resist these temptations:** - Style / naming nits (use a linter for those) - "Add tests" — that's a separate review - Rewrites — only suggest local refactoring moves - "Use design pattern X" without a smell to justify it - Speculative generality ("what if we need to swap the DB later?") - Performance — separate review unless the smell *causes* the perf issue - **High-severity ceiling.** Aim for ≤ 3 High findings per review. If everything is High, nothing is. - **Honor existing project conventions.** If the codebase is consistently structured a certain way (e.g. Veeam VDC handlers), don't flag conformance to that style as a smell. ## When to fail loudly - If the scope is empty (no diff, no target), ask the user what to review. - If the user asks to review > ~50 files in one go, push back and propose narrowing. - If running a tool errors out (e.g. `gocyclo` not installed), note it in "Notes" — do not silently skip. ## Reference - [`references/code-smells.md`](references/code-smells.md) — Fowler smell catalog + refactoring moves, used as the authoritative vocabulary for findings.