Refactoring Your Code

As mentioned in my earlier article, Technical Debt, refactoring your code is very important.  It’s the primary method of managing/reducing technical debt, and helps to constantly improve your codebase. However, knowing what to refactor, what to refactor first, and how to refactor code isn’t always obvious.

What Is Refactoring?

Refactoring is the act of modifying the internals of your code, normally without altering it’s external behaviour. For example, you could change the algorithm used in a function to make it more efficient, without changing what that function returns.

The reason you want to constantly refactor your code is to improve it, as you should always be learning new things. You’ll find faster/cleaner ways of doing something, you’ll learn about potential exploits or bugs in functions, and maybe you’ll just reread your code and realize your comments aren’t as helpful as you first thought. By refactoring your code, you aim to increase the quality of your code.

When should I refactor?

The answer is constantly. With every new feature you add, you should hopefully be refactoring parts of your codebase. You’ll optimize how functions are executed, rewrite comments to make them more obvious, fix bugs you discover, and organize your code logically.

For example, maybe you are asked to add code to prevent brute forcing of a user’s login by limiting failed login attempts. While you are adding this feature, you could refactor the authentication method, adding comments where you think they are needed, and maybe adding functionality that you didn’t have time for in the beginning (For example, maybe you check the user’s status at one point, but didn’t have time to write the error messages and just returned ‘bad status’. You could write out different error messages for each of the statuses).

What should I refactor?

If there is a class or function that has been growing frequently as of late, you may consider tackling that, dividing large functions into smaller functions, each with its own purpose. Maybe you’ve been adding code to your User class that should have it’s own class (UserPets for example). Code like this is what accrues the most technical debt, because you have so much code, some of which should never be in the class (Why does the User class have an isFed function for checking if a pet’s been fed?). This adds unnecessary complexity to your code and should be fixed sooner, rather than later.

Examples

I’ve put together an example below of how you might refactor some code. This is only concerning the class itself, you’ll have to fix all the code that uses this code as well.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
<?php class User { protected $pets = array(); public function __construct( $user_id ) { } public function isActive() { // Check if the user is active } public function getPets() { return $this->pets; } public function isFed( $pet ) { // Check if the specified pet is fed } } // Use case $user = new User( 5 ); $pets = $user->getPets(); foreach ( $pets as $pet ) { if ( ! $user->isFed( $pet ) ) { echo "{$pet->name} hasn't been fed!\n"; } }

Refactored:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
<?php class User { protected $pets = array(); public function __construct( $user_id ) { } public function isActive() { // Check if the user is active } public function getPets() { return $this->pets; } } class UserPet { public $name; public $fed = FALSE; public isFed() { return $this->fed; } } // Use case $user = new User( 5 ); $pets = $user->getPets(); foreach ( $pets as $pet ) { if ( ! $pet->isFed() ) { echo "{$pet->name} hasn't been fed!\n"; } }

 

  2 comments

  1. Pingback: Brandon Wamboldt | Technical Debt

  2. Rory McKinley   •  

    I would extend this article by underlining the importance of a solid foundation of automated tests before embarking on any refactoring. By having unit tests covering your code, you can branch off, refactor aggressively and be confident that your exposed interfaces are unchanged.

    Any code without unit tests is technical debt. :)

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>