Spaghetti code is frightening, but it is something that we all have hanging out there on the Internet that our 14 year old self would be amazed by. Spaghetti code is technically known as legacy code. I struggled with refactoring a larger application I did into a MVC architecture. It was about half of a million lines of PHP code. Refactoring it was an uphill battle and was well worth it. Wanting to call it quits was tempting and now I can share with you pitfalls and strategies to use when evaluating your next project. I’ll go through the steps and thought process I had when it came to refactoring my PHP application.
Step 1: Accept that your PHP code is legacy and determine your objectives
Your code is legacy. Period. The things that you are implementing today will be considered legacy by the time you are done reading this article. The fact that you are reading a blog post about refactoring your legacy code means that it is legacy.
The hardest thing for me was to accept that my project was coded poorly compared to the new software techniques I learned. Sure it had some newer features for the customer but the code base was struggling heavily. The customer was starting to have recurring problems with the application and I had no good way to test it or troubleshoot it.
I really wanted to nuke this thing from orbit and just start over. I’d fantasize about starting from a clean slate and not having any issues any more. Phrases like: Test Driven Development, 100% code coverage, modular design, semantic versioning, continuous integration, etc. all rolled through my head. Then I saw Paul M. Jones give a talk at Midwest PHP 2014.
When you get excited about nuking code from orbit – you need to take a step back and evaluate the technical debt you currently have.
I found out that nuking my code from orbit (or anyone’s code) is not the answer. It only took me a conference and a talk by @pmjones to convince me otherwise – nevertheless, I chose to refactor the code base in incremental steps to help repay my technical debt. Acceptance set in.
You can probably identify tons of things wrong with the application at hand. For me it was the continuous bug I was encountering with keeping track of employee time. This was the biggest thorn. The next low-hanging fruit for me was moving things out of the bloated functions.php file and into actual classes that could be auto-loaded.
Step 2: Take out the low-hanging fruit (technical debt)
Having the low hanging fruit gives you a quick win that is needed for repaying your technical debt. If you go through refactoring your entire PHP code base without accomplishing something for weeks – you will be less likely to do it and stick with the regiment.
Also, the most important thing that Paul mentions while identifying and starting to make incremental changes is to “Keep your application running”. You cannot afford downtime on this application. If it means spinning off a module and having a custom router control the application flow then that is what you need to do to take out the low hanging fruit.
Step 3: Develop, test, and reduce risks
Now that you are removing all of the includes and requires from your legacy application you feel a bit better right? Good! Now you can start focusing on developing those features that your customer needed yesterday. Don’t fall into the mistake of underestimating the time like I did!
I fell into a trap where I wanted to get features done for the customer and get on to the next paying job. This trap skips testing and analysing future project risks while introducing bugs into the existing software.
Bugs erode trust.
Now that you know the proper way to code you must stick with the regiment. You must continually improve and have that time allocated for on your projects otherwise you will erode the trust that you need as a developer.
Step 4: Plan the next release
Rinse, rather, repeat. Since you are done implementing your new code along with some reduction in technical debt – plan your next release. I listen to what the customer is saying and try to balance that with any goals I may have with the project. Maybe the next iteration I will finally spend 10% of budgeted time towards writing regression tests since there have been some backwards compatibility issues.