The Split Phase Refactoring

When we write code to solve a tricky problem, we often end up with methods that show us the whole journey of how we got to the solution: there is code to load data, followed by transformation logic intertwined with data clean-up hacks to prevent the creation of a report from exploding.

It is nothing wrong with writing code that way and to iterate until we reach the goal. The problem is that we keep everything in the order in which we initially wrote it. The developer who needs to fix a bug does not care if we found a missing default value at the beginning of the implementation or at the end. They much more prefer code that separates the different phases (load, clean-up, transform, report) and guides them towards the place where they should implement the fix.

The clear separation of the different phases makes the code simpler to understand and thus reduces the risk of breaking the existing features when we fix bugs. Let’s look how we can refactor code into distinct phases.

 

The mechanics

The split phase refactoring https://refactoring.com/catalog/splitPhase.html helps us to separate our methods into different phases. We can use this process to separate two phases:

  1. Use Extract Method for the second phase in your method
  2. Test
  3. Introduce an intermediate data structure as an additional argument to the extracted method.
  4. Test
  5. Examine each parameter of the extracted method of the second phase. If it is created by the first phase, move it to the intermediate data structure. Test after each move.
  6. Use Extract Method for the first phase and return the intermediate data structure.

If you have three or more phases, start with the last phase and work your way up to the first phase using the process from above. You may need more than one intermediate data structure depending on what your code does.

 

A small but realistic example

This little birthday calendar creator uses the Adventure Works database to get a list of all employees and orders them by their birthday in the year:

There is a phase to load the employees, a clean-up phase and the report creation that gives us this result:

(Mr.) Brian S. Welcker: 06/06/1977
        Suchitra O. Mohan: 10/06/1987
        Don L. Hall: 13/06/1971
        Ryan L. Cornelsen: 13/06/1972
        Michael T. Entin: 15/06/1989
        Michael I. Sullivan: 16/06/1979
(Ms.) Jill A. Williams: 18/06/1979
        David M. Barber: 21/06/1964

 

Extract the report creation

The last phase in our example is the report creation. We extract the line in its own method and introduce the intermediate data structure (the class ReportEmployee):

It is a small start, but we need to start somewhere.

 

Move parameters

Next we move the parameters birthday, middleName and title to the ReportEmployee class (they are all created in the clean-up phase). We add a property to the ReportEmployee class, assign the value in the clean-up phase and use it in the report phase. As a final change we remove the parameter from the method signature:

 

Extract the clean-up phase

Next we extract the clean-up phase and return the ReportEmployee:

For the moment we keep the dynamic row parameter as it is.

 

Extract the load phase

The remaining phase in our Create() method is the database access. We can extract everything related to the employee query into its own method:

 

The result

Our Create() method is now down to this algorithm with all the concrete work extracted to the phase-specific methods:

We can now write tests for the extracted methods and address the code smell with the dynamic object for the row parameter. With everything clearly separated, we could move the clean-up behaviour to the ReportEmployee class and turn it into a full object with data and behaviour. The better we understand the code, the more options we have to clean it up.

If you want to try it on your own, you find the code on GitHub.

A graphical representation of the structure before and after the split phase refactoring can look like this:

We start with a method full of mixed phases and we end with a small class for the algorithm and separate classes for the different phases.

 

Conclusion

The split phase refactoring offers us a way to improve the readability of our code. The tiny steps may look boring, but that’s where the safety of this refactoring lies. This safety aspect is of great importance when we need to add automated tests to existing code that everyone considers “untestable”. Try it with a method that needs clarification in your project and let me know how it went.

Leave a Comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.