Push Down Field: Swimming Pool Timings Belong on 7C's Board Only
Learn the Push Down Field refactoring with a school notice-board story — move a superclass field that only some subclasses use down into exactly those subclasses, with safe steps in TypeScript and C#, IDE dialogs, and the pull-up vs push-down compass.
🏊 Swimming pool timings on the main board
One last visit to Sunrise Public School — and this time, the problem is upside down.
You remember the rule from the Pull Up Field story: shared information goes on the main office board. The school followed it faithfully. The address went up. The phone number went up. The exam timetable went up. Head clerk Mr. Sharma kept the main board so well that it became the trusted single home for everything common.
But rules applied without thinking create their own mess. One day, the sports teacher pinned a new notice on the main office board: "Swimming Pool Timings — Mon/Thu 8:00–9:30." He meant well. The main board was where important notices went, and to him, nothing was more important than pool timings.
Now, here is the thing about Sunrise School: only 7C, Ms. Fernandes' sports section, has swimming. Mrs. Iyer's 7A has Mathematics in that slot; Mr. Bose's 7B has English. The pool timings mean nothing to two-thirds of the school.
Watch what this one misplaced notice did:
- A 7A student read the main board, assumed the timings applied to everyone, and turned up at the pool with a towel — missing his maths class. Mrs. Iyer marked him absent; his mother got a worried phone call; the misunderstanding took two days to untangle.
- A new teacher, preparing 7B's timetable, called Mr. Sharma's office to ask which lane 7B had been allotted. Mr. Sharma had to explain, again, that 7B has no swimming. He keeps a count, half-jokingly, of how many times he answers this question — it is once every single term.
- The main board grew crowded. Students stopped reading it carefully, because "half of it doesn't apply to me anyway" — and so they also missed notices that did apply to them.
The main board made a silent promise: everything here concerns every section. The pool notice broke that promise, and the cost was paid in confusion, wasted questions, and a board nobody trusted fully.
The fix took Headmistress Dr. Meena Kulkarni thirty seconds. She unpinned the notice from the main board and pinned it on 7C's section board, where every reader actually has swimming. The main board went back to telling the truth: all of it for all of us. And 7C's board now carried its own special information, right where Meera and her classmates actually look.
In code, the main board is the superclass and the section boards are subclasses. When a field sits in the parent but only some children use it, we move it down into exactly those children. This is Push Down Field — the precise mirror image of the refactoring that started this series.
The week around the misplaced notice, from the students' side:
📌 What is Push Down Field?
Push Down Field comes from the same "dealing with generalization" family in Martin Fowler's Refactoring catalog, and its instruction is the mirror of Pull Up Field's:
When a field declared in a superclass is used by only some of its subclasses, remove it from the superclass and declare it only in the subclass(es) that actually need it.
How does a field end up too high in the first place? Three common stories:
- Planned features that shrank. The designer thought every section would get swimming "eventually", so
swimmingPoolTimingswent intoSectionfrom day one. Eventually never came. This is the Speculative Generality smell — structure built for a future that did not arrive. - Hierarchies that changed shape. Once upon a time the school had only one section and it did swim. More sections were added later, the field stayed up, and nobody re-examined it.
- Over-enthusiastic pulling up. Someone read about Pull Up Field, saw two subclasses with a similar-looking field, and hoisted it — without checking the third and fourth subclasses that never wanted it.
Whatever the story, the result is the same: the superclass declares state that is not genuinely common, and every subclass inherits it whether it wants to or not. The children that never use the field are carrying dead weight — and worse, misleading weight, because a parent field is a printed promise: "all my children have this." Readers believe the promise. Code completion shows the field on every subclass. New teammates write code against it. The 7A student walks to the pool.
This is the structural face of the Refused Bequest smell — a bequest is an inheritance, and the subclasses are refusing theirs. Push Down Field is its most direct cure for data.
One-line summary: Push Down Field moves a field that only some subclasses use out of the superclass and into exactly those subclasses — like unpinning the swimming-pool timings from the main office board and pinning them on 7C's board, the only section that swims.
And there is a bonus prize. In the parent, the field had to be at least protected, so every subclass could touch it. Once it lives inside the single class that uses it, it can usually be tightened back to private. Smaller visibility means fewer places that can read or break it — the field's blast radius shrinks to one class.
College corner: push-down is where the protected visibility trade-off finally pays you back. protected is a halfway house: wider than private (every subclass, including ones written years from now, can depend on the field) but narrower than public. Each pull-up spends encapsulation to buy sharing; each push-down refunds it. There is also a Liskov Substitution Principle angle: a parent field that is meaningless for most children quietly violates the spirit of substitutability — code holding a Section reference cannot safely use poolTimings even though the type says it can. The parent's interface should be the intersection of what all children honestly support, not the union of everything any child ever needed. Push Down Field trims the union back to the intersection.
Where this move lives on the family map — the downward branch is the hero this time:
🔍 When do we need it?
The signs to watch for:
- A parent field that most subclasses never read or write. Search for usages: if
swimmingPoolTimingsis referenced only fromSectionSevenC, the field is living one floor too high. This is Refused Bequest in its quietest form — no error, no warning, just an inheritance the children silently ignore. - Fields that are
null/undefinedfor most children. IfPassengerCarleavescargoVolumeas null forever, and everyone "knows" not to touch it on that type, the hierarchy is lying about itself and everyone is compensating from memory. - Explaining the exception over and over. "Oh, that field — ignore it unless you are in the sports section." Any sentence of that shape, said twice, is a refactoring request. Mr. Sharma answering the same 7B lane question every term is this exact signal, measured in clerk-hours.
- The parent is bloated with one-child specials. Three fields for one subclass, two for another — the superclass has become a crowded main board that nobody reads carefully. Each push-down makes the parent's promise honest again.
And the signs to stop:
- All (or nearly all) subclasses use the field. Then it is genuinely common and belongs upstairs — pushing it down would create the Duplicate Code problem that Pull Up Field exists to fix. The two refactorings are inverses; do not undo good work in the wrong direction.
- Code accesses the field through the parent type. If some report module reads
section.swimmingPoolTimingson a variable typedSection, that code breaks the moment the field moves down. Sometimes the fix is to make that code work with the subclass; sometimes the breakage is telling you the field really is part of the parent's contract. Listen to it. - The "only some" subset keeps growing. If two subclasses use the field today and a third will next month, perhaps the subset is a real concept needing its own class — an intermediate
SportsSectionparent, or an Extract Subclass move — rather than scattered copies.
On the placement map, the pool-timings field is the exact mirror of the school address from the first post — used by one subclass, but living in the base:
Read it against Figure 3 of the Pull Up Field post: the address dot sat bottom-right (pull up now); this dot sits top-left (push down now). Two mistakes, two opposite corrections, one map.
👀 Before and after at a glance
Here is the school's class hierarchy with the misplaced notice. The pool timings sit in Section, so every section inherits them:
// BEFORE: a one-section field forced on every section
abstract class Section {
protected schoolAddress = "12 Lake Road, Pune 411001"; // truly shared — fine
protected poolTimings = "Mon/Thu 8:00-9:30"; // only 7C ever uses this!
protected poolLane = 0; // meaningless for 7A, 7B
}
class SectionSevenA extends Section {
// never touches poolTimings or poolLane — but inherits both
}
class SectionSevenB extends Section {
// never touches them either — dead weight, quietly misleading
}
class SectionSevenC extends Section {
swimmingPlan(): string {
return `Swimming at ${this.poolTimings}, lane ${this.poolLane}`;
}
}SectionSevenA and SectionSevenB carry two fields they never use. Autocomplete offers poolTimings on a 7A object as if it meant something. The parent's promise — "all sections have this" — is false. Look at who actually reads the field versus who is forced to inherit it:
After Push Down Field:
// AFTER: the field lives exactly where it is used
abstract class Section {
protected schoolAddress = "12 Lake Road, Pune 411001"; // the parent keeps
// only what is truly common
}
class SectionSevenA extends Section {} // clean — nothing irrelevant inherited
class SectionSevenB extends Section {} // clean
class SectionSevenC extends Section {
private poolTimings = "Mon/Thu 8:00-9:30"; // moved down — and now PRIVATE
private poolLane = 4;
swimmingPlan(): string {
return `Swimming at ${this.poolTimings}, lane ${this.poolLane}`;
}
}Notice two upgrades, not one. The fields moved down, and they tightened from protected to private — nobody outside 7C needs them, so nobody outside 7C can touch them. The parent is honest, the children are clean, and the special data sits behind the smallest possible door.
And the count of classes carrying irrelevant pool state, before and after:
🪜 Step-by-step, the safe way
Push Down Field is mechanically simple, but the verification step matters more than in any pull-up, because you are about to remove something from a widely visible place. The overall flow:
-
Find every usage of the field — really every one. Use your IDE's "Find Usages" on the parent's field, not a text search alone. You must answer two questions precisely: which subclasses touch the field, and does any code access it through a parent-typed reference? In our example: only
SectionSevenCusespoolTimings, and no code reads it via aSectionvariable. Green light. -
Declare the field in each subclass that actually uses it. For now, keep the same visibility (
protected) so nothing else changes yet. This is the intermediate state — the field briefly exists in both places, which is safe because behaviour stays identical:// INTERMEDIATE: declared in the real user; parent copy still present class SectionSevenC extends Section { protected poolTimings = "Mon/Thu 8:00-9:30"; // new home, same visibility protected poolLane = 4; // ... }Compile and run the tests.
-
Remove the field from the superclass. Delete
poolTimingsandpoolLanefromSection. Compile. If the compiler complains anywhere other than code you expected, congratulations — step 1 missed a usage, and the compiler just found it for you. Investigate before continuing: maybe that code should use the subclass type, or maybe the field is more shared than you thought. -
Run the full test suite. Behaviour must be unchanged: 7C still swims at the same time, in the same lane; 7A and 7B never cared.
-
Tighten the visibility. Now that the field lives in one class, change
protectedtoprivate(and considerreadonlyif it never changes after construction). Compile and test once more. -
Sweep for related members. A pushed-down field often travels with friends: a method that uses it (
swimmingPlan()was already in 7C — good), a constructor parameter that fills it, a parent method that mentioned it. Move the companions down too — the method version of this move is Push Down Method, the same compass pointing the same way.
The field's lifecycle through these steps — note that the downward journey ends in a Tightened state that no pull-up ever reaches:
The dangerous moment is step 3, the deletion from the parent — and your protection is compiling and testing between steps 2 and 3, not after both. If you add the subclass copy and delete the parent copy in one big edit and something fails, you cannot tell whether the new declaration or the deletion caused it. Two small steps, two green checkpoints. Also: never skip step 1's "parent-typed access" check — tests may not cover the one report module that reads the field through a Section reference, and that breakage will surface at the worst time.
The compile-time story after the move is worth one more picture. When old code tries to read the pool field through a parent-typed reference, the compiler now refuses — and that refusal is the refactoring working, not failing:
🏗️ A bigger real-life example
The school's full timetable system shows how push-down cleans a genuinely crowded parent. Over the years, Section collected specials for everyone:
// BEFORE: the parent has become a crowded main board
abstract class Section {
protected schoolAddress = "12 Lake Road, Pune 411001"; // shared — stays
protected classTeacher = ""; // shared — stays
protected poolTimings = ""; // only the sports section (7C)
protected poolLane = 0; // only the sports section (7C)
protected labAssistant = ""; // only the science section (7B)
protected chemicalsRegister: string[] = []; // only the science section (7B)
}
class SectionSevenA extends Section {
// uses NONE of the four specials — pure refused bequest
}
class SectionSevenB extends Section {
labSafetyBriefing(): string {
return `Lab assistant ${this.labAssistant} keeps the register of ` +
`${this.chemicalsRegister.length} chemicals`;
}
}
class SectionSevenC extends Section {
swimmingPlan(): string {
return `Swimming at ${this.poolTimings}, lane ${this.poolLane}`;
}
}Look at poor SectionSevenA — Mrs. Iyer's ordinary section inherits four fields it has no use for. And the parent class reads like the cluttered main board: a stranger cannot tell which fields define "a section of this school" and which are one section's private business.
Push each special down to its real owner, one field at a time, testing between moves:
// AFTER: each board carries exactly its own notices
abstract class Section {
protected schoolAddress = "12 Lake Road, Pune 411001";
protected classTeacher = "";
// That is ALL sections truly share — the parent's promise is honest again.
}
class SectionSevenA extends Section {
// nothing irrelevant inherited; what you see is what 7A has
}
class SectionSevenB extends Section {
private labAssistant = "Mr. Rao"; // science specials, private now
private chemicalsRegister: string[] = [];
labSafetyBriefing(): string {
return `Lab assistant ${this.labAssistant} keeps the register of ` +
`${this.chemicalsRegister.length} chemicals`;
}
}
class SectionSevenC extends Section {
private poolTimings = "Mon/Thu 8:00-9:30"; // sports specials, private now
private poolLane = 4;
swimmingPlan(): string {
return `Swimming at ${this.poolTimings}, lane ${this.poolLane}`;
}
}The superclass shrank to its honest core. Each subclass now documents itself: open SectionSevenB and the lab fields tell you immediately what makes the science section special. And all four moved fields became private — four doors narrowed.
One more thought before we leave the example. Suppose next year the school opens SectionSevenD, another sports section that also swims. Now two subclasses need the pool fields. Push Down Field would mean two copies — tolerable, but smelly. The better design at that point is an intermediate parent: a SportsSection class between Section and the two swimming sections, holding the pool fields once. The compass generalizes beautifully: every member should live at the lowest level where everyone below it still needs it. One user → that subclass. Some users → an intermediate class for exactly that group. All users → the root.
🐍 The same idea in Python
Python's push-down looks the same, and the underscore conventions make the visibility tightening visible in the names themselves:
# BEFORE: one-section state declared for every section
class Section:
def __init__(self):
self._school_address = "12 Lake Road, Pune 411001"
self._pool_timings = "Mon/Thu 8:00-9:30" # only SectionSevenC uses these
self._pool_lane = 0
# AFTER: pool state lives in the sports section only
class Section:
def __init__(self):
self._school_address = "12 Lake Road, Pune 411001"
class SectionSevenA(Section):
pass # honest and empty-handed
class SectionSevenC(Section):
def __init__(self, pool_timings: str, pool_lane: int):
super().__init__()
self.__pool_timings = pool_timings # double underscore: name-mangled,
self.__pool_lane = pool_lane # the Python flavour of private
def swimming_plan(self) -> str:
return f"Swimming at {self.__pool_timings}, lane {self.__pool_lane}"A Python-specific observation: because Python attributes are created at assignment time, the "before" hierarchy quietly forces every section instance to allocate and carry the pool attributes, even when they hold dummy values. After the push-down, only SectionSevenC instances pay for pool state at all. In Python, push-down is not just honesty — it is also a tiny memory and clarity win on every single object created.
💼 The same refactoring in C#
The C# version of the school, before:
// BEFORE: one-section state declared for every section
abstract class Section
{
protected string _schoolAddress = "12 Lake Road, Pune 411001";
protected string _poolTimings = ""; // only SectionSevenC uses these
protected int _poolLane;
}
class SectionSevenA : Section { /* inherits pool fields it never wants */ }
class SectionSevenC : Section
{
public string SwimmingPlan() =>
$"Swimming at {_poolTimings}, lane {_poolLane}";
}After pushing down — with the visibility tightened and the fields made readonly, since they are set once:
// AFTER: pool state lives in the sports section only
abstract class Section
{
protected string _schoolAddress = "12 Lake Road, Pune 411001";
}
class SectionSevenA : Section { /* honest and empty-handed */ }
class SectionSevenC : Section
{
private readonly string _poolTimings; // private again — smallest door
private readonly int _poolLane;
public SectionSevenC(string poolTimings, int poolLane)
{
_poolTimings = poolTimings; // subclass-specific setup stays
_poolLane = poolLane; // in the subclass constructor
}
public string SwimmingPlan() =>
$"Swimming at {_poolTimings}, lane {_poolLane}";
}C#-specific notes:
- Tighten aggressively.
protected→privateis the headline, but C# offers more:readonlyfor set-once fields, or converting the field to aprivateauto-property if the class's style prefers properties. Push-down is the natural moment for these upgrades, because you finally control the field from a single class. - Watch parent-typed access. If any code did
Section s = GetSection(); var t = s._poolTimings;, it stops compiling once the field leavesSection. In C# you may be tempted to "fix" it with a cast —((SectionSevenC)s)._poolTimings— but a cast like that is usually a design smell of its own. Prefer giving the behaviour (SwimmingPlan()) to the subclass and letting callers hold the right type. - Constructor knock-on. If the base constructor was initializing the pushed-down field (the inverse of what we built in Pull Up Constructor Body), that parameter and assignment move down into the subclass constructor, exactly as shown above. Up-moves and down-moves use the same checklist, walked in opposite directions.
🛠️ IDE support
Push-down has first-class tool support in the JetBrains family, and partial support elsewhere:
- IntelliJ IDEA / PhpStorm: Refactor → Push Members Down… opens a dialog mirroring Pull Members Up: tick the members to move, and the IDE relocates them into the direct subclasses, deleting them from the parent. JetBrains documents the pair together — "Pull members up, push members down" — as the two-direction tool for cleaning hierarchies.
- JetBrains Rider / ReSharper (C#): Refactor → Push Members Down moves members from a base type into its direct inheritors, with conflict analysis that flags exactly our danger case — usages through the base type that would break. It can also push a member into all inheritors or only selected ones.
- Visual Studio (without ReSharper): there is a built-in Pull Members Up dialog via Ctrl+., but no symmetrical built-in "push members down" as of current releases — the down direction is done manually (declare in subclass, delete from parent, let the compiler guide you) or with ReSharper installed. The manual route is exactly our step-by-step recipe, so you already know it.
- Eclipse (Java): Refactor → Push Down… has existed for years and works on fields and methods alike.
As always, the tool's conflict checker replaces grep, not judgment. It will tell you who uses the field; only you can decide whether two users deserve two copies, an intermediate class, or a rethink.
⚖️ Benefits and risks
| Benefits | Risks / costs |
|---|---|
| The superclass tells the truth: every member it declares concerns every child | If two or more subclasses use the field, pushing down creates duplicate copies |
| Subclasses that never used the field stop carrying misleading dead weight | Code accessing the field via a parent-typed reference breaks and must be redesigned |
Visibility tightens — protected becomes private, shrinking the blast radius | Pushing into several subclasses can scatter a concept that wanted its own class (consider Extract Subclass / an intermediate parent) |
| The subclass becomes self-documenting: its special data sits inside it | Knock-on moves: companion methods and constructor logic usually travel down too |
| Cures Refused Bequest and trims Speculative Generality | Almost none when exactly one subclass uses the field — that case is pure win |
And now the series' closing thought on directions, because this post completes the pair. Pull Up Field and Push Down Field are exact inverses — one tool, two directions, like an elevator in the school building. Here is the whole series in one table:
| Refactoring | Direction | School story | Smell it cures |
|---|---|---|---|
| Pull Up Field | Up | The address copied on three boards | Duplicate Code (state) |
| Pull Up Method | Up | Three drifting leave-application sheets | Duplicate Code (behaviour) |
| Pull Up Constructor Body | Up | The shared morning opening before first period | Duplicate Code (initialization) |
| Push Down Field (this post) | Down | Pool timings moved to 7C's board | Refused Bequest |
- Pull up when the duplication is real: the same field, same meaning, in every sibling. Keeping copies downstairs invites drift (remember 7B's stale PIN code). The cost of not pulling up is Duplicate Code.
- Push down when the sharing is fake: a parent field that only some children touch. Keeping it upstairs spreads false promises (remember the 7A student at the pool). The cost of not pushing down is Refused Bequest.
- Neither direction is "the good one." The same field can legitimately ride the elevator twice in a system's life: pushed down when a feature turns out to be niche, pulled back up when the niche becomes universal. The hierarchy is healthy when every member sits at the lowest level where all classes beneath it still need it — and code reviews should ask that question for every new field: whose board does this notice belong on?
🩺 Which smells does it cure?
| Smell | How Push Down Field helps |
|---|---|
| Refused Bequest | The primary cure for its data form — children stop inheriting state they never wanted |
| Speculative Generality | Removes "someday every section will swim" fields from the shared abstraction |
| Large Class (bloated superclass) | Each push-down slims the parent toward its honest, common core |
| Duplicate Code | Indirect, as a boundary: knowing when not to push down (widely used fields) avoids creating duplication — the inverse compass in action |
📦 Quick revision box
+--------------------------------------------------------------+
| PUSH DOWN FIELD — REVISION |
+--------------------------------------------------------------+
| Story : "Swimming Pool Timings" pinned on the MAIN board, |
| but only 7C swims -> confused 7A student at the |
| pool, crowded board nobody trusts. |
| Fix: move the notice DOWN to 7C's board only. |
| |
| Move : Field in superclass used by only SOME children |
| ---> declared only in the subclass(es) that |
| actually use it |
| |
| Do it when : usage is genuinely narrow (ideally ONE child) |
| Don't when : all/most children use it (that's Pull Up |
| territory) or parent-typed code needs it |
| |
| Safe steps : find ALL usages (incl. parent-typed access!) |
| -> declare in real user(s) -> test -> delete |
| from parent -> test -> tighten protected -> |
| private -> move companion methods down too |
| |
| Bonus : visibility shrinks; subclass self-documents |
| Inverse : Pull Up Field — same elevator, other direction |
| Cures : Refused Bequest, Speculative Generality |
| Compass : a member lives at the LOWEST level where |
| everyone below still needs it |
+--------------------------------------------------------------+✏️ Practice exercise
Final exercise of the series — and this one asks you to use both directions of the elevator. Here is the school's activity-club software:
abstract class Club {
protected clubName = "";
protected meetingDay = "";
protected instrumentInventory: string[] = []; // hmm...
protected debateTopicOfMonth = ""; // hmm...
protected annualBudget = 0;
}
class MusicClub extends Club {
tuneUp(): string {
return `${this.clubName}: checking ${this.instrumentInventory.length} instruments`;
}
}
class DebateClub extends Club {
announceTopic(): string {
return `${this.clubName} topic: ${this.debateTopicOfMonth}`;
}
}
class ChessClub extends Club {
// uses clubName, meetingDay, annualBudget — and nothing else
private chessSets = 10; // wait — should this even be here? yes! why?
}Your tasks:
- For each of the five parent fields, run the compass: who actually uses it? Mark each as stays up, push down to MusicClub, or push down to DebateClub.
- Perform the push-downs in the safe order: declare in the real user, test, delete from
Club, test, tighten toprivate. ChessClub.chessSetsis alreadyprivateand already in the subclass. Explain in one sentence why this field is an example of the correct placement this whole series teaches — it never needed any refactoring.- A teammate argues
annualBudgetshould be pushed down "because each club's budget is different." Different values are not different concepts — explain why the field still stays up. (Hint: every club has a budget; the school address had a different value than the phone number too.) - Bonus, the full-series question: next term the school adds
OrchestraClub, which also keeps aninstrumentInventory. Two clubs now need the field. Lay out your three options — duplicate in both, intermediateMusicalClubparent, or pull back up toClub— and pick one with a one-line justification.
If you can argue task 5 confidently, you have the whole picture: Pull Up Field, Pull Up Method, and Pull Up Constructor Body carry the genuinely shared things upstairs, Push Down Field carries the genuinely special things downstairs — and the school's notice boards stay so tidy that every student trusts every board they read, from Mrs. Iyer's 7A door to Mr. Sharma's main office wall.
Frequently asked questions
- What does Push Down Field do?
- When a field declared in a superclass is used by only some of its subclasses, Push Down Field removes it from the superclass and declares it only in the subclass or subclasses that actually use it. The parent then contains only state that is genuinely common to all children.
- Isn't Push Down Field just Pull Up Field in reverse?
- Yes, exactly — they are precise inverses, and both exist because both mistakes happen. The compass: if every subclass shares the field, it belongs upstairs (Pull Up); if only one or two use it, it belongs downstairs (Push Down). A healthy hierarchy applies both over its lifetime.
- What if two out of four subclasses use the field — pushing down duplicates it, right?
- Right, and that is the honest trade-off. Two copies in the two real users is often still better than one misleading copy forced on four classes. But if those two subclasses share more than this one field, they may deserve an intermediate parent of their own, or the situation may signal a missing subtype — consider Extract Subclass.
- What breaks when I push a field down?
- Any code that accessed the field through a superclass-typed reference stops compiling, because the parent no longer declares it. That is useful information: either that code should be working with the subclass type, or the field genuinely belongs in the parent after all and you should stop.
- Why can the field become private again after pushing down?
- In the superclass it had to be at least protected so subclasses could reach it. Once it lives inside the single class that uses it, no one else needs access, so you can tighten it to private — shrinking its exposure and making future changes safer.
Further reading
Related Lessons
Refused Bequest: The Child Who Refused the Sweet Shop Recipes
Learn the Refused Bequest code smell with a family sweet shop story, Liskov violations in TypeScript and C#, and the delegation cure explained step by step.
Duplicate Code: Writing the Same Address on 50 Wedding Cards
Learn the Duplicate Code smell with a wedding card story. Understand DRY, the Rule of Three, and how Extract Method removes dangerous copy-paste code.
Speculative Generality: Plumbing for a Swimming Pool You May Never Build
Learn the Speculative Generality smell with a house-building story. Understand YAGNI, why guessing future needs backfires, and how to collapse unused abstractions.
Pull Up Field: One Notice Board for Information Everyone Shares
Learn the Pull Up Field refactoring with a school notice-board story — move a field that every subclass duplicates into the superclass, with safe steps in TypeScript and C#, IDE support, and the pull-up vs push-down direction guide.