| name | decomplect |
| description | Review code for *complecting* — concerns braided together that could stand apart (Rich Hickey, "Simple Made Easy"). Scans a diff, file, or module against a catalog of complex constructs (state⊗time, objects, inheritance, scattered conditionals, direct A→B coupling, syntax-over-data, ...) and reports each entanglement with the decomplected alternative and its cost to changeability. Unlike generic "simplification," it does NOT minimize line count and may recommend MORE, separate pieces. Use when asked to "decomplect", find entanglement / interleaving, assess why code is hard to change, or review changeability. |
| version | 0.1.1 |
| last_reviewed | 2026-05-28T00:00:00.000Z |
Decomplect — Entanglement Radar
Find complecting: places where two or more independent concerns are braided together so you can't reason about, test, or change one without dragging in the other. From Rich Hickey's "Simple Made Easy" — complex (Latin com-plex, "braided together") is the opposite of simple ("one fold"). The opposite operation is compose (place together, side by side).
Core rule — this is NOT simplify. Generic simplification reduces: fewer lines, dedup, raise altitude. Decomplecting unbraids, and the right unbraiding frequently produces more code, more named things, more files — Hickey: "simplicity is not about counting." Better many pieces hanging straight down than two tied in a knot. Never reward consolidation for its own sake. If a finding's only justification is "fewer lines," it belongs in simplify, not here.
The test is objective and pointable: "X is interleaved with Y, and X and Y could stand apart." If you can't name the two concerns and argue they're independent, it's not a decomplect finding.
Input (precedence order)
- Explicit path argument —
decomplect path/to/file_or_dir → read those files directly.
- Explicit diff range —
decomplect main...feature-branch.
- Default —
git diff main...HEAD (current branch vs. main).
Decomplecting is meaningful on a whole module/namespace, not just a diff — when given a file or directory, review the code as it stands, not only what changed.
The Complecting Catalog (the checklist)
Walk each row against the target. Each names a complex construct, the concerns it braids, the simpler replacement Hickey names, and the tell to grep for. Examples lean Clojure (the talk's idiom); the principle is language-general — adapt the replacement to the host language (see Rules §6).
| # | Construct | Braids (X ⊗ Y) | Decomplected alternative | Tell / smell |
|---|
| 1 | Mutable state | value ⊗ time | immutable values | same call → different answer |
| 2 | Objects | state ⊗ identity ⊗ value | values + managed refs | a thing that is its mutable fields |
| 3 | Methods | function ⊗ state (⊗ namespace) | functions + namespaces | behavior that needs this |
| 4 | Vars / mutable variables | value ⊗ time | managed references (atom/ref) | reassignment; no stable value to hand off |
| 5 | Inheritance | type ⊗ type | polymorphism à la carte (protocol / type class / interface) | extends; base-class coupling |
| 6 | Switch / pattern-match on a tag | many (who ⊗ what) pairs, in one closed place | open polymorphism (dispatch) | a growing case/cond/switch on a type field |
| 7 | Syntax | meaning ⊗ order | data (maps/sets/seqs) | a DSL string where data would do |
| 8 | Imperative loop / fold | what ⊗ how (fold also ⊗ order) | set functions (map/filter/reduce as set ops) | manual index/accumulator |
| 9 | Actors | what-is-done ⊗ who-does-it | queues | a stateful mailbox that also computes |
| 10 | ORM | representation ⊗ logic ⊗ identity | declarative data manipulation (SQL/datalog) | objects mirroring tables row-for-row |
| 11 | Conditionals as scattered policy | rules ⊗ program structure | rule system (declarative) | the same business rule re-encoded at many call sites |
| 12 | Inconsistency |
How to report a finding
Every finding states the braid in canonical form, then the unbraiding:
[#N Construct] short title — file:line (or pattern)
Complected: X is braided with Y here — <the specific evidence>.
Cost: what becomes hard to change/test/reason about because of the braid.
Decomplect: the specific separation (which catalog alternative, applied here).
Confidence: high / medium / low — and the domain judgment it rests on.
Lead with the cost to changeability — that's Hickey's primary payoff ("ease of change and easier debugging"). A braid that never needs to change is a low-priority finding even if real.
Triage every finding: incidental vs. inherent
- Incidental ("Latin for your fault") — the braid came from a construct/tool choice. Fixable by decomplecting. These are the findings worth acting on.
- Inherent / environmental ("not your fault") — resource contention, GC, scheduling; the braid is in the problem/implementation substrate, not your construct choice. Name it, mark it inherent, move on. Don't propose a refactor for complexity that isn't yours to remove.
Output format
## Decomplect Report — <target description>
**Entanglement score:** <Low / Moderate / High / Severe> — <one-sentence characterization>
(based on how many independent concerns are braided, weighted by change-cost)
---
### Findings — incidental (worth decomplecting) _ranked by change-cost_
**[#N Construct] title** — `file:line`
> *Complected:* X ⊗ Y — <evidence>
> *Cost:* <what's hard to change/test/reason about>
> *Decomplect:* <specific separation>
> *Confidence:* <high/med/low>
---
### Noted — inherent / environmental (not your fault)
- <braid> — inherent because <reason>. No construct change removes it.
---
### Already simple _(positive findings worth keeping)_
- <place where concerns are cleanly composed, not complected>
Rules
- Objective test or it doesn't ship. Every finding must name two concerns and argue they're independent. "This feels complex" is not a finding.
- More is allowed. If the right unbraiding adds code, files, or names, say so plainly. Do not soften a correct finding because it grows the line count.
- Modularity ≠ decomplected. Separate files/classes/namespaces can be fully complected ("this module presumes that one never returns 17"). Judge conceptual entanglement, not code organization. Conversely, don't credit partitioning/stratification as simplicity — they're enabled by it, not equal to it.
- Don't fragment a single concern. Separating independent concerns is the goal; splitting one cohesive concern into shards is the failure mode (and what
improve-codebase-architecture's "deep modules" guidance guards against). When unsure whether two things are truly independent, mark the finding low-confidence.
- Findings are candidates, not verdicts. Whether identity is really separable from state here is domain judgment. Report confidence; let the human decide. Match
code-review's calibrated tone.
- Adapt the replacement to the host language. In a non-Clojure repo, translate: managed refs → a state container /
useRef-style cell; polymorphism à la carte → tagged unions + functions / interfaces + injection; data-as-data → records/dicts over bespoke classes. The braid is universal; the fix is idiomatic.
- Name the cost, don't moralize. Hickey: "I'm not a functional-whatever guy." Flag the entanglement and its change-cost; propose the alternative; don't preach FP. Unusual ≠ complected.
- Duplication is not entanglement — and watch for the testability payoff. Two patterns the first real-world run surfaced (see calibration writeup): (a) when a "finding" is really the same concern reimplemented in N places, that's a missing abstraction → consolidation territory (
improve-codebase-architecture), not braiding to separate; recommend a shared home, don't frame it as a split. (b) A payoff worth naming in Cost: extracting an independent concern — e.g. a pure decision function out of a side-effecting handler — often makes logic that was previously reachable only through the full machine directly unit-testable.
Pitfalls
- Collapsing into
simplify. The moment a finding's justification is "shorter/DRYer," you've left this skill. Re-anchor on "what two concerns are braided."
- Counting things. A namespace with 30 small pure functions may be simpler than one with 3 stateful methods. Don't penalize quantity.
- Refactoring inherent complexity. Proposing a construct change for GC pressure or thread-pool contention. Mark it inherent and stop.
- Confident over-reach. Declaring two concerns separable when the domain genuinely fuses them. Use low-confidence and ask.
Cross-references
simplify — the other skill. Reduces/dedups/raises altitude. Run it for tidiness; run decomplect for entanglement. They can disagree, and the disagreement is informative.
improve-codebase-architecture — leans Ousterhout (deep modules, consolidate). Real tension with rule #4: that skill may want to merge what this one wants to separate. When both apply, surface the trade-off rather than picking silently.
code-review / security-review — hunt bugs/vulns; orthogonal axis. Can run alongside.
warmed-review (sibling repo) — complecting is the mechanism behind much of WARMED's M (modify) and R (read) cost. They cite each other.
Deep reference
The Complecting Catalog with per-row rationale and code examples, the simple-vs-easy framing, and the design tensions (Hickey vs. Ousterhout) live in skill_distillation_analysis.md and the talk artifacts in simple_made_easy_talk/.