Skip to main content
CleanCodeMastery

Extract Method: Turn One Giant Function into Small Named Helpers

Learn Extract Method step by step. Pull a messy block out of a long function, give it a clear name, and make your code read like a clean to-do list.

26 min read Updated June 11, 2026beginner
refactoringcomposing methodsextract methodextract functionclean codelong method

The Big Fat Wedding To-Do List ๐Ÿ“

Imagine your cousin Sana's wedding is coming up in two months. Your whole family is excited. Your Nani takes a big notebook and starts writing one giant to-do list. Book the hall. Call the caterer. Order 200 kg of rice. Buy marigold flowers. Hire the band. Print invitation cards. Arrange cars for the baraat. Buy return gifts. The list grows and grows. By Friday evening it has one hundred and twenty items, all mixed together on the same pages, in the order Nani happened to remember them.

Now the trouble starts. Asif Mama is in charge of food. He wants to check the food items. But he has to read all one hundred and twenty lines just to find the ten lines about food. Priya Didi is handling decoration. The flower items are scattered between car bookings and card printing. Ravi Uncle keeps asking, "Is the band booked or not?" and nobody can answer without reading the whole notebook again. Everyone reads everything. Everyone is confused. Two tasks get done twice. Three tasks get done by nobody. The wedding is six weeks away and the family WhatsApp group is on fire.

Then your Nana does something quietly clever. On Sunday morning he sits with the notebook, a pair of scissors, and five fresh pages. He breaks the giant list into small, named lists. One page says "Catering List โ€” Asif". One page says "Decoration List โ€” Priya". One page says "Transport List โ€” Ravi". One says "Invitations โ€” Nani". One says "Gifts โ€” Sana's Papa". Then he writes a new master page with only five lines: catering, decoration, transport, invitations, gifts โ€” each line with the helper's name next to it.

The change is magical. Anyone can read the master page in ten seconds and know the whole plan. Asif Mama opens only his catering page and sees only his own work. When Ravi Uncle asks about the band, Nana points at one line: "Music is under Decoration. Ask Priya." Done.

Notice something important. The total work did not change. The same 120 tasks still exist. Nobody cancelled the rice order. But the organisation changed, and suddenly everything is clear, everything is findable, and every person knows their job.

Figure 1: The family's journey from one giant list to small named lists

This is exactly what the Extract Method refactoring does to code. And remember our golden line: refactoring means improving the inside of code without changing what it does outside. The program behaves the same. Only the arrangement becomes better. Keep Nana's scissors in your mind. We will use them on code for the rest of this post.

What is Extract Method?

Extract Method is one of the most famous refactorings in the world. Here is the plain definition.

You find a block of code inside a long function that does one clear job. You move that block into a brand new function. You give the new function a name that says what it does. Then, at the old place, you simply call the new function.

The long function becomes short. It now reads like Nana's master page: a small list of clear steps. Each step has a name. If a reader wants details, they open that one helper function, just like Priya Didi opens only the decoration page. If a reader does not need the details, the name alone tells the story, and they keep moving.

๐Ÿ’ก

One-line memory trick: Extract Method = cut a piece out, give it a name, call it from the old spot. The behaviour stays the same; only the reading becomes easy.

A note about the name. Martin Fowler wrote the classic book Refactoring. In the first edition (1999), this refactoring was called Extract Method. In the second edition (2018), he renamed it to Extract Function, because the trick works for any function, not only for methods that live inside classes. So if you see "Extract Function" on refactoring.com and "Extract Method" on Refactoring.Guru or in your IDE menu, do not get confused. They are the same refactoring with two names. In this post we will say Extract Method, because most IDE menus still say that.

Fowler also says something lovely about this refactoring: it is probably the one he uses the most. If a piece of code takes effort to understand, he pulls it out and names it after its purpose. The name does the explaining forever after. His rule of thumb is bold: the decision to extract is not about length, it is about the gap between intention and implementation. The moment you have to think "what is this bit doing?", that bit deserves its own name.

Here is the whole idea on one small map. Look at it once now, and again after you finish the post โ€” the second look will feel like meeting an old friend.

Figure 2: Extract Method in one mind map โ€” when to do it, how to do it, what it cures

When Do We Need It? ๐Ÿ”

How do you know a function is begging for Extract Method? Watch for these signs. Each one is a page of Nani's notebook waving at you.

  1. The function is long. If you must scroll to read a function, it is probably doing many jobs at once. This is the classic Long Method smell, and Extract Method is its number one medicine. Nani's notebook was long because catering, decoration, and transport were all squeezed into one place.
  2. Comments are acting like section headings. When you see // calculate total, // print receipt, // validate input inside one function, each comment is secretly announcing, "a method wants to be born here!" This is the Comments smell โ€” comments used as labels instead of clear code. Nana literally turned each section heading into a page title.
  3. The same block appears in many places. If you copy-paste a calculation into three functions, that is Duplicate Code. Extract the block once, name it, and call it from all three places. Imagine if the rice order was written on three different pages โ€” change the quantity on one page and the other two silently stay wrong.
  4. Big and small ideas are mixed. One line says "send the invoice" (a big idea) and the next ten lines fiddle with string formatting (tiny details). Readers get tired switching between levels. The master page never mentions marigold counts; it just says "Decoration โ€” Priya". Extracting the details restores one smooth level of reading.
  5. You cannot test a piece separately. A calculation buried in the middle of a function cannot be unit tested alone. Once extracted, it can be tested, reused, and even overridden in a subclass. Asif Mama can verify the catering list on his own, without the whole family sitting together.

What actually fills up a typical long function? When you slice one open, you usually find a few distinct jobs glued together, like this:

Figure 3: A typical long method is several jobs glued into one body

Each slice of that pie is a candidate for its own named method. Validation becomes validateOrder. Calculation becomes calculateTotal. Printing becomes printReceipt. Saving becomes saveToDatabase. Four slices, four pages, one short master function.

The hardest and most valuable part of this refactoring is choosing the name. You must answer the question, "what does this block really do?" If you cannot find a good name, that is useful news too โ€” maybe the block is not one job but a jumble, and you should pick a different boundary. Nana never made a page called "Miscellaneous Stuff โ€” Someone". Every page had an honest owner and an honest title.

College corner: Research on method size keeps pointing the same way. Studies of large codebases (including well-known analyses of open-source Java and C# systems) find that very long methods correlate with higher defect density and slower comprehension, while teams working in codebases full of small, well-named functions locate faults faster. Cognitive psychology explains why: human working memory holds only a handful of "chunks" at a time (the famous 7ยฑ2 finding by George Miller). A 60-line method asks you to hold dozens of facts at once; a 5-line method that calls named helpers turns each helper into a single chunk. Extract Method is, quite literally, chunking applied to source code. Robert C. Martin's Clean Code pushes the same idea to its extreme โ€” "functions should do one thing" โ€” and Fowler's own heuristic is softer but identical in spirit: extract whenever intention and implementation drift apart.

Before and After at a Glance

Here is a tiny example. This function prints a wedding bill. Read the "before" and notice how your eyes slow down in the middle.

// BEFORE: one function, three jobs glued together
function printWeddingBill(booking: Booking): void {
  console.log("=== SHAADI BILL ===");
  console.log(`Family: ${booking.familyName}`);
 
  // calculate total amount
  let total = 0;
  for (const item of booking.items) {
    total += item.price * item.quantity;
  }
  total -= booking.advancePaid;
 
  console.log(`Amount due: Rs. ${total.toFixed(2)}`);
  console.log(`Pay by: ${booking.dueDate.toDateString()}`);
}
// AFTER: the function reads like Nana's master page
function printWeddingBill(booking: Booking): void {
  printHeader(booking);
  const total = calculateAmountDue(booking);
  printFooter(booking, total);
}
 
function printHeader(booking: Booking): void {
  console.log("=== SHAADI BILL ===");
  console.log(`Family: ${booking.familyName}`);
}
 
function calculateAmountDue(booking: Booking): number {
  let total = 0;
  for (const item of booking.items) {
    total += item.price * item.quantity;
  }
  return total - booking.advancePaid;
}
 
function printFooter(booking: Booking, total: number): void {
  console.log(`Amount due: Rs. ${total.toFixed(2)}`);
  console.log(`Pay by: ${booking.dueDate.toDateString()}`);
}

The comment // calculate total amount vanished, because the method name calculateAmountDue now says the same thing โ€” and a name can never go out of date the way a comment can.

The whole working rhythm of the refactoring fits in one line of arrows:

Figure 4: The Extract Method rhythm โ€” spot, name, extract, verify

Read those arrows again. Tests still green is not decoration. It is the finish line of every single extraction. If the tests are not green, you did not refactor โ€” you broke something.

The Classic Example: printOwing ๐Ÿงพ

Every refactoring book student meets the same famous example, and you should too, because interviewers and seniors will mention it. In Fowler's book, an Invoice class has a method printOwing that prints a banner, calculates the outstanding amount, and prints details โ€” three jobs in one body, exactly like our wedding bill.

// BEFORE: Fowler's classic shape
class Invoice {
  constructor(public orders: Order[], public customer: string) {}
 
  printOwing(): void {
    console.log("***********************");
    console.log("**** Customer Owes ****");
    console.log("***********************");
 
    let outstanding = 0;
    for (const order of this.orders) {
      outstanding += order.amount;
    }
 
    console.log(`name: ${this.customer}`);
    console.log(`amount: ${outstanding}`);
  }
}

After three extractions โ€” printBanner, calculateOutstanding, and printDetails โ€” the class looks like this:

// AFTER: three named helpers, one readable master method
class Invoice {
  constructor(public orders: Order[], public customer: string) {}
 
  printOwing(): void {
    this.printBanner();
    const outstanding = this.calculateOutstanding();
    this.printDetails(outstanding);
  }
 
  private printBanner(): void {
    console.log("***********************");
    console.log("**** Customer Owes ****");
    console.log("***********************");
  }
 
  private calculateOutstanding(): number {
    let outstanding = 0;
    for (const order of this.orders) {
      outstanding += order.amount;
    }
    return outstanding;
  }
 
  private printDetails(outstanding: number): void {
    console.log(`name: ${this.customer}`);
    console.log(`amount: ${outstanding}`);
  }
}

The class structure after the refactoring is worth drawing. One public method tells the story; three private helpers hold the details:

Figure 5: The Invoice class after extraction โ€” one storyteller, three helpers

And at runtime, the call is a polite little conversation. printOwing asks each helper to do its one job and waits for the answer, the same way Nana asks Asif for the catering status and gets a one-line reply:

Figure 6: One call during printOwing โ€” the master asks, the helper answers

Notice the shape of the conversation. The master never reaches into a helper's work halfway. It sends the inputs, receives the output, moves on. That clean handshake is what makes each helper testable on its own.

Step-by-Step, the Safe Way ๐Ÿชœ

Refactoring is not done in one big jump. We move in baby steps, and we run the tests after every step. Let us extract calculateAmountDue from the wedding bill slowly, the safe way, and watch the code at every stage.

Step 1 โ€” Choose the fragment and find its name. We pick the loop that computes the total. We ask: what does it do? It calculates the amount the family still has to pay. Name: calculateAmountDue. Name it after what it does, never after how (loopOverItems would be a bad name โ€” it describes the machinery, not the purpose).

Step 2 โ€” Create the new empty method and copy the fragment into it. Do not delete anything from the original yet. Just copy.

function calculateAmountDue(): number {
  let total = 0;
  for (const item of booking.items) {   // problem: booking is unknown here!
    total += item.price * item.quantity;
  }
  total -= booking.advancePaid;
  return total;
}

The copy does not even compile. That is expected. The next steps fix it.

Step 3 โ€” Find variables the fragment READS from outside. Make them parameters. Our fragment reads booking, which was declared outside the fragment. So booking becomes a parameter.

function calculateAmountDue(booking: Booking): number {
  let total = 0;
  for (const item of booking.items) {
    total += item.price * item.quantity;
  }
  total -= booking.advancePaid;
  return total;
}

Step 4 โ€” Find variables the fragment CHANGES that are used afterwards. Return them. The fragment changes total, and the code after the fragment (the footer printing) uses total. There is exactly one such variable, so we return it. If there were two or more changed variables used later, plain extraction would be stuck, because a function can return only one value. In that case we would first apply other refactorings like Split Temporary Variable or Replace Temp with Query, or use the bigger tool Replace Method with Method Object.

Step 5 โ€” Variables born inside the fragment and used only inside stay as locals. Here item lives only inside the loop, so it simply stays in the new method. Nothing to do.

Step 6 โ€” Replace the original block with a call. Now the original function shrinks.

function printWeddingBill(booking: Booking): void {
  console.log("=== SHAADI BILL ===");
  console.log(`Family: ${booking.familyName}`);
 
  const total = calculateAmountDue(booking);
 
  console.log(`Amount due: Rs. ${total.toFixed(2)}`);
  console.log(`Pay by: ${booking.dueDate.toDateString()}`);
}

Step 7 โ€” Compile and run all the tests. The bill printed before must match the bill printed now, paisa for paisa. If a test fails, undo the last small step and try again. Because the step was tiny, finding the mistake is easy.

Step 8 โ€” Look again. Repeat. With the calculation gone, the two console.log clusters stand out clearly as two more jobs. Extract printHeader and printFooter the same way, one at a time, testing after each.

โš ๏ธ

Run your tests after every single step, not only at the end. If you do five steps and then test, a failure could hide in any of the five. If you test after each step, a failure points straight at the one step you just did. Small steps plus frequent tests is the whole secret of safe refactoring.

The journey of one fragment, from mess to verified helper, passes through clear states. Memorise this little state machine โ€” it is the heartbeat of the whole technique:

Figure 7: The life of one extraction โ€” every fragment passes through these states

If the tests fail at the Verified state, you do not panic and you do not debug for an hour. You undo one tiny step and try again. That is the luxury that baby steps buy you.

A Bigger Real-Life Example: Planning Sana's Wedding in Code

Now let us write the wedding story as real code. Here is a wedding planning function the way it often gets written at first โ€” everything in one place, just like Nani's giant notebook on that chaotic Friday evening.

interface Wedding {
  familyName: string;
  guests: { name: string; isVip: boolean }[];
  platePriceRs: number;
  flowerMetres: number;
  ratePerMetreRs: number;
  lightingPackageRs: number;
  budgetRs: number;
}
 
// BEFORE: one giant function, four jobs tangled together
function planWedding(wedding: Wedding): void {
  // print guest summary
  console.log(`Wedding of the ${wedding.familyName} family`);
  let vipCount = 0;
  for (const guest of wedding.guests) {
    if (guest.isVip) vipCount++;
  }
  console.log(`Guests: ${wedding.guests.length}, VIPs: ${vipCount}`);
 
  // calculate catering cost
  let cateringCost = wedding.guests.length * wedding.platePriceRs;
  cateringCost += vipCount * 200; // special thali for VIPs
 
  // calculate decoration cost
  let decorationCost = wedding.flowerMetres * wedding.ratePerMetreRs;
  decorationCost += wedding.lightingPackageRs;
 
  // print budget report
  const totalCost = cateringCost + decorationCost;
  console.log(`Catering: Rs. ${cateringCost}`);
  console.log(`Decoration: Rs. ${decorationCost}`);
  console.log(`Total: Rs. ${totalCost}`);
  if (totalCost > wedding.budgetRs) {
    console.log("Warning: over budget! Talk to the family.");
  }
}

Count the comment labels: guest summary, catering cost, decoration cost, budget report. Four comments means four hidden methods. Let us free them one by one, exactly like Nana made one named page per helper.

First we extract the guest counting. It reads wedding.guests and produces vipCount, which is used later. So vipCount becomes the return value.

function countVips(wedding: Wedding): number {
  let vipCount = 0;
  for (const guest of wedding.guests) {
    if (guest.isVip) vipCount++;
  }
  return vipCount;
}

Run the tests. Green. Next, catering. It reads the wedding and the VIP count, and produces one number.

function calculateCateringCost(wedding: Wedding, vipCount: number): number {
  const baseCost = wedding.guests.length * wedding.platePriceRs;
  const vipExtra = vipCount * 200;
  return baseCost + vipExtra;
}

Tests again. Green. Then decoration, then the report. After all four extractions, the master function looks like this.

// AFTER: planWedding reads like the master page of the to-do list
function planWedding(wedding: Wedding): void {
  const vipCount = countVips(wedding);
  printGuestSummary(wedding, vipCount);
  const cateringCost = calculateCateringCost(wedding, vipCount);
  const decorationCost = calculateDecorationCost(wedding);
  printBudgetReport(wedding, cateringCost, decorationCost);
}
 
function printGuestSummary(wedding: Wedding, vipCount: number): void {
  console.log(`Wedding of the ${wedding.familyName} family`);
  console.log(`Guests: ${wedding.guests.length}, VIPs: ${vipCount}`);
}
 
function calculateDecorationCost(wedding: Wedding): number {
  const flowerCost = wedding.flowerMetres * wedding.ratePerMetreRs;
  return flowerCost + wedding.lightingPackageRs;
}
 
function printBudgetReport(
  wedding: Wedding,
  cateringCost: number,
  decorationCost: number
): void {
  const totalCost = cateringCost + decorationCost;
  console.log(`Catering: Rs. ${cateringCost}`);
  console.log(`Decoration: Rs. ${decorationCost}`);
  console.log(`Total: Rs. ${totalCost}`);
  if (totalCost > wedding.budgetRs) {
    console.log("Warning: over budget! Talk to the family.");
  }
}

Look at planWedding now. Five lines. A new team member can read it in ten seconds and understand the whole plan โ€” count VIPs, show guests, cost the food, cost the decoration, report the budget. Want details about catering? Open only calculateCateringCost, the way Asif Mama opens only his catering page. Want to unit test the decoration maths? Now you can, because it is a separate function with clear inputs and one output. And every comment label disappeared, replaced by names that can never go stale.

There is a second, quieter benefit. When a bug report comes in โ€” say a parent calls and says "the decoration cost looks wrong" โ€” you no longer search a 25-line tangle. You open calculateDecorationCost, six lines, and the bug has nowhere to hide. The difference in debugging speed is not small:

Figure 8: Small named methods shrink bug-hunting time dramatically

The numbers above are illustrative, but every working programmer recognises the shape of that chart. In the big method you read everything to find anything, like Asif Mama scanning 120 lines for ten food items. In the small methods, the name of the right method takes you straight to the right six lines.

The Same Refactoring in C# and Python

The idea is identical in every language. Here is a short C# version of the billing piece.

// BEFORE
public void PrintBill(Booking booking)
{
    Console.WriteLine($"Family: {booking.FamilyName}");
 
    // calculate amount due
    decimal total = 0;
    foreach (var item in booking.Items)
    {
        total += item.Price * item.Quantity;
    }
    total -= booking.AdvancePaid;
 
    Console.WriteLine($"Amount due: Rs. {total:F2}");
}
 
// AFTER
public void PrintBill(Booking booking)
{
    Console.WriteLine($"Family: {booking.FamilyName}");
    decimal total = CalculateAmountDue(booking);
    Console.WriteLine($"Amount due: Rs. {total:F2}");
}
 
private decimal CalculateAmountDue(Booking booking)
{
    decimal total = 0;
    foreach (var item in booking.Items)
    {
        total += item.Price * item.Quantity;
    }
    return total - booking.AdvancePaid;
}

And the same move in Python, where standalone functions make the "Extract Function" name feel very natural:

# BEFORE
def print_bill(booking):
    print(f"Family: {booking.family_name}")
 
    # calculate amount due
    total = 0
    for item in booking.items:
        total += item.price * item.quantity
    total -= booking.advance_paid
 
    print(f"Amount due: Rs. {total:.2f}")
 
# AFTER
def print_bill(booking):
    print(f"Family: {booking.family_name}")
    total = calculate_amount_due(booking)
    print(f"Amount due: Rs. {total:.2f}")
 
def calculate_amount_due(booking):
    total = 0
    for item in booking.items:
        total += item.price * item.quantity
    return total - booking.advance_paid

Same recipe everywhere: reads become parameters, the one changed-and-used value becomes the return, the comment becomes the method name. Only the costume changes; the dance is the same.

IDE Support โš™๏ธ

Good news: you rarely have to do the variable bookkeeping by hand. Modern editors automate Extract Method safely. Select the lines, trigger the refactoring, type a name, and the tool works out the parameters and return value for you.

IDEHow to extractShortcut
Visual StudioSelect code โ†’ Edit โ†’ Refactor โ†’ Extract Method, or Quick ActionsCtrl+R, Ctrl+M (or Ctrl+. then "Extract method")
VS CodeSelect code โ†’ Refactor menu โ†’ "Extract to function/method"Ctrl+Shift+R (Refactor) or Ctrl+. (Quick Fix)
IntelliJ IDEA / Rider / other JetBrains IDEsSelect code โ†’ Refactor โ†’ Extract MethodCtrl+Alt+M (Cmd+Option+M on Mac)
ReSharper in Visual StudioSelect code โ†’ Refactor This โ†’ Extract MethodCtrl+Shift+R then choose Extract Method

Two small tips. First, the tool will warn you if the selection cannot be extracted cleanly, for example when two changed variables are used later โ€” that warning is teaching you the same rule we learned in Step 4. Second, even with a tool, still run your tests. Tools are excellent, but your tests are the final judge.

Extract or Leave It? Making the Call ๐Ÿค”

Not every block deserves extraction. Before you reach for Nana's scissors, ask two questions: how hard is this block to read? and how many places need it? The answers place the block on a simple decision map:

Figure 9: Where your code block lands decides whether to extract

Read the map like this. A block that is hard to read and needed in many places is a must-extract โ€” you gain clarity and kill duplication in one stroke. A block that is hard to read but used once still usually deserves extraction, purely for the explaining power of the name. A clear one-liner used once? Leave it alone; extraction would only add furniture. A clear block used in many places is worth extracting just to remove the copies.

Here is a quick reference table for the same judgement, with wedding flavour:

SituationWedding versionDecision
Hard block, used in many functionsThe thali cost rule needed by bill, report, and SMSExtract immediately โ€” clarity plus reuse
Hard block, used onceThe VIP counting loop inside one functionExtract โ€” the name explains it forever
Simple line, used in many places"Rs." formatting on every amountExtract โ€” one place to change it later
Simple line, used onceOne greeting console.logLeave it โ€” a name would add nothing

College corner: What about performance? Students often worry that more function calls means slower programs. A century ago in computing years, that was occasionally true. Today, optimising compilers and JIT runtimes perform inlining automatically: the JVM's HotSpot compiler inlines small hot methods (the default bytecode-size threshold for trivial methods is tiny โ€” around 35 bytecodes), the .NET RyuJIT does the same for small IL bodies, and C/C++ compilers inline aggressively at -O2. In other words, you write small readable methods for humans, and the machine quietly rebuilds the big fast blob for itself. The classic engineering advice applies: never sacrifice readability for speed you have not measured. Profile first; the bottleneck is almost never the function call.

Benefits and Risks โš–๏ธ

Point
โœ…The calling function becomes a short, self-explaining summary โ€” code reads like a to-do list.
โœ…Good names replace comments, and names cannot drift out of date.
โœ…Extracted logic can be reused everywhere instead of copy-pasted.
โœ…Small functions are easy to unit test, debug, and override.
โœ…It opens the door to other refactorings like Move Method and Replace Temp with Query.
โš ๏ธOver-extraction creates a swarm of one-line methods with weak names; readers must hop between ten places to follow one simple story.
โš ๏ธA fragment that changes several variables used later cannot be extracted directly โ€” fix the temps first or use Replace Method with Method Object.
โš ๏ธIn an extremely hot loop, the extra function call can cost a tiny bit of speed โ€” but modern compilers inline calls, so measure before you worry.

When NOT to use it: if you cannot find an honest name for the fragment, or if extraction would only produce doStuff1 and doStuff2, stop. A bad name is worse than no extraction. Nana would never have written a page titled "Various Things โ€” Whoever Is Free".

The seesaw with Inline Method. Extract Method and Inline Method are exact inverses, like the two ends of a seesaw. Extract Method adds a named layer; Inline Method removes a layer that is not earning its keep. Neither side is "right" forever. If you extracted too eagerly and a method's body is clearer than its name, inline it back. If a function grew too long, extract again. Healthy code moves up and down this seesaw until it balances at clarity.

Which Smells Does It Cure?

SmellHow Extract Method helps
Long MethodThe primary cure. Break the giant into small named steps, just like the wedding list.
CommentsA comment that labels a block becomes the name of an extracted method, and the comment is deleted.
Duplicate CodeExtract the repeated block once; every old copy becomes a one-line call.
Complex conditionalsExtracting the condition and each branch is the heart of Decompose Conditional.

Quick Revision Box

+--------------------------------------------------------------+
|                EXTRACT METHOD โ€” QUICK REVISION               |
+--------------------------------------------------------------+
| WHAT   : Move a code block into a new, well-named function   |
|          and call it from the old place.                     |
| 2ND ED : Fowler now calls it "Extract Function".             |
| WHEN   : Long Method, comment-labelled blocks,               |
|          duplicate blocks, untestable pieces.                |
| STEPS  : 1. Pick fragment, find a what-it-does name          |
|          2. Copy body into new method                        |
|          3. Outside reads  -> parameters                     |
|          4. One changed-and-used value -> return             |
|          5. Inside-only vars stay local                      |
|          6. Replace fragment with a call                     |
|          7. TEST after every step                            |
| INVERSE: Inline Method (the other end of the seesaw)         |
| RULE   : No good name? Then do not extract yet.              |
+--------------------------------------------------------------+

Practice Exercise ๐Ÿ

Your turn! This function prints a school report card. It has three comment-labelled jobs hiding inside. Extract them into well-named methods. Remember: one extraction at a time, and pretend to run tests after each step.

function printReportCard(student: Student): void {
  // print student details
  console.log(`Name: ${student.name}`);
  console.log(`Class: ${student.className}, Roll: ${student.rollNo}`);
 
  // calculate percentage
  let totalMarks = 0;
  for (const subject of student.subjects) {
    totalMarks += subject.marks;
  }
  const percentage = totalMarks / student.subjects.length;
 
  // print result
  console.log(`Percentage: ${percentage.toFixed(1)}%`);
  if (percentage >= 40) {
    console.log("Result: PASS");
  } else {
    console.log("Result: FAIL โ€” meet the class teacher.");
  }
}

Hints: the middle block reads student and produces percentage โ€” which becomes the return value. Aim for a final printReportCard of exactly three lines. When you finish, check three things, the Nana way: Does the master function read like a five-second summary? Did every comment disappear into a method name? Can each helper be tested alone? If yes to all three, shabash โ€” you have just performed the most useful refactoring in the world, and Sana's wedding planner would be proud to have you on the family committee.

Frequently asked questions

What is the Extract Method refactoring in simple words?
Extract Method means taking a block of code out of a long function, putting it into a new function, giving that function a clear name, and calling it from the old place. The code does the same work as before, but now it is easier to read.
Why did Martin Fowler rename Extract Method to Extract Function?
In the 2nd edition of his Refactoring book, Fowler renamed it to Extract Function because the idea works for plain functions too, not only for methods inside classes. Both names mean the same refactoring.
How do I know which block of code to extract?
Look for a block that does one clear job, especially a block with a comment above it explaining what it does. If you can give the block a good name, it is ready to become its own method.
Does Extract Method change what my program does?
No. Refactoring never changes the outside behaviour of the program. Extract Method only changes how the code is organised inside. That is why you must run your tests after each small step, to prove nothing broke.
Can I extract too many methods?
Yes. If you create dozens of one-line methods with weak names, readers must jump around to understand simple code. When a method's body is clearer than its name, use the inverse refactoring, Inline Method, to fold it back.

Further reading

Related Lessons