Refactoring - an ode to code

Kevin

Kevin


Aug 27th 2019 in code explication

What is refactoring? Should you redo your whole project? How can you proceed?

This article will give you an overall explanation of refactoring in software development.
We will explore the theory and then present some examples from real life.
But, as I always say, no explanation is complete without clarifying the benefits and challenges first.

Let's get to it, shall we?

What is it?

Refactoring refers to independent techniques and steps to improve code that has already been written.
To make it short, refactoring is the art of increasing the maintainability of a piece of code.

There are two ways of constructing a software design. One way is to make it so simple that there are obviously no deficiencies. And the other way is to make it so complicated that there are no obvious deficiencies.
—  C.A.R. Hoare

But don't get me wrong, having to refactor your own codebase is not bad. It doesn't make you a poor-skilled developer.
Actually, during your career you will always be refactoring code (yours or others).
The Technical debt is a complete part of the development process, as nicely stated in this article from Marc Friederich & Gilles Doge.

On a standard 101-key keyboard, there are 100 keys that increase technical debt, and only one key that reduces it.
— Josh Wulf

During a refactoring process, you might be doing a lot of changes, adding new Classes, renaming, reorganising. But remember, at the end of your journey you won't ever be altering the observable behaviour of the code.

First, refactoring is not debugging. Your code needs to be running in the first place.
Of course, during a refactoring process you may find bugs. The moment that you start dealing with them, you've stopped refactoring and started bug fixing, which is another mindset.

Second, refactoring is not about performance.
I was speaking with a young developer the other day who was trying to convince me that refactoring a codebase makes it obviously faster.
It is a very common misconception that bad code automatically leads to performance leaks. The performance of your code is not the goal of a refactoring process - nor even what you should expect out of it.

Finally, refactoring is not adding features.
When you are refactoring a part of your code, you should not change its behaviour, otherwise you are no longer refactoring.

Should you do it?

You did not fix bugs, you did not make it faster, you did not add any new feature.

So, you may ask me "why should I refactor then?".

Well, the answer is quite simple. Well-structured code will make it so much easier to add new features and new capabilities in the future. And, it will make it easier to start analysing performance or overall improving the application.

By improving the code quality, you will also improve the overall team efficiency, certainly save a fair amount of money and make your developers happy to work on that codebase - or at least I hope so.

It's called technical debt, because it's like taking out a loan. You can accomplish more today than you normally could, but you end up paying a higher cost later.

If you face tedious difficulty getting approval on spending time for refactoring - because the benefits aren't immediately apparent - remember that you're not refactoring for your end-user, you're refactoring to get the future roadblocks out of your way.

How do we do it ?

Bored of reading theory? Alright - me too - let's dig into some real-life examples.

Always code as if the guy who ends up maintaining your code will be a violent psychopath who knows where you live.
— Martin Golding

There is no such thing as a set of rules or a specific order that anyone can just follow, but there is a set of techniques to help you refactor code. Here I will drop some of my favourites and easy ones to try to use in every project.

One more thing, if I could give you one piece of advice, and share insight on one thing it would be this one simple sentence: "Never refactor a production code that does not have unit tests".
The main reason is maybe pretty obvious, but let me say it out loud again: without unit tests, you will end up with broken functionalities that are nearly impossible to fix because you won't be able to figure out what's happening anymore.
So please, if you have to refactor something, first make sure it is covered by tests.

Where are the tests?

Conditional Guard Clauses (return early)

To keep readability in functions and methods, it's wise to return early if simple conditions apply that can be checked at the beginning of a method. Then, when it's hard to determine the normal flow of code execution, try to isolate checks.

It's better to return early, keeping indentation and brain power needed to follow the code low.

Isolate all special checks and edge cases into separate clauses and place them before the main checks. Ideally, you should have a flat list of conditionals, one after the other.

Assignments to Parameters

Sometimes, you will need to alter a given parameter value inside your own method body. If this parameter is passed via reference, then after the parameter value is changed inside the method, this value is passed to the argument that called this method.
Very often, this occurs accidentally and leads to unfortunate effects. Even if parameters are usually passed by value (and not by reference), this coding quirk may be weird to those who are unaccustomed to it.

Use a local variable instead of altering the parameter.

Replace Array with Object

Arrays are an excellent tool for storing data and collections of a single type.
But if you use an array like post office boxes, storing the username in box 1 and the user's address in box 14, you will someday be very unhappy that you did that way.

You have an array that contains various types of data.

Replace the array with an object that will have separate keys for each element.

Plus, using Object over Array, you will be able to apply properties assertions, I would suggest everybody to take a look at the ArrayAccess implementations which is great to replace object-like Array.

Replace Magic Number with Symbolic Constant

Magic numbers or magic values are encountered in the source code but have no obvious meaning. This "anti-pattern" makes it harder to understand the program and thus refactor the code.

Often, a simple Find & Replace won't work on those values, as the same data may be used for different purposes in different places, meaning that you will have to verify each line that uses this value.

Replace this number with a constant that has a human-readable name explaining the meaning of the number.

Consolidate Conditional Expression

When your code contains a lot of alternating operators that perform identical actions, it is not clear why the operators are split up.

The main purpose of consolidation is to extract the conditionals to separate methods for more clarity.

Consolidate all these conditionals in a single expression.

Use the language capabilities

Often, developers forget some awesome capabilities of the programming language they use.
Many of these features can save you a lot of effort. Take a look at the next examples and notice how it can be easy to achieve the same result by using the type hinting methodology.

Could be changed to a simpler method with the same capabilities

Inline Temp

Prevent usage of temporary variable when necessary. For example, when you have a temporary variable that is assigned the result of a simple expression and nothing more.

Replace the references to the variable with the expression itself.

What else ?

I would like to end with a few more quick tips on better coding:

  • Use a new array form [ ] instead of the old array()
  • Use === operator instead of == unless it is important to not check for the dataType
  • Use prefix is/has with functions that return boolean ex: isAdmin($user), hasPermission($permission, $user)
  • Organise class methods with public methods at the top
  • Always apply the single responsibility concept to your classes


Sources

For the most curious of you, here are some sources of additional information that inspired the creation of this article.

Sourcemaking (23 August, 2019). Refactoring
See on https://sourcemaking.com/refactoring

Refactoring Guru (23 August, 2019). Refactoring Guru
See on https://refactoring.guru/refactoring

Mohamed Aladdin (19 August, 2018). Refactor Your PHP legacy Code (real projects examples)
See on https://medium.com/hackernoon/refactor-your-php...

Josh Wulf (15 April, 2018). There is no good coding, only good refactoring
See on https://medium.com/@sitapati/there-is-no-good-...

Fionna Chan (11 October, 2018). Code Refactoring — How to Write Better Code
See on https://medium.com/@fionnachan/code-ref...

Thomas Deniffel (20 April, 2019). Brutal Refactoring)
See on https://medium.com/@tdeniffel/brutal-refactorin...

Samuel Roze (21 August, 2018). Refactoring the right way: regional, not global
See on https://medium.com/@sroze/refactoring-the...

Omar El Gabry (02 October, 2017). Refactoring — The Hygienic Habit
See on https://hackernoon.com/refactori...

Shawn McGrath (22 August, 2016). The Exceptional Beauty of Doom 3's Source Code
See on https://kotaku.com/the-except...

The copyright for CommitStrip is held by CommitStrip and is licensed to CommitStrip.