Category
Change Preventers
Smells where one change forces edits in many places, or one class changes for many unrelated reasons, making every edit slow and risky.
What these smells share
Change preventers show up in the commit history more than in any single file. You notice them when a small feature takes a day because it touches ten files, or when one class appears in every pull request regardless of topic. The structure of the code does not match the axes along which requirements change.
The fix is to regroup code so that things which change together live together, and things which change for different reasons live apart.
Members
- Divergent Change: one class is edited for many unrelated reasons, such as both database changes and pricing rules.
- Shotgun Surgery: one logical change requires small edits across many classes.
- Parallel Inheritance Hierarchies: every new subclass in one hierarchy needs a matching subclass in another.
How to choose within this category
- Divergent Change and Shotgun Surgery are mirror images. Ask which way the change spreads.
- One class, many reasons to change: Divergent Change. Split the class.
- One reason, many classes to change: Shotgun Surgery. Gather the pieces.
- If the scattering follows a pair of class hierarchies that grow in lockstep, it is the special case Parallel Inheritance Hierarchies.
- Use version control to confirm. Files that are always committed together point to shotgun surgery; a file touched by every unrelated change points to divergent change.
Typical treatments
- Extract Class to split a class along its reasons to change.
- Move Method and Move Field to gather scattered behavior into one place.
- Inline Class when a scattered concern ended up in many tiny classes.
- Move Method and Move Field to fold one parallel hierarchy into the other.
For agents
- Do not over-correct. Splitting a class for every possible reason creates shotgun surgery; merging everything to avoid it creates divergent change. Group by the changes you have actually seen.
- Check the git log for co-change patterns before restructuring. It is better evidence than reading the code.
See also
- BloatersSmells where methods, classes and parameter lists grow too large to read, test or change safely, usually one small addition at a time.
- CouplersSmells where classes depend too much on each other's data or structure, or where delegation is overused, so one change ripples through others.
- Move MethodMove a method to the class whose data it uses most, and leave a delegating call or update the callers.
- Extract ClassSplit a class that does two jobs by moving one job's fields and methods into a new class it holds a reference to.
Original writing and examples. Topic coverage follows Refactoring.Guru, which explains this topic with its own illustrations.