Example: Sprout Method on TransactionGate

Starting code — postEntries posts a date on each entry and adds them to the bundle:

public class TransactionGate
{
    public void postEntries(List entries) {
        for (Iterator it = entries.iterator(); it.hasNext(); ) {
            Entry entry = (Entry)it.next();
            entry.postDate();
        }
        transactionBundle.getListManager().add(entries);
    }
    ...
}

We need to skip entries that are already in transactionBundle. The tempting inline approach folds the duplicate check into the existing loop:

public class TransactionGate
{
    public void postEntries(List entries) {
        List entriesToAdd = new LinkedList();
        for (Iterator it = entries.iterator(); it.hasNext(); ) {
            Entry entry = (Entry)it.next();
            if (!transactionBundle.getListManager().hasEntry(entry) {
                 entry.postDate();
                 entriesToAdd.add(entry);
            }
        }
        transactionBundle.getListManager().add(entriesToAdd);
    }
    ...
}

It works, but it’s invasive and we have no way to know we got it right. Worse, it muddies the method by mingling two concerns — date posting and duplicate detection — and introduces a temporary variable that tends to attract still more code over time.

The cleaner alternative treats duplicate removal as a separate operation, built test-first as a new method uniqueEntries:

public class TransactionGate
{
    ...
    List uniqueEntries(List entries) {
        List result = new ArrayList();
        for (Iterator it = entries.iterator(); it.hasNext(); ) {
            Entry entry = (Entry)it.next();
            if (!transactionBundle.getListManager().hasEntry(entry) {
                result.add(entry);
            }
        }
        return result;
    }
    ...
}

Then the original method just calls it:

public class TransactionGate
{
    ...
    public void postEntries(List entries) {
        List entriesToAdd = uniqueEntries(entries);
        for (Iterator it = entriesToAdd.iterator(); it.hasNext(); ) {
            Entry entry = (Entry)it.next();
            entry.postDate();
        }
        transactionBundle.getListManager().add(entriesToAdd);
    }
    ...
}

There’s still a temporary, but the method is much less cluttered, and any further work on the non-duplicated entries has a natural home (its own method, eventually its own class). The result is shorter, more understandable methods overall.

The Sprout Method steps

  1. Identify where the change goes.
  2. If it can be a single sequence of statements in one place, write the call to a new method that will do the work and comment it out (doing this first shows what the call will look like in context).
  3. Make the local variables the source method needs into arguments of the call.
  4. If the sprouted method returns a value, assign its return to a variable in the call.
  5. Develop the sprout method test-first (TDD).
  6. Uncomment the call to enable it.

Source

Working Effectively with Legacy Code, Michael Feathers — Chapter 6, I Don’t Have Much Time and I Have to Change It.