Insights

Legacy Code and Safe Refactoring

BY ROBBIE JAKOB-WHITWORTH

As a Junior Developer, my role at Komodo comprises working on a variety of projects for clients with a wide range of different needs. Sometimes I have to help design something new from the ground up, where we have total architectural control over the design of the system and the technologies used. For some other projects, I’m responsible for maintaining legacy codebases.

A Definition

Wikipedia tells us:

Legacy code can be defined as source code that relates to a no-longer supported technology.

In layman’s terms, legacy code is old code that is based on technologies that have lost popularity or fallen out of date.

Supporting legacy code does present its own set of challenges – but I’d argue that there are merits as well. Seeing old code helps develop my understanding of why technologies and frameworks are the way that they are today. Managing legacy code gives me the historical context to libraries and languages that in my case, as a junior, I may not necessarily have had much exposure to.

My day-to-day work can consist of a client requesting a feature change or a bug fix to their existing codebase. In contrast to a new project, I may no longer be able to freely select what tools and libraries I use. Code that I write needs to be in the style of the existing project, while still following modern, up-to-date best practices.

A More Concrete Example

I worked on a project recently where we needed to rebuild several webpages for a codebase that was a few years old. The frontend was built almost entirely with jQuery (I much prefer vanilla ES6 or React) and so I wasn’t able to rely on new features of JavaScript as much as I normally do.

It wasn’t practical to set up a transpiler (like Babel) which would automatically convert my new code to a format that was compatible with the existing codebase. Instead, I had to change how I approached the problem and rethink my solution. As I wrote code in a slightly older style, there was definitely a temptation to rewrite huge parts of the project in a more modern fashion.

Unit Testing

I was fortunate enough to receive a company-sponsored ticket to PHP Yorkshire 2019. One theme that stuck out to me throughout the conference was the importance of unit testing. If we refer back to our friend Wikipedia, we’re told that:

Unit testing is a software testing method by which individual units of source code are tested to determine whether they are fit for use.

I spoke about how every project I’ve worked on at Komodo has a full testing suite – a collection of unit and integration tests to catch bugs early on. Adding unit tests retrospectively to a codebase can prove challenging if that code wasn’t built with unit tests in mind.

Something that caught my attention most was when a senior developer here at Komodo described to me the benefits of dependency injection. This entails isolating your code (the “units”) from the other units they connect to (the “dependencies”), which makes using a tool like Mockery for PHPUnit a breeze. The importance of this was echoed at PHP Yorkshire. One of the talks discussed how to use Mockery and PHPUnit to test the units of your application and how, if necessary, to safely refactor a legacy codebase to incorporate this.

Closing Thoughts

I’ll freely admit that it can be difficult to work with legacy code. However, there’s a certain challenge to it that can be rewarding. Using older versions of a framework like Laravel helps me understand why modern versions of the tool are built in the way that they are, and helps me think more critically about what improvements could be made to the underlying technologies.

I would like to thank iamproperty for the PHP Yorkshire conference ticket and Komodo for sponsoring my travel and accommodation.

Insights

Curiosity is what drives us to learn and grow professionally enabling us to remain vigilant to change and the opportunities it presents for our clients. We document some of this learning and share it via our 'Insights' section.