Shotgun Surgery: One Small Change, Ten Offices to Visit
Learn the Shotgun Surgery code smell with an address-change story, simple definitions, TypeScript and C# examples, a clear comparison with Divergent Change, and practice.
🏠 The day Meera's family shifted house
Meera's family lived in Indira Nagar, Lucknow. Last month, her father got a transfer, and the family shifted to a new flat in Gomti Nagar. New house, new paint smell, new neighbours. Everyone was happy — until Papa took out a notebook and started writing a list.
"What is that list, Papa?" Meera asked.
"Beta, this is the list of every office where our address is written," he sighed. And he started counting on his fingers:
- Aadhaar card — visit the Aadhaar Seva Kendra, take a token, wait two hours.
- Bank — fill the KYC form, attach proof, sign in three places.
- Meera's school records — write an application to the principal's office.
- Gas connection — go to the agency, show the new rent agreement.
- Ration card — another office, another queue, another photocopy.
- Electricity bill, post office, scooter RC... the list kept growing.
The next two days were a tour of the city. Token machines, photocopies, "come after lunch", "the server is down, come tomorrow". Watch Papa's mood through the journey — the scores tell the whole story:
One small change in real life — the family lives in a new flat — but ten different offices must each be updated, one by one, by hand. And here is the scary part Papa mentioned at dinner: "If I forget even one office, trouble comes later. Last time, your uncle forgot the bank. His debit card got blocked because the address on file did not match."
Notice the shape of this pain. The change is one. The places to update are many. No office talks to the others. Nobody sends Papa a checklist. Whether every record gets updated depends completely on Papa's memory. And look at the last row of the journey above — even careful Papa missed the scooter RC, and only found out a week later.
Meera, who had just started learning to code, asked the golden question: "Papa, why is there no one office where you change the address once, and it tells all the others?"
Papa smiled. "Beta, the day you build that, you will have fixed a very famous problem."
Software has the exact same disease. Sometimes one tiny change — a new tax rate, a new date format, a renamed status — forces a programmer to hunt through ten files and edit each one by hand. Miss one file, and a bug quietly waits in production, just like uncle's blocked debit card. This smell is called Shotgun Surgery.
🤔 What is this smell?
Shotgun Surgery happens when a single change forces you to make many small edits in many different classes.
The name is vivid on purpose. A rifle makes one clean hole. A shotgun sprays many small pellets across a wide area. When this smell is present, one conceptual change does not land in one clean place — it sprays edits all over the codebase. And each edit is a small "surgery": careful, manual, and easy to get wrong.
Martin Fowler describes it in Refactoring: every time you make a kind of change, you have to make lots of little edits to lots of different classes. When the changes are all over the place, they are hard to find, and it is easy to miss an important one.
The root cause is almost always the same: a concept never got a home. Think about "how we format an address" or "how late fine is calculated". If that idea lives in one class, changing it means one edit. But if it was written inline — copy-pasted, re-typed, slightly varied — at every place that needed it, then the idea has no owner. It is smeared across the system like butter scraped over too much bread. Changing the idea now means finding every smear.
Shotgun Surgery is the second member of the Change Preventers family. Like its sibling Divergent Change, it does not crash your program. It slows your changes. Teams suffering from it start saying things like "oh no, not the address format again" — dread before a simple task is the emotional signature of this smell.
Easy memory trick: Shotgun Surgery = one house shift, ten offices. One reason to change, many classes to edit. The cure is to build "one office that informs all others" — gather the scattered logic into a single owning class.
One more sharp observation from Fowler: with Divergent Change, at least everything is in one place and easy to find — the problem is that it is too much in one place. With Shotgun Surgery, the problem is worse in one way: the pieces are hard to even find. You cannot fix what you cannot locate, and the compiler usually will not help you locate string formats and sprinkled if-conditions.
Here is the entire smell on one revision map:
🔍 How to spot it
Shotgun Surgery is felt before it is seen. Here is the checklist. Tick three or more, and you have it.
- A "simple" requirement produces a pull request touching 8+ files, each with two or three changed lines.
- Your team keeps a mental (or written!) checklist: "when X changes, remember to update A, B, C, and that one job in the legacy folder."
- You have shipped bugs of the form "we updated it everywhere except one place."
- The same constant, format string, or validation rule appears — slightly differently — in many files.
- New developers ask "where do I change X?" and the honest answer is "everywhere, a little."
- Code reviews for small changes take long, because the reviewer must verify nothing was missed — which is much harder than verifying what is present.
As a table for quick revision:
| Sign | What you observe | What it means |
|---|---|---|
| Confetti PRs | One ticket, ten files, two lines each | The concept being changed has no single home |
| Tribal checklist | "Remember to also update..." knowledge | Correctness depends on human memory |
| Except-one bugs | Production bug in the one missed spot | Scattered edits are incomplete by default |
| Cloned rules | Same validation/format logic in many files | Copy-paste spread the concept everywhere |
| Slow reviews | Reviewer must hunt for missing edits | Absence is harder to review than presence |
| Grep-driven work | You search the codebase by keyword to make a change | The type system cannot find the sites for you |
A practical detection trick: look at your version control history for commits that always travel together. If files A, D, and K change together in commit after commit, an invisible thread ties them. That thread is a homeless concept — and it is exactly what you should extract and give a home.
You can also make the scatter visible with a simple chart. Take one concept — say "how we write an address" — and count where its code currently lives:
A healthy concept produces a boring pie — one slice, one owner. Five nearly-equal slices means five offices, each holding its own photocopy of your address, each going stale independently.
College corner: Researchers who mine version-control histories call this change coupling (also "logical coupling"): files that have no compile-time dependency on each other, yet keep changing in the same commits. Tools like CodeScene rank file pairs by co-change frequency precisely to surface Shotgun Surgery that no static analyzer can see — because the coupling lives in the concept, not in the imports. If you ever do a software engineering mini-project, mining co-change pairs from a real repo's git log is a genuinely publishable exercise.
⚠️ Why it is a problem
1. Errors of omission. This is the killer. The danger is not the nine edits you make — it is the tenth one you forget. With scattered change-sites, forgetting is the default and completeness needs heroic memory. Papa's uncle forgot the bank; your team will forget LegacyExportJob.
2. Small changes become expensive. A one-line conceptual change becomes an afternoon of hunting, editing, and re-testing ten files. When small improvements cost this much, people stop making small improvements, and the codebase slowly stops getting better.
3. Reviews become weak. A reviewer can check that your ten edits are correct. But how can they check there is no eleventh place you both missed? Reviewing absence is nearly impossible, so the review becomes a hopeful guess.
4. The copies drift apart. Each scattered site gets edited independently over the years. One site rounds the fine up, another rounds down. One formats the address with a comma, another without. Tiny differences pile up into "why does the invoice show a different address than the receipt?" mysteries.
5. Knowledge gets locked in people. The full list of change-sites often exists only in a senior developer's head. When that person goes on leave, the team is stuck — a project risk hiding inside a code smell.
Here is the spray, drawn the way it feels on a Monday morning when the ticket says "small change":
And here is how the conversation actually goes inside a team living with this smell. Notice that the most important question — "is that all of them?" — has no confident answer:
College corner: This smell is the textbook case of change amplification — John Ousterhout's term from A Philosophy of Software Design for when a simple change requires code modifications in many places. Note how it pairs with its sibling smell: Divergent Change amplifies the understanding needed for one edit; Shotgun Surgery amplifies the number of edit sites. Both inflate the true cost of a change far beyond the size of the idea behind it. A good architecture is one where the cost of a change is proportional to the size of the idea, not to the age of the codebase.
💻 A real-life code example
Let us code Meera's address problem. A small shop's software keeps customer addresses. Watch how the idea of "how we write an address" was never given a home — every class that needed an address just built the string itself.
// The concept "format an address" is smeared across the system.
class CustomerView {
renderProfile(c: Customer): string {
return `${c.houseNo}, ${c.street}, ${c.city} - ${c.pincode}`;
}
}
class InvoicePdf {
billingBlock(c: Customer): string {
// same idea, typed again, slightly different
return `${c.houseNo} ${c.street}, ${c.city}-${c.pincode}`;
}
}
class ShippingLabel {
print(c: Customer): string {
// and again, with its own little variation
return `${c.houseNo}, ${c.street}\n${c.city} ${c.pincode}`;
}
}
class SmsSender {
confirmDelivery(c: Customer): void {
smsGateway.send(c.phone, `Delivered to ${c.houseNo}, ${c.street}, ${c.city}`);
}
}
// ...and somewhere in a dusty corner:
class LegacyExportJob {
exportRow(c: Customer): string {
return [c.houseNo, c.street, c.city, c.pincode].join("|");
}
}Now the requirement arrives: "Add the state name to every address, and put the pincode in the standard 'PIN: 226010' style." A one-sentence change. But look at what it costs: you must find and edit CustomerView, InvoicePdf, ShippingLabel, SmsSender, and LegacyExportJob — five files, five careful little surgeries. And did you even remember LegacyExportJob exists? Nothing in the code told you to look there. You found four sites by searching for pincode, but the export job joins fields without that word nearby on the same line. The fifth pellet is already lost.
Notice also the drift: three of the five formats already disagree about commas and dashes. They were not designed to differ — they just drifted, because each site was edited alone over time. That drift is the smell ageing.
🛠️ Cleaning it up, step by step
The cure is the opposite of the cure for Divergent Change: do not split — gather. Give the homeless concept one home, and make every old site delegate to it. The tools are Move Method, Move Field, and sometimes Inline Class.
Step 1 — Name the homeless concept. Ask: "What idea keeps forcing this multi-file sweep?" Here it is clearly "how we present an address". Say the name out loud; it usually sounds like a class begging to exist: Address.
Step 2 — Create (or choose) the owner. Sometimes a suitable class already exists and just lacks the behavior. Here, none exists — so we create one and use Move Field to bring the address data into it:
// One home for the concept.
class Address {
constructor(
private houseNo: string,
private street: string,
private city: string,
private state: string,
private pincode: string
) {}
full(): string {
return `${this.houseNo}, ${this.street}, ${this.city}, ${this.state} - PIN: ${this.pincode}`;
}
short(): string {
return `${this.houseNo}, ${this.street}, ${this.city}`;
}
exportRow(): string {
return [this.houseNo, this.street, this.city, this.state, this.pincode].join("|");
}
}Step 3 — Redirect each old site, one by one. Use Move Method thinking: the formatting behavior moves into Address, and each scattered site becomes a one-line delegation. Convert one site, run the tests, commit. Then the next.
// After: every site delegates to the one owner.
class CustomerView { renderProfile(c: Customer) { return c.address.full(); } }
class InvoicePdf { billingBlock(c: Customer) { return c.address.full(); } }
class ShippingLabel { print(c: Customer) { return c.address.full(); } }
class SmsSender {
confirmDelivery(c: Customer) {
smsGateway.send(c.phone, `Delivered to ${c.address.short()}`);
}
}
class LegacyExportJob { exportRow(c: Customer) { return c.address.exportRow(); } }The structure after gathering is worth drawing. One owner in the middle; every old site reduced to a polite one-line visitor:
Step 4 — Let the compiler hunt for you. Here is a lovely bonus. Once Customer holds an Address object instead of four loose strings, every leftover site that still does c.pincode fails to compile. The compiler becomes your checklist. The "did I miss one?" fear — the worst part of this smell — simply disappears, because missed sites announce themselves with red underlines.
Step 5 — Check for over-fragmentation. Sometimes Shotgun Surgery exists because a concept was split into too many tiny classes that always change together. In that case the cure is Inline Class: fold the fragments back into one class so the concept stops being confetti.
The whole journey of the concept — from homeless, to drifting, to safely housed — in one state machine:
Now replay the original requirement: "add state, use the PIN style." One edit, inside the full method of Address. One file, one test run, one easy review. Papa's dream: shift the house, update one office, and that office informs everyone else automatically.
The before-and-after is dramatic enough to chart:
College corner: What we just built is the single source of truth — the practical face of the DRY principle ("Don't Repeat Yourself", from The Pragmatic Programmer). But note the precise wording of DRY: every piece of knowledge must have a single, authoritative representation. It is about knowledge, not text. Five visually different lines that all encode the same business rule violate DRY even though no two lines are identical — which is why "find duplicate code" tools catch only the easy cases of Shotgun Surgery. Conversely, two identical-looking lines that encode different decisions (a coincidence) should NOT be merged. Gather by meaning, not by appearance.
Do not over-gather! If you pull unrelated things into one "common" class just to reduce files, you will build a god class — and unrelated reasons will start hitting it. That is Divergent Change, the mirror smell. Gather only what truly changes together for the same reason.
🧪 The same smell in C# and Python
The C# version of the same disease, in a payroll setting. The rule "how professional tax is computed" was never given a home:
// Before: the tax rule lives in three places.
public class PayslipPrinter
{
public string Footer(Employee e) =>
$"Prof. Tax: {(e.GrossPay > 15000 ? 200 : 0)}";
}
public class SalaryCalculator
{
public decimal NetPay(Employee e) =>
e.GrossPay - (e.GrossPay > 15000 ? 200 : 0) - e.Pf;
}
public class ComplianceReport
{
public decimal TotalProfTax(IEnumerable<Employee> all) =>
all.Sum(e => e.GrossPay > 15000 ? 200m : 0m);
}When the state changes the slab — say, tax becomes 208 above 21,000 — three files must change identically. Give the rule one home:
// After: one owner; everyone else delegates.
public static class ProfessionalTax
{
public static decimal For(Employee e) => e.GrossPay > 15000 ? 200m : 0m;
}
public class PayslipPrinter { public string Footer(Employee e) => $"Prof. Tax: {ProfessionalTax.For(e)}"; }
public class SalaryCalculator { public decimal NetPay(Employee e) => e.GrossPay - ProfessionalTax.For(e) - e.Pf; }
public class ComplianceReport { public decimal TotalProfTax(IEnumerable<Employee> a) => a.Sum(ProfessionalTax.For); }The next slab change is a single edit in ProfessionalTax. The payslip, the salary, and the report can never disagree again, because they all read from the same rule.
Python projects catch this disease just as easily — usually through f-strings retyped at every print site:
# Before: the late-fine rule retyped in three modules
# library_desk.py
def fine_for(days_late):
return days_late * 5
# fee_counter.py
def receipt_line(days_late):
return f"Late fine: Rs.{days_late * 5}"
# parent_sms.py
def remind(days_late, phone):
sms.send(phone, f"Pending fine: Rs.{days_late * 5}. Please pay.")
# After: one home — fine_policy.py
FINE_PER_DAY = 5
def fine_for(days_late: int) -> int:
return days_late * FINE_PER_DAY
# Every other module imports fine_for. The next fine change is ONE line.The language never matters. The question is always the same: when this rule changes, how many files open? If the answer is more than one, the rule is homeless.
⚖️ Divergent Change vs Shotgun Surgery
Here is the comparison that every student of code smells must master. These two smells are perfect mirror images, and choosing the wrong diagnosis leads to the wrong medicine.
| Question | Shotgun Surgery | Divergent Change |
|---|---|---|
| Shape of the pain | ONE reason, MANY classes to change | ONE class, MANY reasons to change |
| Story version | One address change, ten offices to visit | One clerk disturbed by every department |
| What is wrong | The concept is smeared with no single home | The class is overloaded with unrelated jobs |
| You notice it when | A "small" change becomes a ten-file hunt | The same file appears in every kind of PR |
| Biggest danger | Forgetting one of the scattered sites | Breaking job B while editing job A |
| The cure direction | Gather — collect pieces into one home | Split — break the class apart |
| Main refactorings | Move Method, Move Field, Inline Class | Extract Class, Move Method |
| Danger of over-curing | Over-gathering creates Divergent Change | Over-splitting creates Shotgun Surgery |
The two diagnostic questions, side by side:
- For one kind of change, how many classes do I edit? Many → Shotgun Surgery → gather.
- For one class, how many kinds of change hit it? Many → Divergent Change → split.
Plot any confusing situation on this map and the diagnosis reads itself off the quadrant:
The address case sits low and to the right: one reason (address presentation), many classes touched — pure Shotgun Surgery. After the cure, the Address class moves to the calm corner: one reason, one class. And the haunted top-right corner? That is a codebase where god classes and scattered rules coexist — both smells at once. It happens, and the treatment order matters: gather the scattered concepts first, then split the god classes, so you always know where things live.
And remember the see-saw warning: the cures pull in opposite directions. Gather too much and you create a god class that everyone edits for every reason (Divergent Change). Split too much and you scatter one concept across confetti classes (Shotgun Surgery). Healthy code sits at the balance point: one responsibility per class, one class per responsibility. Fowler's two smells are simply the two ways of falling off that see-saw.
College corner: In coupling/cohesion terms, Shotgun Surgery is what low cohesion at the system level feels like: the parts of one concept, which belong together (high cohesion demands it), are instead distributed across modules, creating hidden common coupling through shared knowledge rather than shared variables. The compiler sees five independent classes; the business sees one rule. Whenever the business's mental model and the code's module structure disagree, every business-driven change pays a translation tax. Domain-Driven Design people call the fix "aligning the model with the domain" — Meera calls it "one office that informs the others."
🕵️ Where this smell hides in real projects
Practitioners (Fowler's Refactoring, refactoring.guru, the NDepend blog, and countless team retrospectives) report the same hiding spots again and again:
- Magic values sprinkled by hand. Tax rates, fee amounts, limits, URLs, and format strings typed directly at each use site. The day the value changes, the hunt begins.
- Cross-cutting concerns without a wrapper. Logging formats, permission checks, audit entries, and error-response shapes written manually at every endpoint. Changing the policy means sweeping every endpoint.
- Primitive Obsession fallout. When "phone number", "money", or "address" is passed around as raw strings and numbers, every consumer reimplements the formatting and validation. The missing value-object is the missing home.
- Switch statements on the same enum, everywhere. Five different files each switch on
OrderStatus. Add one status, and all five switches need a new case — and the compiler may warn you about none of them. - Layered architectures with rigid ceremony. Adding one field can require touching the entity, the DTO, the mapper, the validator, the API contract, and the UI form. Some of this is unavoidable layering; but when each layer adds no judgement of its own, the ceremony is Shotgun Surgery wearing a suit.
- Microservices sharing a hidden concept. When several services each hard-code the same business rule, a rule change becomes a multi-repo, multi-deploy sweep — the distributed, expensive edition of this smell.
😌 When it is okay to ignore
Honesty time. Not every multi-file change is a disease, and not every scatter is worth consolidating today.
| Situation | Ignore it? | Why |
|---|---|---|
| The change is genuinely cross-cutting (a new parameter must pass through real layers) | Yes | Some sweeps are essential structure, not smell; no gathering removes them |
| The scattered rule changes once in five years | Usually | Consolidation costs more than the rare sweep saves |
| You do not yet understand the concept well | Wait | Gathering too early builds a wrong abstraction, which becomes its own magnet for trouble |
| The "scatter" is two places, both obvious | Probably | Two well-known sites are cheap; a new abstraction may not pay rent |
| The same sweep happens every month and someone missed a site last quarter | No — fix it | The smell is actively producing bugs and dread |
| Each scattered site disagrees slightly with the others | No — fix it | Drift has started; it only gets worse with time |
Rule of thumb: fix the scatter when the change is frequent or the miss is costly. A rare, low-stakes sweep can wait. A monthly sweep that once caused a production bug should be consolidated this sprint — the payoff is immediate and permanent.
💊 Which refactorings cure it
| Refactoring | What it does here | When to reach for it |
|---|---|---|
| Move Method | Moves the scattered logic into the one class that should own the concept | The primary gathering tool |
| Move Field | Brings the related data into the owning class, next to its behavior | When the moved methods keep reaching back for data |
| Inline Class | Folds over-fragmented tiny classes back into one | When the scatter came from splitting too aggressively |
| Extract Class | Creates the missing home when no suitable owner exists | When the concept (like Address) has no class at all yet |
| Replace Primitive with Object | Turns a raw string/number into a concept-owning type | When Primitive Obsession caused the scatter |
The working rhythm: name the concept, create or choose its owner, move behavior and data in, convert call sites one at a time with tests passing after each, and finish only when the next change of that kind will touch exactly one file.
📦 Quick revision box
+--------------------------------------------------------------+
| SHOTGUN SURGERY — QUICK REVISION |
+--------------------------------------------------------------+
| Story : House shifted once -> Aadhaar, bank, school, |
| gas, ration card... ten offices to update |
| Smell : ONE change forces edits in MANY classes |
| Family : Change Preventers |
| Root : A concept was never given a single home |
| Spot it : Confetti PRs; tribal checklists; "missed one |
| place" bugs; cloned rules drifting apart |
| Costs : Errors of omission, costly small changes, |
| weak reviews, inconsistency, locked knowledge |
| Cure : GATHER -> Move Method, Move Field, Inline Class |
| (one home; every old site delegates to it) |
| Opposite : Divergent Change (one class, many reasons) |
| Memory : Shotgun = one shot, many pellets -> GATHER |
| Ignore : Rare changes; genuine cross-cutting layers |
+--------------------------------------------------------------+✏️ Practice exercise
Be the officer who builds "one office that updates all others"!
Exercise 1 — Find the pellets. A school app stores the late-fine rule in several places. List every file you would need to edit if the fine changes from 5 to 10 rupees per day, and identify the homeless concept.
class LibraryDesk {
fineFor(daysLate: number): number { return daysLate * 5; }
}
class FeeCounter {
receiptLine(daysLate: number): string { return `Late fine: Rs.${daysLate * 5}`; }
}
class ParentSms {
remind(daysLate: number, phone: string): void {
smsGateway.send(phone, `Pending fine: Rs.${daysLate * 5}. Please pay.`);
}
}
class AnnualReport {
totalFines(records: { daysLate: number }[]): number {
return records.reduce((s, r) => s + r.daysLate * 5, 0);
}
}Exercise 2 — Build the home. Create a LateFinePolicy class with a single method fineFor(daysLate). Then convert all four classes to delegate to it. After your refactor, the rule change should be a one-line edit.
Exercise 3 — Catch the drift. Suppose ParentSms had quietly used daysLate * 4 because of an old typo. In the scattered version, how long might that bug hide? In the gathered version, can it even exist? Write two sentences explaining why gathering kills this whole bug family.
Exercise 4 — Chart your own scatter. Pick one rule from any project you have (a discount, a date format, a validation regex). Grep for it and draw a pie like Figure 3 of where it lives. If you get more than one slice, write down the name the concept is begging for — that name is your missing class.
Exercise 5 — The diagnosis drill. Shotgun Surgery, Divergent Change, or healthy?
- Adding a new report type means editing only
ReportFactory. - Changing the GST rate requires edits in 7 files across 3 folders.
AppManageris edited for login changes, billing changes, and UI text changes.- Adding a database column requires changing the entity, the migration, and the form — each with its own real logic.
(Think it through: 1 is healthy — one reason, one place. 2 is Shotgun Surgery — gather the rate into one home. 3 is Divergent Change — split the class. 4 is mostly essential layering — each layer adds its own judgement, so the sweep may be irreducible.)
When you can confidently say "this one needs gathering, that one needs splitting", you have mastered both mirror smells. Next, meet the structural special case of this smell: Parallel Inheritance Hierarchies.
Frequently asked questions
- What is Shotgun Surgery in one line?
- Shotgun Surgery is when one small conceptual change — like changing an address format — forces you to make many tiny edits scattered across many different classes and files. One reason, many places to cut.
- Why is it called Shotgun Surgery?
- A shotgun does not make one clean hole; it sprays many small pellets over a wide area. This smell is the same: one change sprays many small edits across the codebase. The 'surgery' part reminds us that each edit is a careful, risky cut.
- How is Shotgun Surgery different from Divergent Change?
- They are exact opposites. Shotgun Surgery is ONE reason that touches MANY classes — fix it by gathering the scattered code into one home. Divergent Change is ONE class hit by MANY reasons — fix it by splitting the class.
- Which refactorings fix Shotgun Surgery?
- Move Method and Move Field gather the scattered behavior and data into one owning class. If the scatter came from splitting things into too many tiny classes, Inline Class folds the fragments back together.
- Is Shotgun Surgery the same as code duplication?
- They are close friends but not the same. Duplicated Code is copies of the same logic; Shotgun Surgery is the pain you feel when changing a concept that has no single home. Duplication is the most common cause, but even non-duplicated, related edits scattered across files count as Shotgun Surgery.
Further reading
Related Lessons
Divergent Change: One Poor Clerk, Too Many Bosses
Learn the Divergent Change code smell with a school clerk story, simple definitions, TypeScript and C# examples, a clear comparison with Shotgun Surgery, and practice.
Parallel Inheritance Hierarchies: Every Sweet Needs Its Shadow Box
Learn the Parallel Inheritance Hierarchies code smell with a sweet-shop story, mirrored class trees explained simply, TypeScript and C# examples, fixes, and practice.
Move Method: Shift Work to the Class Where It Truly Belongs
Learn the Move Method refactoring through a simple school story. Shift a method into the class whose data it uses most so behaviour and data stay together.
Move Field: Keep Data in the Room Where It Is Used
Learn the Move Field refactoring with an easy school story. Move a piece of data to the class that really uses it, so state and behaviour live side by side.