# Shotgun SurgeryA intermediate-level guide to Shotgun Surgery: before-and-after java code and diagrams for a CS student.

## The Pain of the "Scattered Change"

Imagine you are tasked with adding a new order type to an existing system. Instead of making one logical change in one file, you find yourself opening `Order.java`, then hunting down `Shipping.java` to update its logic, and finally searching through `Invoice.java` to ensure the taxes remain correct. You finish your task, but you feel uneasy. Did you miss a fourth or fifth location?

This feeling is the hallmark of **Shotgun Surgery**. It occurs when a single responsibility—in this case, how an order type dictates behavior—is spread across multiple classes. When that responsibility changes, it "sprays" edits across the codebase like buckshot from a shotgun.

```mermaid
classDiagram
    class Order {
        +String type
        +double amount
        +isTaxable() boolean
    }
    class Shipping {
        +calculateShipping(Order order) void
    }
    class Invoice {
        +generateInvoice(Order order) void
    }
    Shipping ..> Order : dependency
    Invoice ..> Order : dependency
```

In the diagram above, notice how `Shipping` and `Invoice` both depend on the internal details of `Order`. While they are separate classes, they are tightly **coupled**; their logic is tied to the specific values inside an `Order` object.

```java
class Order {
    String type; // "RETAIL" or "WHOLESALE"
    double amount;

    Order(String type, double amount) {
        this.type = type;
        this.amount = amount;
    }

    public boolean isTaxable() {
        return !"WHOLESALE".equals(type);
    }
}

class Shipping {
    void calculateShipping(Order order) {
        if ("RETAIL".equals(order.type)) {
            System.out.println("Standard shipping cost applied.");
        } else {
            System.out.println("Freight shipping cost applied.");
        }
    }
}

class Invoice {
    void generateInvoice(Order order) {
        if (order.isTaxable()) {
            System.out.println("Applying standard sales tax.");
        } else {
            System.out.println("Applying zero-rated tax rate.");
        }
    }
}
```

## Consolidating Responsibility with Move Method

To fix this, we perform a refactoring called **Move Method**. The goal is to take logic that is currently being performed by one class using another's data and move that logic into the class that actually owns the data. 

By moving the shipping and tax decision-making inside the `Order` class, we achieve better **encapsulation**. Encapsulation is the practice of bundling data with the methods that operate on that data, hiding the internal details from the outside world. When responsibility is encapsulated, a change to "how shipping works" only requires changing one method in one class.

```java
class Order {
    String type; // "RETAIL" or "WHOLESALE"
    double amount;

    Order(String type, double amount) {
        this.type = type;
        this.amount = amount;
    }

    public boolean isTaxable() {
        return !"WHOLESALE".equals(type);
    }

    void applyShippingLogic() {
        if ("RETAIL".equals(type)) {
            System.out.println("Standard shipping cost applied.");
        } else {
            System.out.println("Freight shipping cost applied.");
        }
    }

    void applyTaxLogic() {
        if (isTaxable()) {
            System.out.println("Applying standard sales tax.");
        } else {
            System.out.println("Applying zero-rated tax rate.");
        }
    }
}

class Shipping {
    void calculateShipping(Order order) {
        order.applyShippingLogic();
    }
}

class Invoice {
    void generateInvoice(Order order) {
        order.applyTaxLogic();
    }
}
```

By applying Move Method, we have transformed the relationship from a scattered set of dependencies into a clean delegation. Now, when you need to add a new order type, you modify `Order`, and the other classes automatically behave correctly because they simply ask the `Order` what it should do.

```mermaid
sequenceDiagram
    participant S as Shipping
    participant O as Order
    participant I as Invoice

    S ->> O: applyShippingLogic()
    O -->> S: 
    I ->> O: applyTaxLogic()
    O -->> I: 
```

## When to Use It, and When Not To

Move Method is highly effective when you notice that a single requirement change forces you to touch many different files. This often happens because logic has "leaked" out of its natural home.

However, be wary of over-consolidation. If you move every single piece of logic into one class just to avoid touching other files, you risk creating a **God Object**—a massive, bloated class that tries to do everything and is impossible to maintain. The goal is to find the *right* home for the logic, not just to dump it all in one place.

## Takeaways

- Shotgun Surgery occurs when a single change requires small edits to many different classes.
- High **coupling** (where classes are too dependent on each other's internals) makes code fragile and hard to change.
- Use **Move Method** to consolidate scattered logic into the class that owns the relevant data.
- Aim for high encapsulation; a class should be responsible for its own rules so that changes stay localized.

## Usage

**Demonstrating the scenario where logic is consolidated inside Order to prevent Shotgun Surgery when types change.**

```java
Order retail = new Order("RETAIL", 100.0);
new Shipping().calculateShipping(retail);
new Invoice().generateInvoice(retail);
```
