# Long MethodA intermediate-level guide to Long Method: before-and-after java code and diagrams for a CS student.

## The Scrolling Problem

Imagine you are reviewing a colleague's work. You open a single method and find yourself scrolling constantly just to understand what it does. By the time you reach the bottom, you have forgotten the logic that started at the top. This is often caused by high "Cognitive Load"—the amount of mental effort required to process information. When a method tries to do too many things at once, your brain has to track dozens of local variables and multiple logical stages simultaneously, making it nearly impossible to spot bugs or understand the intent.

```java
public class InvoiceProcessor {
    public void processInvoice(Order order) {
        // Step 1: Validate Order
        if (order.items().isEmpty()) {
            throw new IllegalArgumentException("Order must have items");
        }
        if (order.getCustomer() == null) {
            throw new IllegalArgumentException("Customer is required");
        }

        // Step 2: Calculate Totals
        double subtotal = 0;
        for (Item item : order.items()) {
            subtotal += item.price() * item.quantity();
        }

        double taxRate = 0.08;
        if (order.isInternational()) {
            taxRate = 0.15;
        }
        double taxAmount = subtotal * taxRate;
        double total = subtotal + taxAmount;

        // Step 3: Apply Discounts
        if (total > 100.0) { 
            total -= (total * 0.10);
        }

        // Step 4: Generate Receipt
        System.out.println("Invoice for: " + order.getCustomer().name());
        System.out.println("Subtotal: $" + subtotal);
        System.out.println("Tax: $" + taxAmount);
        System.out.println("Total: $" + total);
    }
}
```

The `processInvoice` method above is suffering from the Long Method smell. Instead of being a high-level summary of an invoice's lifecycle, it is a monolithic block of instructions that mixes validation, math, and output.

```mermaid
classDiagram
    class Order {
        +items() List~Item~
        +getCustomer() Customer
        +isInternational() boolean
    }
    class Item {
        +price() double
        +quantity() int
    }
    class Customer {
        +name() String
    }
    class InvoiceProcessor {
        +processInvoice(Order order) void
    }
    InvoiceProcessor ..> Order : uses
    Order *-- Item : contains
    Order --> Customer : has
```

## Identifying the Smell

How do you know when a method has grown too large? Look for these physical symptoms in your IDE:

*   **Deep Indentation:** If your code is pushed far to the right by nested `if` statements and loops, it is difficult to track which "else" belongs to which "if."
*   **The "Step 1, Step 2" Comment Pattern:** If you find yourself writing comments like `// Calculate tax` or `// Print receipt` to label blocks of code within a method, those comments are actually screaming for the code they describe to be moved into its own named function.
*   **Unrelated Variables:** When a single method declares variables used in different logical phases (e.g., a variable for validation and a completely separate one for printing), it is likely violating the Single Responsibility Principle—the idea that a piece of code should have only one reason to change.

## The Solution: Extract Method

To fix a Long Method, we use a refactoring technique called **Extract Method**. You identify a coherent chunk of code within your large method, move it into a new, smaller method, and replace the original code with a call to that new method.

This creates a "Composed Method"—a high-level method that reads like a table of contents, delegating the gritty details to specialized sub-methods.

```java
public class InvoiceProcessor {
    public void processInvoice(Order order) {
        validateOrder(order);
        double subtotal = calculateSubtotal(order);
        double taxAmount = calculateTax(subtotal, order.isInternational());
        double total = applyDiscounts(subtotal + taxAmount);
        printReceipt(order.getCustomer().name(), subtotal, taxAmount, total);
    }

    private void validateOrder(Order order) {
        if (order.items().isEmpty()) {
            throw new IllegalArgumentException("Order must have items");
        }
        if (order.getCustomer() == null) {
            throw new IllegalArgumentException("Customer is required");
        }
    }

    private double calculateSubtotal(Order order) {
        return order.items().stream()
                .mapToDouble(i -> i.price() * i.quantity())
                .sum();
    }

    private double calculateTax(double subtotal, boolean isInternational) {
        double taxRate = isInternational ? 0.15 : 0.08;
        return subtotal * taxRate;
    }

    private double applyDiscounts(double amount) {
        if (amount > 100.0) {
            return amount * 0.90;
        }
        return amount;
    }

    private void printReceipt(String name, double subtotal, double tax, double total) {
        System.out.println("Invoice for: " + name);
        System.out.println("Subtotal: $" + subtotal);
        System.out.println("Tax: $" + tax);
        System.out.println("Total: $" + total);
    }
}
```

By extracting methods like `validateOrder`, `calculateSubtotal`, and `printReceipt`, we have transformed the logic into a readable story. The `processInvoice` method no longer cares *how* tax is calculated; it only cares that the calculation happens.

```mermaid
sequenceDiagram
    participant IP as InvoiceProcessor
    participant O as Order
    IP->>O: validateOrder(order)
    IP->>O: calculateSubtotal(order)
    IP->>O: calculateTax(subtotal, isInternational())
    IP->>O: applyDiscounts(amount)
    IP->>O: printReceipt(name, subtotal, tax, total)
```

## When to Use It, and When Not To

Extract Method is one of the most frequently used refactorings because it makes code "self-documenting." You no longer need a comment to explain what five lines of math are doing if you can simply name that method `calculateTax`.

However, be wary of **fragmentation**. If you extract every single line into its own tiny method, you might end up with an overly complex web where it is hard to follow the program's flow because you are constantly jumping between dozens of different locations in the file. Aim for "logical chunks"—groups of code that represent a single, clear action or calculation.

## Takeaways

*   If you have to scroll to read a single method, it is likely too long.
*   Comments describing steps are often a sign that those steps should be their own methods.
*   Use Extract Method to turn a list of instructions into a readable story.

## Usage

**Using the refactored Composed Method approach**

```java
InvoiceProcessor processor = new InvoiceProcessor();
processor.processInvoice(myOrder);
```
