Skip to main content
CleanCodeMastery

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.

27 min read Updated June 11, 2026beginner
divergent changecode smellschange preventerssingle responsibilityextract classtypescript

🏫 The story of Ramesh-ji, the school clerk

Meet Ramesh-ji. He is the only clerk at Saraswati Vidya School in Kanpur. He is a kind man with a small desk, one old computer, and a cup of tea that always goes cold. Why does the tea go cold? Because everyone in the school disturbs him, all day, for completely different reasons.

At 9 in the morning, the exam in-charge madam comes. "Ramesh-ji, the board has changed the marksheet format. Please update all the marksheets." Ramesh-ji nods and opens the marksheet file.

At 10, before he can finish, the accounts sir arrives. "Ramesh-ji, fee structure has changed. Late fine is now 50 rupees, not 20. Update the fee receipts." Ramesh-ji sighs, closes the marksheet file, and opens the fee register.

At 11, the sports sir comes running. "Ramesh-ji! Annual sports day! We need new trophy orders and certificates for the winners!" Ramesh-ji closes the fee register and opens the sports file.

At 12, the exam madam is back. "Ramesh-ji, did you finish the marksheets?" Of course he did not. He never gets to finish one job peacefully, because three different departments treat him as their personal helper.

By 2 in the afternoon, something worse happens. While hurriedly updating a fee receipt, Ramesh-ji writes a fee number on a marksheet by mistake — the papers were lying on the same desk, after all. The exam madam catches it the next day, and now everyone is upset with the most hardworking man in the school.

In the evening, Ramesh-ji writes one line in his small diary: "Today also, three bosses, one desk, zero finished jobs."

Watch his whole day in one picture — and watch his mood scores sink:

Figure 1: One clerk's day — every department lands on the same desk, and his mood keeps falling

Now think carefully. Is Ramesh-ji a bad worker? No. He is hardworking and sincere. The problem is the design of the school office. Three different kinds of work — exams, accounts, and sports — all flow to one person. Every change in any department lands on the same desk.

If the school had three small desks — an exam clerk, an accounts clerk, and a sports clerk — each change would go to exactly one desk. Marksheet change? Exam desk only. Fee change? Accounts desk only. Nobody's tea would go cold, and a fee number could never land on a marksheet, because fee papers and marksheets would never sit on the same desk.

In code, we have classes that suffer exactly like Ramesh-ji. One class gets edited for exam reasons, fee reasons, and sports reasons. This smell has a name: Divergent Change.

🤔 What is this smell?

Divergent Change happens when one class is commonly changed in many different ways, for many different reasons.

The word "divergent" means "going in different directions". The changes that arrive at this class diverge — they come from completely different directions. A tax rule change, a database change, an email format change — all of them open the same file.

Martin Fowler describes this smell in his famous book Refactoring. His simple test is this: when you say things like "I have to change these three methods every time the database changes, and these four methods every time a new payment type is added," the class is suffering from Divergent Change. Two different kinds of future are pulling on the same class.

This smell belongs to a family called Change Preventers. These are smells that make change painful. The code does not stop you from changing it — but it makes every change slow, scary, and expensive. So, slowly, the team starts avoiding changes. That is the real damage.

There is a deep principle hiding here. The Single Responsibility Principle (SRP) says: a class should have only one reason to change. Divergent Change is what an SRP violation looks like in real, daily life. You do not see SRP breaking in a diagram — you feel it when the same poor class keeps appearing in every kind of pull request, like Ramesh-ji appearing in every department's complaint list.

College corner: Notice the exact wording of SRP. Uncle Bob does not say "a class should do only one thing" — he says it should have only one reason to change, and he later sharpened it to "a module should be responsible to one, and only one, actor." An actor is a group of people who request changes: the exam team, the accounts team, the sports team. Divergent Change is precisely the situation where multiple actors share one module. When you write your design documents in college, do not count functions to check SRP — count actors. One actor per class is the goal; Ramesh-ji had three.

💡

Easy memory trick: Divergent Change = one Ramesh-ji, many bosses. One class, many reasons to change. The cure is to give each boss their own clerk — split the class so each reason has its own home.

One more important point. Divergent Change is hard to see in a single screenshot of code. It is a smell of history. A class might look only "a bit big" today. But if you open its git log and see commits like "fix tax rounding", "change email template", "switch to new database driver" — all on the same file — the smell becomes loud and clear.

Here is the whole idea of this smell as one map you can revise from:

Figure 2: The Divergent Change mind map — signs, costs, cures, and its mirror smell

🔍 How to spot it

You spot Divergent Change by watching what kinds of changes land on a class. Here is a simple checklist. If you tick three or more boxes, you very likely have this smell.

  • When different kinds of requirements change, you always open the same class.
  • The class's git history looks like the changelog of the whole product, not of one feature.
  • The methods inside form separate "islands" — one group talks to the database, another formats text, another sends messages — and the islands share almost no fields.
  • The class name is vague: Manager, Processor, Handler, Service, Util. The name had to be vague to cover so many jobs.
  • The import list at the top of the file looks like a tour of the whole system — networking, storage, formatting, and math all together.
  • You cannot describe the class in one sentence without using the word "and".

Here is the same idea as a quick reference table:

SignWhat you observeWhat it means
Magnet fileUnrelated pull requests keep touching one fileMany reasons to change live in one place
Method islandsGroups of methods that never share fieldsSeveral hidden classes are trapped inside one
Vague nameOrderManager, StudentHelper, DataServiceThe name covers too many jobs to be specific
Import zooDB, HTTP, email, and formatting imports in one fileThe class talks to every corner of the system
Re-test fearA small fee change forces re-running exam testsResponsibilities are tangled, not separated
The "and" test"It calculates fees AND prints marksheets AND..."More than one responsibility, guaranteed

A practical tip for real projects: run git log --oneline -- path/to/File.ts and read the commit messages. If the messages belong to three different departments of your product, you have found your Ramesh-ji.

You can even draw the evidence. Take the last twenty commits that touched the suspect class and sort them by the kind of reason behind each one. A healthy class produces a boring chart — one giant slice. A Ramesh-ji class produces a colourful pizza:

Figure 3: Sort the last 20 commits on one class by reason — a colourful pie like this is the smell's fingerprint

If your pie has one dominant slice, relax — the class has one master. If it looks like the one above, with three or four healthy slices of unrelated reasons, the class is serving too many masters.

⚠️ Why it is a problem

You might ask: "So what if one class does many things? The code still runs!" True. But remember — Change Preventers do not break the program. They break the team's speed and confidence. Here is the cost, step by step.

1. Every edit is risky. To change the fee logic, you must scroll past marksheet code and sports code. Your eyes get tired. One wrong line, and you break exams while fixing fees. Unrelated things sitting together means unrelated things breaking together — exactly like the fee number that landed on a marksheet on Ramesh-ji's crowded desk.

2. Merge conflicts everywhere. In a team, the exam developer and the accounts developer both edit the same file in the same week. Git cries. Time is wasted resolving conflicts between changes that had no business meeting each other.

3. Tests become slow and fat. You cannot test the fee calculation alone, because it is tangled with database code and email code. So tests need a database, a mail server, everything. Slow tests get skipped. Skipped tests mean bugs.

4. Nothing can be reused. The nice marksheet formatting logic cannot be used in another project, because it is glued to the fee logic and the trophy logic in the same class.

5. New developers suffer. To safely change one small thing, a newcomer must understand the whole 800-line class. The learning cost of a tiny change becomes huge.

Figure 4: Many unrelated reasons all pull on one class — every department's change lands on the same file

Notice the last box: the team avoids changes. That is the quiet, final cost. When changing a file feels dangerous, people stop improving it. The class rots, grows, and becomes the famous "nobody touches that file" of your project.

Cost number 2 — the merge conflict — deserves its own picture, because it is the cost college students feel first when they do their first group project. Two teammates, two completely unrelated tickets, one shared class:

Figure 5: Two developers, two unrelated reasons, one class — and Git delivers the bad news

College corner: This is where the textbook words coupling and cohesion become real. Cohesion measures how strongly the parts inside one module belong together. A Divergent Change class has low cohesion: its exam methods, fee methods, and sports methods are strangers sharing a flat. And because every consumer of any of those jobs must depend on the whole class, the class also drags in high coupling — the fee module's callers are accidentally coupled to exam code they never use. The classic design goal "high cohesion, low coupling" is just Ramesh-ji's story in formal clothes: give each job its own desk (cohesion), so departments stop bumping into each other (coupling).

💻 A real-life code example

Let us write Ramesh-ji's desk as code. Here is the school's software, with everything dumped into one class — exactly how it grows in real projects, one "small" method at a time.

// SchoolClerk.ts — the poor class everyone disturbs
class SchoolClerk {
  // ----- Reason to change #1: EXAM rules -----
  prepareMarksheet(student: Student): string {
    const total = student.marks.reduce((sum, m) => sum + m.score, 0);
    const percent = (total / (student.marks.length * 100)) * 100;
    const grade = percent >= 90 ? "A+" : percent >= 75 ? "A" : "B";
    return `MARKSHEET\n${student.name}\nPercent: ${percent.toFixed(1)}\nGrade: ${grade}`;
  }
 
  // ----- Reason to change #2: FEE rules -----
  generateFeeReceipt(student: Student, paidOn: Date): string {
    const baseFee = 1200;
    const dueDate = new Date(paidOn.getFullYear(), paidOn.getMonth(), 10);
    const lateFine = paidOn > dueDate ? 50 : 0; // accounts sir changes this often!
    return `RECEIPT\n${student.name}\nFee: ${baseFee}\nFine: ${lateFine}\nTotal: ${baseFee + lateFine}`;
  }
 
  // ----- Reason to change #3: SPORTS events -----
  orderTrophies(eventName: string, winners: Student[]): string[] {
    return winners.map(
      (w, rank) => `Trophy: ${eventName} - Rank ${rank + 1} - ${w.name}`
    );
  }
 
  // ----- Reason to change #4: STORAGE -----
  saveRecord(student: Student): void {
    // talks to the database — changes when the school changes its software vendor
    db.execute("INSERT INTO students ...", student);
  }
}

Look at the comments. Four different departments own four different parts of this class. Exam madam will ask you to change prepareMarksheet. Accounts sir owns generateFeeReceipt. Sports sir owns orderTrophies. And the IT vendor owns saveRecord. Four bosses, one class. That is textbook Divergent Change.

Here is the same situation as a class diagram — before the cure on the left side of your imagination, after the cure on the right. The overloaded clerk delegates nothing; the healthy office has one small desk per reason:

Figure 6: The overloaded class versus the four small desks it should become

The danger is real: suppose accounts sir says "fine is now 75 rupees". You open this file, change one number — and your editor's auto-format accidentally touches the marksheet method too. Now your one-line fee change needs the exam tests to run as well, "just in case". Everything is connected because everything lives together.

🛠️ Cleaning it up, step by step

The cure is to split the class along its reasons for change. Each reason gets its own small class. The main tool is Extract Class, helped by Move Method and Move Field. Do it gradually — one responsibility at a time, with tests running after each step.

Step 1 — List the reasons. Read the class and ask of every method: "Who asks me to change this?" Write the answers down. For SchoolClerk we get: exam team, accounts, sports, IT vendor. Four reasons. So we aim for four homes.

Step 2 — Extract the first responsibility. Pick one cluster — say, exams — and use Extract Class to give it a home of its own:

// ExamOffice.ts — owned by the exam team only
class ExamOffice {
  prepareMarksheet(student: Student): string {
    const total = student.marks.reduce((sum, m) => sum + m.score, 0);
    const percent = (total / (student.marks.length * 100)) * 100;
    const grade = this.gradeFor(percent);
    return `MARKSHEET\n${student.name}\nPercent: ${percent.toFixed(1)}\nGrade: ${grade}`;
  }
 
  private gradeFor(percent: number): string {
    return percent >= 90 ? "A+" : percent >= 75 ? "A" : "B";
  }
}

Then, inside SchoolClerk, the old method simply delegates: prepareMarksheet(s) just returns this.examOffice.prepareMarksheet(s). Run the tests. Everything still works, but the exam logic now has its own room.

Step 3 — Repeat for each remaining reason. Use Move Method to carry the fee logic into an AccountsDesk, the trophy logic into a SportsDesk, and the saving logic into a StudentRepository. If a method drags some data with it (like the base fee amount), use Move Field so the data travels with its behavior.

// After the full split: each class has exactly ONE reason to change
class AccountsDesk {
  private readonly baseFee = 1200;
  private readonly lateFine = 50;
  generateFeeReceipt(student: Student, paidOn: Date): string { /* fee logic only */ }
}
 
class SportsDesk {
  orderTrophies(eventName: string, winners: Student[]): string[] { /* sports only */ }
}
 
class StudentRepository {
  saveRecord(student: Student): void { /* storage only */ }
}

Step 4 — Decide the fate of the old class. Sometimes the original class becomes a thin coordinator that simply holds the four desks together — that is fine. Sometimes it becomes empty, and you delete it. Either ending is a happy ending.

Step 5 — Apply the one-sentence test. Describe each new class in one sentence. "AccountsDesk calculates fees and fines." "SportsDesk prepares trophy orders." No "and" joining unrelated jobs? You are done.

The whole life of the class — from healthy, to overloaded, to cured — looks like this:

Figure 7: The life cycle of a Divergent Change class — duties pile up slowly, the cure is a deliberate split

And the payoff is measurable. Count how many unrelated reasons can force an edit on each class, before and after the split:

Figure 8: The split in numbers — reasons to change per class drop from four to one

Now watch what happens next month. Accounts sir changes the fine to 75 rupees. You open AccountsDesk, change one number, run only the fee tests, and go home on time. The exam code was never even opened. That is the whole reward.

College corner: John Ousterhout, in A Philosophy of Software Design, gives this pain a precise name: change amplification — when a simple change requires modifications in many places, or forces you to understand far more code than the change itself deserves. Divergent Change amplifies understanding: a one-line fee edit demands that you understand (or at least carefully step around) 800 lines of exam and sports code. After the split, the understanding needed shrinks to exactly the size of the change. Reducing change amplification is one of the most practical definitions of "good design" you will ever get.

⚠️

Do not over-split! If you make twenty tiny classes that always change together, you have created the opposite smell — Shotgun Surgery. Split by reason for change, not by number of methods. Two methods that always change together belong together.

🧪 The same smell in C# and Python

The smell looks identical in C#. Here is a compact version — one OrderProcessor that changes for pricing reasons, storage reasons, and email reasons:

// Before: three reasons to change, one class
public class OrderProcessor
{
    public decimal CalculateTotal(Order order)   // changes when tax rules change
    {
        var subtotal = order.Lines.Sum(l => l.Price * l.Qty);
        return subtotal + subtotal * 0.18m; // GST
    }
 
    public void Save(Order order)                // changes when the database changes
    {
        using var conn = new SqlConnection(_cs);
        conn.Execute("INSERT INTO Orders ...", order);
    }
 
    public void SendConfirmation(Order order)    // changes when email design changes
    {
        _smtp.Send(order.Email, "Your order", RenderHtml(order));
    }
}

After splitting along the reasons for change:

// After: one reason per class
public class PricingCalculator { public decimal CalculateTotal(Order o) { /* tax only */ } }
public class OrderRepository   { public void Save(Order o) { /* storage only */ } }
public class OrderNotifier     { public void SendConfirmation(Order o) { /* email only */ } }

A GST change now touches only PricingCalculator, and only its tests need to run. The database team and the email team never collide with the tax team again.

Python students, do not feel left out — dynamic typing hides nothing from this smell. A Django or Flask project grows the exact same Ramesh-ji, usually named utils.py or helpers.py:

# student_service.py — Before: one class, three bosses
class StudentService:
    def prepare_marksheet(self, student):       # exam team owns this
        percent = sum(m.score for m in student.marks) / len(student.marks)
        grade = "A+" if percent >= 90 else "A" if percent >= 75 else "B"
        return f"MARKSHEET\n{student.name}\n{percent:.1f}% — {grade}"
 
    def fee_receipt(self, student, paid_on):    # accounts owns this
        fine = 50 if paid_on.day > 10 else 0
        return f"RECEIPT\n{student.name}\nTotal: {1200 + fine}"
 
    def order_trophies(self, event, winners):   # sports owns this
        return [f"Trophy: {event} - Rank {i + 1} - {w.name}"
                for i, w in enumerate(winners)]
 
# After: one small class per reason — ExamOffice, AccountsDesk, SportsDesk

The language changes; the diagnosis question does not: who asks for each method to change? If the answers differ, the class must split.

⚖️ Divergent Change vs Shotgun Surgery

This is the most important comparison in the whole Change Preventers family, and students mix these two up all the time. Here is the clean way to remember: they are mirror opposites.

QuestionDivergent ChangeShotgun Surgery
Shape of the painONE class, MANY reasons to changeONE reason, MANY classes to change
Story versionOne clerk disturbed by every departmentOne address change, ten offices to visit
What is wrongThe class is overloaded with jobsThe job is smeared across the codebase
You notice it whenThe same file appears in every kind of PRA "small" change becomes a ten-file hunt
The cure directionSplit — break the class apartGather — collect the pieces into one home
Main refactoringsExtract Class, Move MethodMove Method, Move Field, Inline Class
Principle violatedSingle Responsibility (too many reasons)Single ownership (no single home for a concept)
Danger of over-curingOver-splitting creates Shotgun SurgeryOver-gathering creates Divergent Change
Figure 9: Mirror opposites — many reasons hitting one class, versus one reason hitting many classes

The diagnostic question is beautifully symmetric. Ask two things:

  1. For one class, how many kinds of change hit it? Many → Divergent Change → split.
  2. For one kind of change, how many classes do I edit? Many → Shotgun Surgery → gather.

You can place any suspicious situation on a simple map. The horizontal axis asks how many classes a change touches; the vertical axis asks how many reasons touch one class. Healthy code sits in the calm corner; each smell owns its own corner; and yes, truly unlucky codebases manage both at once:

Figure 10: The diagnosis map — plot your situation and read off the smell

Our SchoolClerk sits high on the left: one class, many reasons — Divergent Change territory. An address format smeared across ten files sits low on the right — Shotgun Surgery territory. A healthy PricingEngine that changes for pricing reasons only, and changes alone, sits in the calm bottom-left corner.

And note the warning in the table's last row. The two cures push in opposite directions. If you split too enthusiastically, related code gets scattered and every change becomes a multi-file hunt — you have traded one smell for its mirror. The goal is balance: each class owns one responsibility, and each responsibility lives in one class.

🕵️ Where this smell hides in real projects

Divergent Change loves certain hiding spots. Researchers and practitioners (Fowler's Refactoring, refactoring.guru, and many code-quality blogs) keep finding it in the same places:

  • "God" service classes. UserService, OrderManager, AppHelper — classes whose vague names invited everyone to dump code there. In many codebases, one such class quietly handles validation, formatting, persistence, and notifications.
  • Controllers in web apps. A controller that validates input, applies business rules, talks to the database, and shapes the JSON response changes for four different reasons. Framework tutorials often teach this shape, so it spreads.
  • Utility classes. Utils.ts and Helpers.cs are Divergent Change by design — a drawer where every department throws its odd socks.
  • Configuration and startup files. One giant startup class that wires logging, database, security, and caching changes whenever any of those areas changes.
  • Long-living legacy classes. The oldest classes in a system attract code by gravity. The path of least resistance — "just add one more method here" — repeated for five years, produces a perfect Ramesh-ji.

A practical detection trick used in real teams: tooling that ranks files by number of distinct authors and number of commits. Files high on both lists are usually Divergent Change suspects, because many people changing one file for many tickets is exactly the smell's signature.

😌 When it is okay to ignore

Good engineers are honest: not every smelly class deserves surgery today. Here is the honest table.

SituationIgnore it?Why
The class is rarely edited (twice in two years)YesThe smell is theoretical; splitting buys nothing real
Early prototype, requirements still fuzzyYes, for nowBoundaries are not visible yet; premature splits will be wrong splits
The "different" responsibilities always change togetherYesThey are really one responsibility; splitting creates artificial seams
Small script or throwaway toolYesIndirection costs more than it saves in tiny code
The file appears in unrelated PRs every sprintNo — fix itThe smell is active and charging you interest every week
Two teams keep merge-conflicting on the same classNo — fix itThe split also splits team ownership, ending the conflicts

The rule of thumb: let the edit history decide. Code smells are hints, not laws. A class with many responsibilities that never changes is an academic problem. A class that keeps appearing in unrelated commits is an expensive, active problem — fix that one first.

💊 Which refactorings cure it

RefactoringWhat it does hereWhen to reach for it
Extract ClassPulls one whole responsibility into a new, focused classThe primary cure — use it once per reason-to-change
Move MethodCarries a single method to the class where its reason livesWhen a method clearly belongs to an already-extracted home
Move FieldMoves data next to the behavior that uses itWhen extracted methods keep reaching back for old fields
Extract FunctionSplits a multi-job method before class-level surgeryWhen the tangle is inside individual methods too
Extract Superclass / SubclassOrganizes split classes that share common behaviorWhen the new classes turn out to be natural siblings

Work in small, safe steps: extract one responsibility, run the tests, commit, repeat. Never do the whole split in one giant risky change — that would be ironic for a smell whose whole lesson is about making change safe.

📦 Quick revision box

+--------------------------------------------------------------+
|              DIVERGENT CHANGE — QUICK REVISION               |
+--------------------------------------------------------------+
| Story    : One school clerk, disturbed by EVERY department   |
| Smell    : ONE class changed for MANY different reasons      |
| Family   : Change Preventers                                 |
| Breaks   : Single Responsibility Principle (SRP)             |
| Spot it  : Same file in unrelated PRs; vague name; method    |
|            islands; import zoo; fails the one-sentence test  |
| Costs    : Risky edits, merge conflicts, slow tests,         |
|            no reuse, team afraid to change the file          |
| Cure     : SPLIT the class -> Extract Class, Move Method,    |
|            Move Field (one responsibility per class)         |
| Opposite : Shotgun Surgery (one reason, many classes)        |
| Memory   : Divergent = one desk, many bosses -> SPLIT        |
| Ignore   : If the class is stable and rarely edited          |
+--------------------------------------------------------------+

✏️ Practice exercise

Time to be the school principal who fixes the office!

Exercise 1 — Spot the reasons. Below is a class from a small shop's software. List every reason to change you can find, and name who (which "department") owns each reason.

class ShopAssistant {
  calculateBill(items: Item[]): number {
    const total = items.reduce((s, i) => s + i.price * i.qty, 0);
    return total > 1000 ? total * 0.95 : total; // 5% festival discount
  }
  printLabel(item: Item): string {
    return `${item.name} — Rs.${item.price} (MRP incl. all taxes)`;
  }
  reorderStock(item: Item): void {
    if (item.qty < 5) supplierApi.placeOrder(item.name, 50);
  }
  sendOfferSms(customer: Customer): void {
    smsGateway.send(customer.phone, "Festival sale! 5% off above Rs.1000");
  }
}

Exercise 2 — Plan the split. For each reason you found, propose a new class name (one sentence describing its single job). You should end with three or four small classes.

Exercise 3 — Do one extraction. Actually perform Extract Class for the billing responsibility only. Make ShopAssistant delegate to your new class so all old callers still work.

Exercise 4 — Draw the pie. Open any project you have written (even a college assignment) and pick its biggest class. Sort its methods by who would ask for each to change. Sketch the pie chart from Figure 3 for your class. One big slice? Healthy. A colourful pizza? You know what to do.

Exercise 5 — The diagnosis drill. For each situation below, say whether it is Divergent Change, Shotgun Surgery, or neither:

  1. Renaming a status value forces edits in 11 files.
  2. The InvoiceManager class is edited for tax changes, PDF layout changes, and email changes.
  3. A 40-line class has not been touched in 18 months.
  4. Every discount rule change means editing PricingEngine — and only PricingEngine.

(Answers to think about: 1 is Shotgun Surgery — one reason, many files. 2 is Divergent Change — one class, many reasons. 3 is no active smell — stable code earns no surgery. 4 is healthy design — that is exactly how it should feel!)

If you can explain to a friend why number 2 needs splitting but number 1 needs gathering, you have truly understood the Change Preventers family. Next, read about the mirror smell: Shotgun Surgery.

Frequently asked questions

What is Divergent Change in one line?
Divergent Change is when one class keeps getting edited for many different, unrelated reasons — exam reasons today, fee reasons tomorrow, sports reasons next week. The class has too many jobs, so every kind of change lands on it.
How is Divergent Change different from Shotgun Surgery?
They are exact opposites. Divergent Change is ONE class changed for MANY reasons — the fix is to split the class. Shotgun Surgery is ONE reason that forces changes in MANY classes — the fix is to gather the scattered code into one place.
Which refactoring fixes Divergent Change?
Extract Class is the main cure. You pull each separate responsibility out into its own small class. Move Method and Move Field help you carry the methods and data to their new homes.
How is Divergent Change related to the Single Responsibility Principle?
Divergent Change is what SRP violation feels like in daily work. SRP says a class should have only one reason to change. A class with Divergent Change has many reasons to change, so it breaks SRP by definition.
Is every big class a case of Divergent Change?
No. A class can be big but still have one clear job. Divergent Change is about reasons for change, not size. Check the edit history: if unrelated requests keep landing on the same class, the smell is real. If the class is stable and rarely edited, leave it alone.

Further reading

Related Lessons