DEV Community

Cover image for Changing Software : Sprout Method
DevByJESUS
DevByJESUS

Posted on

Changing Software : Sprout Method

Hello Everybody ๐Ÿ˜„
It is me again ; we continue talking about legacy code .
Today we are going to talk about the question I Don't have much time and I have to Change It when working with legacy.
Let's go ๐Ÿ˜œ

What it costs us

We are not gonna lie , with testing developers are going to write much more additional code , yes with tests. Laura comes and say i do not have much time and i have to write it ๐Ÿ˜’ , and Paul responds I understand you but think about it , if you do not write it now and say i will come later , we all know that once the feature has been added no one is going to look back to that mess in the code .

๐Ÿ˜‰
Look at what M. Feathers says:

The truth is, the work that you do to break dependencies and write tests for your changes is going to take some time, but in most cases, you are going to end up saving timeโ€”and a lot of frustration. When? Well, it depends on the project. In some cases, you might write tests for some code that you need to change, and it takes you two hours to do that. The change that you make afterward might take 15 minutes. When you look back on the experience, you might say, โ€œI just wasted two hoursโ€”was it worth it?โ€ It depends. You donโ€™t know how long that work might have taken you if you hadnโ€™t written the tests.

Paul : we can go now Laura ? ๐Ÿ‘€
Laura : Yes show me how to introduce this feature by being clean and cover it with test. ๐Ÿ˜’

Let's go

Paul : I will introduce to you the Sprout Method
let's start ๐Ÿ˜‡

Paul : small example , look here Laura

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

Paul : If the next feature is verify that none of the new entries are already in transactionBundle before we post their dates and add them
I know you Laura ๐Ÿ˜‚ , the most easy solution will be to write this

Bad ๐Ÿ’”

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);
}
Enter fullscreen mode Exit fullscreen mode

Paul : But Laura why not cover your new code with test and make a separation with the old code and the new one ?

Laura : How ? show me ๐Ÿ˜‘

Paul : The process is simple ๐Ÿ˜‡

  1. Identify where you need to make your code change.

  2. If the change can be formulated as a single sequence of statements in one place in a method, write down a call for a new method that will do the work involved and then comment it out.

  3. Determine what local variables you need from the source method, and make them arguments to the call.

  4. Determine whether the sprouted method will need to return values to source method. If so, change the call so that its return value is assigned to a variable.

  5. Develop the sprout method using test-driven development

Paul : i know it can be hard the first time , but look at how the code looks like when we follow this process

Paul : First we know we can create a new method for the requested feature and why not doing it with Test Driven Development .

Paul : So the result is like below , our new code for the new requested feature , and developed with TDD.

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;
}

Enter fullscreen mode Exit fullscreen mode

Laura : But it is without value Here ๐Ÿ˜ช

Paul : Yes , the interesting part is here , we can now use our newly created method in the place where we need it , in the old code .


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);
}

Enter fullscreen mode Exit fullscreen mode

Laura : Hum , it seems pretty clean , and i can reuse the uniqueEntries method if there is a new feature that needs it ๐Ÿ˜ .

Paul : You start to understand ๐Ÿ˜

Paul : This is the Sprout Method.

Laura : Really , Thanks Paul .

Paul : you're welcome but do not thank me . All this is from the book of Michael Feathers Working Effectively With Legacy Code.

Sprout Method : Disadvantages

Like you have seen we separate the old from the new one , and here only the new code is under test , and this is the downside of the Sprout Method .

Sprout Method : Advantages

What M. Feathers says :

When you use Sprout Method, you are clearly separating new code from old code. Even if you canโ€™t get the old code under test immediately, you can at least see your changes separately and have a clean interface between the new
code and the old code. You see all of the variables affected, and this can make it easier to determine whether the code is right in context.

Thanks for Reading ๐Ÿ˜ƒ
Email Me
YouTube Channel
Twitter
Instagram

JESUS loves you โค๏ธ

Discussion (0)