By Mark Jones
10th December 2014
Posted in PHP, Web Dev
In this first article of the series, we will look at some very simple ways to refactor your code.
So what is Refactoring? Refactoring is simply a set of techniques, procedures and steps to keep your source code as clean as possible.
Below describes some of the easier code smells to detect and how you can go about refactoring them.
This is probably the easiest code smell to detect, and also refactor. It is also known as ‘Extract Method Refactoring’.
Take the below function as an example, which totals up the sum of two receipts:
[php]
function sumReceipts(){
$firstReceiptsTotal = 0;
foreach($this->receipt1 as $value){
$firstReceiptsTotal += $value;
}
echo ‘First Receipt\’s Total: ‘.$firstReceiptsTotal;
$secondReceiptsTotal = 0;
foreach($this->receipt2 as $value){
$secondReceiptsTotal += $value;
}
echo ‘Second Receipt\’s Total: ‘.$secondReceiptsTotal;
echo ‘Grand total: ‘.$firstReceiptsTotal + $secondReceiptsTotal;
return $firstReceiptsTotal + $secondReceiptsTotal;
}
[/php]
As you can see, in the above code there are two foreach loops which do exactly the same thing except loop through different receipts. We could create one function to perform this foreach loop and pass the receipt to the function as an argument so it knows which receipt to loop through.
For example:
[php]
function getTotalForReceipts($receipt){
$firstReceiptsTotal = 0;
foreach($receipt as $value){
$firstReceiptsTotal += $value;
return $firstReceiptsTotal;
}
}
[/php]
Our sumReceipts method would then look like the following:
[php]
function sumReceipts(){
$firstReceiptsTotal = $this->getTotalForReceipts($this->receipt1);
echo ‘First Receipt\’s Total: ‘.$firstReceiptsTotal;
$secondReceiptsTotal = $this->getTotalForReceipts($this->receipt2);
echo ‘Second Receipt\’s Total: ‘.$secondReceiptsTotal;
echo ‘Grand total: ‘.$firstReceiptsTotal + $secondReceiptsTotal;
return $firstReceiptsTotal + $secondReceiptsTotal;
}
[/php]
As you can see, we have removed eight lines of code and only added two saving ourselves 6 lines of code. This may not seem like much but doing this throughout a whole project could possibly save you hundreds of lines of unnecessary code
However have a look at the code again and see if we can see any other pieces of code that are very similar to each other.
Hopefully you would have noticed that the first two echos are near enough exactly the same, except for the name of the receipt and the receipt total. Therefore we could create a function in which you pass through the receipt name and total, and just put one single echo line in this new function. For example:
[php]
function displayReceiptTotals($receiptName,$receiptTotal){
echo $receiptName.’ Receipt\’s Total: ‘.$receiptTotal;
}
[/php]
Our new sumReceipts method would then look like this.
[php]
function sumReceipts(){
$firstReceiptsTotal = $this->getTotalForReceipts($this->receipt1);
$this->displayReceiptTotals(‘First’,$firstReceiptsTotal);
$secondReceiptsTotal = $this->getTotalForReceipts($this->receipt2);
$this->displayReceiptTotals(‘Second’,$secondReceiptsTotal);
echo ‘Grand total: ‘.$firstReceiptsTotal + $secondReceiptsTotal;
return $firstReceiptsTotal + $secondReceiptsTotal;
}
[/php]
In this example we haven’t reduced the number of lines code but putting it into a single function means that when we want to change the echo statement, we only have to change it in one place, which makes it less error prone and removes redundancy.
The key to remembering this type of refactoring, when looking at your own code, is to first of all keep an eye on any lines that are very similar, especially in the same function, and then see if a new function can be created to do the same job.
As well as removing code duplication, you should also try and remove any duplicated calculations.
So taking the sumReceipts method example again, you will notice the following code:
[php]
echo ‘Grand total: ‘.$firstReceiptsTotal + $secondReceiptsTotal;
return $firstReceiptsTotal + $secondReceiptsTotal;
[/php]
As you can see, these two calculations do exactly the same thing. Therefore we can just do the one calculation and put it into a variable for the result to be used anytime after, as below demonstrates.
[php]
$grandtotal = $firstReceiptsTotal + $secondReceiptsTotal;
echo ‘Grand total: ‘.$grandtotal;
[/php]
Again like in the last example, we don’t reduce the lines of code, but we do minimise the amount of calculations being executed, which will increase the speed of the code.
Remember this exactly the same way you would when refactoring duplicated code. Just look out for any calculations that have been duplicated elsewhere in the function and put the result of the first time the calculation appears into a variable, and then use that variable from then on rather than re-calculating each time.
This type of refactoring is more difficult to spot but like all the others, once you have practiced it over and over, you will eventually find it easier to spot.
The example function below is similar to our first example function but instead of finding the total of two receipts added together, this function subtracts the total of the second receipt from the total of the first receipt.
[php]
function subReceipts(){
$computedValue = 0;
foreach($this->receipt1 as $value){
$computedValue += $value;
}
foreach($this->receipt1 as $value){
$computedValue -= $value;
}
echo ‘Subtracted total: ‘.$computedValue;
return $computedValue;
}
[/php]
So how could we refactor this function? Well, following our first example you may think that there are two foreachs doing very similar things, in which case we can create a new function to perform the task and use the new function rather than the two foreach loops.
Even though this would be possible, you would be creating more code than what the two for each loops are using. Unlike the first example these foreach loops use different calculations as one adds the items up and the other subtracts them. This means the new function we were thinking about creating would have to take at least three arguments (receipt1, receipt2, calculationType) and at least three lines of code. Even though this would reduce the code from 6 lines of code to three lines of code, its best practice to keep the amount of arguments passed to a function down to a minimum. There is also a better way this can be refactored to reduce the number of lines of code without having to create a new function.
First of all, if we look at the first foreach loop, we will notice that it does exactly the same as the foreach loop that we extracted into a function from the first example (adding receipt items to get total). Therefore we can use this this same function here to replace the first foreach.
The second foreach is a bit more tricky when considering how we can reduce the number lines of code. The second foreach loop is doing the same as the above function we just used, but instead of adding the item values it deducts them from the first receipt. What we could do here instead is, again, use the same function we have previously used to add up the total of the receipt. We then do one simple calculation which is to remove the total of the second receipt from the first receipt. This means we have now removed two foreach loops and instead used the function we created earlier. The only extra line of code added was the simple calculation mentioned above.
So our newly refactored subReceipts function now looks like this:
[php]
function subReceipts(){
$computedValue = $this->getTotalForReceipts($this->receipt1);
$computedValue2 = $this->getTotalForReceipts($this->receipt2);
$computedValue -= $computedValue2;
echo ‘Subtracted total: ‘.$computedValue;
return $computedValue;
}
[/php]
As mentioned previously, this refactoring can be difficult to find but the best way to remember it is similar to the other examples I have given. First look for any similar code, in this case two foreach loops. See if there are any functions that already do the same thing as was the case with the first foreach loop, then see if the same end result can be achieved using an existing function and modifying the way the calculation is done.