DEV Community

Cover image for Refactoring -- An Example
Humberto A Sanchez II
Humberto A Sanchez II

Posted on

Refactoring -- An Example

Introduction

What is refactoring? Why would a developer need to do a refactor? How do I refactor? I'll strive to answer these questions.

What is Refactoring

Refactoring is developers rewriting code to improve its structure. Developers make small incremental changes and verify functionality has not changed. Unit tests are the single most important enabler of refactoring. They provide automatic verification. They allow the developer to refactor and improve the underlying code with impunity.

Motivation

Developers refactor in order to make code testable, easier to understand, and easier to update. This code restructuring does NOT change its external behavior.

Refactoring Step by Step

PreRefactor Class

The following is a wxPython dialog in pre-refactoring mode. A cursory look at the code outline shows a curious mix of code functionality. It is violating the basic Single Responsibility Principle. Look at the code highlighted in the following figure:

Alt Text

Single Responsibility Principle

Classes should honor the single responsibility principle. This principle says that a class should do a single thing and only a single thing and do it well.

More formally it states, that every class in a computer program should have responsibility over a single part of that program's functionality and it should encapsulate it.

I assert that being a dialog this class should only do or handle user interface functionality. Specifically, functionality required by a wxPython dialog. All other things should be deferred to another “chunk of code” or better yet another class.

I assert that the following methods are basic functionality that manipulate which tip text to display and do not directly belong in a user interface class.

• ._getCurrentTipText() 
• ._incrementTipNumber()
• ._normalizeTip()
Enter fullscreen mode Exit fullscreen mode

Post Refactor Class

Extract Functionality

Thus, the first step is to extract the tip manipulating functionality into a separate class. This makes it necessary to create a class named TipHandler.

In literate programming this name is self-explanatory. Literate programming is a way to write computer code that is understandable by a human. In the past, programmers wrote programs and code that was optimized for a computer. With today’s advances in computer speed and optimization it is perfectly possible with no penalty to write a verbose program that reads like prose.

Notice that in the following figure the TipHandler has the following non-UI functionality:

• Knows the current tip number
• Knows the current tip text
• Can properly increment the current tip number
Enter fullscreen mode Exit fullscreen mode

Alt Text

Pure UI Class

Once we extract the above functionality from the UI class we wind up with a pure UI class as illustrated below.

Alt Text

At first glance the following class methods do not appear to be UI only functionality.

• ._getTipText()
• ._normalizeTip()
Enter fullscreen mode Exit fullscreen mode

UI Constructor

Let us first look at the class constructor in the following image.

The UI class has effectively encapsulated the TipHandler functionality, so that it can delegate to it. This allows the UI class to be oblivious to the TipHandler inner workings.

Alt Text

TipHandler Unit Tests

The following figure depicts the unit tests necessary to functionally test the newly extracted class. These tests verify:

• How the tip count is computed
• Retrieving the correct current tip number
• Retrieving the correct current tip text
• How to properly increment the tip number and account for wrap-around
Enter fullscreen mode Exit fullscreen mode

Alt Text

Conclusion

Thus, what we have accomplished is:

• A simple refactor that turns one class into two
• Demonstrated the single responsibility principle
• Demonstrated literate programming
• Provided an example of unit tests for the extracted functionality
Enter fullscreen mode Exit fullscreen mode

Top comments (0)