Shotgun Surgery
One change requires edits in many different classes.
“Every time you make a kind of change, you have to make a lot of little changes to a lot of different classes.” – Fowler & Beck
The opposite of Divergent Change.
Signs of Use (Symptoms)
- Adding a new field requires editing 10+ files.
- “I changed X, but forgot to update Y, Z, W…”.
Why it is bad (Consequences)
- Easy to miss changes: Bugs due to incomplete updates.
- High effort: Small feature = Many files touched.
Why it happens (Root Cause)
A single concept is scattered across many places instead of being centralized.
When it might be okay (Exceptions)
- Cross-cutting concerns might look like shotgun surgery but be intentional (though AOP is better).
Explanation
Problem
To add a new “User Role”, you must edit User.ts, UserForm.tsx, user_permissions.sql, RoleConstants.java, RoleDropdown.vue…
The Flaw
The concept of “Role” is not encapsulated. It’s scattered.
Real world analogy
Changing the company logo. You must update the website, business cards, letterheads, signage manually. A centralized “Brand Guidelines” document would help.
Refactoring Solution
- Move Method / Move Field: Centralize the scattered logic into one class.
- Inline Class: If the scattered pieces are tiny.
Pros and Cons (of the Antipattern)
| Pros (Why people do it) | Cons (The price you pay) |
|---|---|
Comparison
- Related Antipatterns: Divergent Change (opposite).
- Related Principles: Violates DRY (concept is repeated).
Code example
Typescript
Bad (The Antipattern)
Good (The Fix)