> For the complete documentation index, see [llms.txt](https://raviram.gitbook.io/tdd/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://raviram.gitbook.io/tdd/legacy-code/sprouting-in-legacy-code.md).

# Sprouting in legacy code

## Sprouting in legacy code

### Sprout method

Sprout Method is a technique that one can use when one has to write a new feature in an existing code. The reason for Sprout method is that sometimes <mark style="background-color:blue;">you cannot write unit test for the code that you want to change but you can use TDD to write unit test for the new code</mark>, so that at least the new code would be tested!

#### Example

```csharp
public class TransactionGate{
    ...
    var orderItems = GetOrderItems();
    
    foreach(var orderItem in orderItems)
        transactionBundle.Add(orderItem);
    ...
}
```

**Now a new change is requested on the legacy code**

Now a new task demands to <mark style="background-color:blue;">filter out order items</mark> that are not already in the `TransactionBundle` object, we do it by **sprouting** out our code (function) from the existing code!

```csharp
public class TransactionGate{
  ...
  var orderItems = GetOrderItems();
  
  var uniqueOrderItems = GetUniqueOrderItems(orderItems);
  
  foreach(var orderItem in uniqueOrderItems)
    transactionBundle.Add(orderItem);     
}

public List<OrderItem> GetUniqueOrderItems(List<OrderItem> orderItems){
    ...
}
```

We created a method `GetUniqueOrderItems` with one parameter; a list of order items. Now we can initiate class and write tests for new code. It is recommended to use Test Driven Development to develop a Sprout method itself.

### Sprout Class

When you must extend a large method with a sequence of instructions and the class is heavily dependent on different objects, it can be better to extract the sequence of instructions into a new class method.

This is <mark style="background-color:blue;">more ideal when we want to make sure that Single Responsibility Principle</mark> is not violated anywhere

#### Example

Below we have an existing code/legacy code to create an order. Now we have a new requirement saying that when creating an order, <mark style="background-color:blue;">We also need to add a VAT amount</mark> (a type of tax) if the order is from a non-individual, a company.

**Existing code**

```csharp
public class OrdersFacade{
  private IExternalCustomerApiService customerApiService;
  private IOrderRepository orderRepository;
  ...
       
  public OrdersFacade(
    IExternalCustomerApiService customerApiService,
    IOrderRepository orderRepository,
    ...
    )
    {
    this.customerApiService = customerApiService;
    this.orderRepository = orderRepository;
    ...
    }
  
  public bool CreateOrder(){
    ...
     
    var customerInfoInJson = customerApiService.GetCustomerInfo(customerId);
    var customerInfo = JSonConvert.Serialize(customerInfoInJson);
    order.CustomerName = customerInfo.Name;
    
    orderRepository.Save(order);
    return true;
    }
}
```

**Step 1:** Let’s develop a completely separated class, preferably using TDD.

```csharp
public class OrderVatCalculator{
  public Order AddVatIfNotCompany(Order order, bool isCompany)
  {
    decimal vat = 1.21;
    if(!isCompany){
      order.Price = order.Price * vat;
    }
  }
}
```

**Step 2:** Let’s initialize an object of Sprout class in existing code, pass parameters into its method, and let a method do the required expression.

```csharp
public class OrdersFacade{
  private IExternalCustomerApiService customerApiService;
  private IOrderRepository orderRepository;
  ...
       
  public OrdersFacade(
    IExternalCustomerApiService customerApiService,
    IOrderRepository orderRepository,
    ...
    )
    {
    this.customerApiService = customerApiService;
    this.orderRepository = orderRepository;
    ...
    }
  
  public bool CreateOrder(){
    ...
     
    var customerInfoInJson = customerApiService.GetCustomerInfo(customerId);
    var customerInfo = JSonConvert.Serialize(customerInfoInJson);
    order.CustomerName = customerInfo.Name;
    
    var orderVatCalculator = new OrderVatCalculator();
    
    orderVatCalculator.AddVatIfCompany(order, customerInfo.IsCompany);
    
    orderRepository.Save(order);
    return true;
    }
}
```

{% hint style="info" %}
The new piece of instructions is covered by tests and has only one responsibility. It is very easy to read and maintain!
{% endhint %}

### A good reading resource:

Working Effectively with Legacy Code, by Michael Feathers, [EBook](https://www.oreilly.com/library/view/working-effectively-with/0131177052/)
