A catalog explorer for the canonical refactorings and code smells.
Canonical Fowler refactorings and the smells they address.
Each function reads as a single named domain step — what it does, not how.
Trivial wrappers vanish; the call site reads as exactly what's happening.
A complex expression earns a name that says what it represents in the domain.
Single-use variables that just rename their right-hand side disappear; the expression speaks for itself.
Function names match what they actually do; parameter lists carry only what the function needs, in the order callers expect.
All reads and writes pass through a small named function that owns validation, logging, and invariants.
Variable names match the domain role they play, not their implementation type or scratch nature.
Related arguments travel together as one well-named value object that the function (and callers) refer to by name.
Functions that all act on the same data live alongside it as methods; calls become method calls on a domain object.
Multiple derived values from the same source come from one transform that produces an enriched record.
Each phase reads and writes its own well-defined inputs and outputs; the seam between them is data, not control flow.
Each function lives where its data lives; coupling between modules drops.
Each field belongs to the class that owns its lifecycle; cross-class reaching disappears.
Related statements sit next to each other; the function reads as a sequence of cohesive sub-steps that are easy to extract.
Each loop does one thing; mixed-purpose loops separate into named single-purpose passes.
Filter / map / reduce expresses the transformation as a sequence of named operations; intent jumps off the page.
Every line in the codebase is reachable and used; readers don't waste cycles on phantom branches.
Each variable has one role; reassignment patterns reflect distinct purposes rather than reused storage.
Field names match the domain role they play; readers don't need to inspect usage to know what a field means.
Values computed from other state are computed on demand; no separate field needs to be kept in sync.
Conditions and their consequents read as named domain decisions: isInSummer(), discountFor(date), etc.
Multiple conditions leading to the same action collapse into one named predicate.
Edge cases bail out early at the top of the function; the main flow is unindented and tells the happy path linearly.
Each case becomes a class implementing a shared interface; dispatch happens once via virtual call.
A repeating null-or-special check becomes a Null Object (or Special Case) that responds sensibly to the same interface.
Invariants the code assumes are stated explicitly; readers don't need to deduce them.
Functions either return a value or mutate state, never both — callers can compose them without surprise.
Two near-identical functions that differ only in literal values combine into one with a parameter.
Each flag value becomes its own well-named function; callers say what they mean rather than passing booleans.
Instead of pulling several values out of an object to pass them in, pass the object itself.
When a function can compute its own answer from already-available state, callers don't have to pre-compute it.
Object creation goes through a named function that can validate, choose subclasses, or return cached instances.
Methods that subclasses implement identically move to the shared superclass.
Methods used by only one subclass live with that subclass, not on the shared superclass.
A 'kind' string field becomes a real subclass type; the type system enforces the legal set.
Two classes with substantial shared structure get a common parent that owns the shared bits.
A subclass that no longer differs meaningfully from its parent merges back in.
Behavior that varied via inheritance now varies via a delegate object that implements the variant interface.
A cohesive sub-concept inside a class becomes its own class with its own name, fields, and methods.
Each domain concept has a small typed home — Money, PhoneNumber, OrderId — that knows its rules.
Callers ask the closest object for what they want; the object delegates internally without exposing its collaborators.
Callers talk directly to the real object; trivial passthroughs are deleted.
Bare numbers and strings that encode domain concepts become named constants whose name says what the value represents.
Setup or follow-up that happens around every call to a function moves inside the function, so the caller's contract shrinks.
Statements that vary by caller move out of the function so each caller chooses its own setup or follow-up.
When inline code reproduces what a named function already does, the inline copy is replaced by a call.
A local variable assigned once from a computation becomes a function that returns that computation on demand.
A function with rich internal state becomes an object whose methods can share that state — easier to extract, name, and test in pieces.
A command object whose execute() does everything in one shot collapses back to a plain function.
Instead of mutating a parameter in place, the function returns the modified value so the caller reassigns.
An opaque or convoluted algorithm gets replaced by a clearer one (often from a library or well-known pattern) that produces the same outputs.
A class's internal collection is never returned directly; callers add or remove via methods on the class, and reads return a snapshot or iterator.
A bare record (plain object with public fields) becomes a class whose properties are accessed through methods that can validate, log, or derive.
Fields whose values should only be set at construction lose their setters; callers either construct a new object or call a domain method that changes the field as a side effect of doing real work.
A class with too few responsibilities to deserve its own file folds into a class it collaborates with most.
An object treated as a sharable record (with setters) becomes a value object — immutable, equal by content, replaced rather than mutated.
Duplicate copies of a logically-single entity collapse into one shared object that everyone references.
Loops that maintain a boolean to decide when to stop replace it with a direct `break`, `return`, or `continue`.
A function that reads from a query (global, singleton, instance state) instead accepts the value as a parameter and becomes referentially transparent.
Numeric or string error codes that callers must remember to check are replaced with exceptions that propagate by default.
Exceptions used for predictable, checkable conditions become an explicit precheck the caller can perform, leaving exceptions for truly exceptional cases.
Initialization code repeated across subclass constructors moves into the parent class's constructor and is called via super.
A field declared identically in two or more subclasses moves to the shared superclass.
A field used by only one subclass moves out of the parent and into that subclass.
A subclass whose only purpose was to encode a type code or add nothing collapses back into a field on the parent.
Inheritance from a superclass that doesn't really fit (Liskov violations, awkward methods) becomes composition: the former subclass holds an instance and delegates explicitly.