# How to deal with legacy code

## A few techniques to deal with legacy code:

1. Breaking dependencies using a *Seam*
2. Safe refactoring
3. Extracting methods
4. Extracting classes
5. Abstracting libraries
6. Create **characterization tests** (gold standard tests) before refactoring

## 1. Breaking dependencies using a Seam

Sometimes it is not possible to write tests due to <mark style="background-color:blue;">excessive coupling</mark>. If your code is dealing with external dependencies, we can break the dependency to allow the *Subject Under Test* to be exercised independently.

In clothing, <mark style="background-color:blue;">a</mark> <mark style="background-color:blue;"></mark>*<mark style="background-color:blue;">seam</mark>* <mark style="background-color:blue;"></mark><mark style="background-color:blue;">joins parts together to form a piece of clothing</mark>. In code, we can use this concept to find *soft points* where we can separate coupled parts.

Ideally, we want most of the changes on test code and not on production code.

### An example of a Seam

#### **Using Inheritance to Decouple Production Code**

```java
public class Game
{
    public void Play()
    {
    
        var diceResult = new Random().Next(1, 6);
    ...
    
    }
}
```

In this case, the Game class is coupled with the random number generator library. We need to control the dice rolling in order to test the Game class.

**Step 1**

Add a protected virtual method to the Game class to encapsulate the behavior that has the coupling issue

```java
public class Game
{
    public void Play()
    {
        var diceResult = roll();
    ...
    }
    
    protected virtual int Roll()
    {
        return new Random().Next(1, 6);
    }
}
```

**Step 2**

In your test code, inherit from the Game class and change the behavior of the protected virtual method Roll to something you have control over:

```java
public class TestableGame : Game
{
    private int roll;
    public TestableGame(int desiredRoll)
    {
        roll = desiredRoll;
    }
    
    protected override int Roll()
    {
        return roll;
    }
}
```

**Step 3**

Write a test using the `TestableGame` class:

```java
public class GameShould
{
    [Test]
    public void Do_Something_When_A_Six_Is_Rolled()
    {
        var game = new TestableGame(6);
        game.Play();
        //ASSERT...
    }
}
```

**Advantage**

The advantage of using this method is that it <mark style="background-color:blue;">**minimizes changes to production code**</mark> and can be done using automated refactoring, thus minimizing the risk of introducing breaking changes to production code

## 2. Safe refactoring

The term refactoring is often used incorrectly. When refactoring, you are merely changing the structure of the code. If the logic and/or signature of the code in question changes, then this does not qualify as refactoring!

> If I'm changing the structure of the code (refactoring), then I don't ever change its behavior at the same time. If I'm changing the interface by which some logic is invoked, I never change the logic itself at the same time.
>
> – Kent Beck

{% hint style="info" %}
If I'm refactoring then I don't ever change its behavior at the same time!
{% endhint %}

## 3. Extracting a method

Working with legacy code often involves working with very large methods. A large method is any <mark style="background-color:blue;">method that is longer than</mark> <mark style="background-color:blue;"></mark><mark style="background-color:blue;">**twenty lines**</mark>. A large method can mean that the code is violating the Single Responsibility Principle.

What needs to be done is to find the seams in the method. Seams can be <mark style="background-color:blue;">**found by adding comments to describe different sections**</mark> <mark style="background-color:blue;"></mark><mark style="background-color:blue;">of the method</mark>. Once you have added the comments, you have identified the seams.

Each one of those seams is probably a lower order method that can be extracted. In **most editors and IDE**s, highlight the code you want and use the extract method refactoring provided through either a right-click, context, menu, or via the menu bar.

## 4. Extracting a class

Just like methods, sometimes a large method should really be a class. While extracting methods, if you extract <mark style="background-color:blue;">**three or more methods**</mark><mark style="background-color:blue;">, then you have probably found a class</mark> that needs to be extracted! Extracting a class is similar to extracting a method and is likely supported by your editor or **IDE**.

## 5. Abstracting libraries

Things like <mark style="background-color:blue;">DateTime, Random, and Console</mark> **are best hidden behind classes** that you design to fit the needs of your application. There are several reasons for this;

Most importantly, putting these in their own classes will allow for testing. Without abstracting these to a separate class, it is almost impossible to test with things like DateTime <mark style="background-color:blue;">**that change values on their own**</mark><mark style="background-color:blue;">.</mark>

## 6. Characterization tests

Gold standard tests, or characterization tests, are those tests that <mark style="background-color:blue;">**simply define the expected functionality**</mark> of a method. If you were to add tests to a legacy system, you would likely begin by writing gold standard tests to define the "happy path" through the system.

You might run the application to determine what values a given method returns based on a given input, and then write a test to duplicate the results.

> For these Gold standard tests, You certainly don't want to run the application with all possible values in order to write tests for each of the possibilities. It is far more important to test for every **path of execution**.
