Code Refactoring
Often, you’ll come to a point where your code will work, but you’ll recognize that you could improve the code by breaking it up into a series of functions that have specific jobs. This process is called refactoring. Refactoring makes your code cleaner, easier to understand, and easier to extend.
Let us apply refactoring process by example in Python programming language. Suppose we have a program to store usernames in a json file as below:
And another program that greets a user whose name has already been stored:
We need to combine these two programs into one file. When someone runs the program, we want to retrieve their username from memory if possible; therefore, we’ll start with a try block that attempts to recover the username. If the file (username. json) doesn’t exist, we’ll have the except block prompt for a username and store it in (username. json) for next time:
There’s no new code here; blocks of code from the two programs are just combined into one file. Whichever block executes, the result is a username and an appropriate greeting. If this is the first time the program runs, this is the output:
What is you name? Ahmed
We'll remember you when you come back, Ahmed!
Otherwise:
Welcome back, Ahmed!
This is the output you see if the program was already run at least once.
Recommended by LinkedIn
Refactoring Step 1
We can refactor this program by moving the bulk of its logic into one or more functions. It's focus of is on greeting the user, so let’s move all of our existing code into a function called greet_user():
This file is a little cleaner, but the function greet_user() is doing more than just greeting the user—it’s also retrieving a stored username if one exists and prompting for a new username if one doesn’t exist.
Refactoring Step 2
Let’s refactor greet_user() so it’s not doing so many different tasks. We’ll start by moving the code for retrieving a stored username to a separate function:
The new function get_stored_username() has a clear purpose, as stated in the docstring. This function retrieves a stored username and returns the username if it finds one. If the file (username. json) doesn’t exist, the function returns None. This is good practice: a function should either return the value you’re expecting, or it should return None. This allows us to perform a simple test with the return value of the function.
Now we print a welcome back message to the user if the attempt to retrieve a username was successful, and if it doesn’t, we prompt for a new username.
Refactoring Step 3
We should refactor one more block of code out of greet_user(). If the username doesn’t exist, we should move the code that prompts for a new username to a function dedicated to that purpose:
Each function in this final version has a single, clear purpose. We call greet_user(), and that function prints an appropriate message: it either welcomes back an existing user or greets a new user. It does this by calling get_stored_username(), which is responsible only for retrieving a stored username if one exists. Finally, greet_user() calls get_new_username() if necessary, which is responsible only for getting a new username and storing it.
This compartmentalization of work is an essential part of writing clear code that will be easy to maintain and extend.