- October 4, 2021
Don't Open That Black Box: How to Efficiently Modernize Legacy Projects
Aging happens to every project that survives long enough; it can't be stopped by any plan, sprint, or project approach. Technical debt is accrued, features are abandoned, tradeoffs are made—it's the natural byproduct of building software.
The development industry politely refers to this aged state as “legacy,” and you've likely been a part of at least one project in this state. It's nothing to be ashamed or regretful of! It's a sign that your project is successful. Your project is still around and creating value. You made it.
But there's still more to be done: features need to be built, deadlines need to be met, KPIs need to be reached. You can still provide value to your audience, but these days it seems that your application itself is holding you back more than anything else.
Happy Cog recently completed a project in that exact state: modernizing it after nearly a decade of development work, feature additions, and bug fixes, as well as several stakeholder arrivals/departures.
Here's what we learned:
Leave the black box alone: now is not the time for boy-scouting
In software, a “black box” is any feature of a project that can be thought of purely by what it needs, and what it does. (In other words, its inputs and outputs.) Feature X requires three files and a way to email them to a user, Feature Y requires a list of calendar events and specific settings for an organization, and so forth.
When you're modernizing your project, it works best to think of features as black boxes—you don't need to thoroughly examine the minute details of each line of code that makes the feature work, you just need to know if it works in the version of your project's framework.
This is opposite to how many developers work (yours truly, included)—we want to resolve issues as we encounter them so we're more confident in the state of the feature once we're finished.
While this approach works well for many efforts, it'll derail the process of modernizing your application. Hours can be easily-burned fixing issues that—while important—aren't critical to the primary task of modernizing your application. If you want to have anything close to a realistic deadline, don't do this.
The only changes that should be made are those that are critical for the application to function in the latest version of your project's framework. Doing otherwise puts your modernization efforts at risk of burning through a large portion of your budget without having accounted for any of that time.
But—that doesn't mean issues within the “black boxes” should be ignored completely. Instead, note them as they're encountered, then continue working on the primary task of modernization. Once you've completed the initial efforts of modernization (i.e. you're running in a later version of your project's framework), revisit the issues you found and take a deeper dive into each 'black box'.
Place value on the time spent debugging the current state of your project
It's common for developers to take the "complete rewrite" approach to modernizing or upgrading projects. In some cases this is actually best—the time required to comb through the codebase and address each area to make the project function in a later version is significant, compared to simply rewriting the logic in the new version.
But—that's not always true.
In our project, there was one particular file that was heavily-used across the application. It wasn't particularly large or complex; there were other files that were much more demanding to understand.
What it did have was over 8 years of bug fixes—thousands of hours running on the live site, being used by actual users. Those users found bugs we hadn't ever considered.
The file had nearly 300 commits addressing specific issues/requests/modifications from real, paid users of the project.
It would've been easy to toss the file and rewrite the feature while modernizing the project, but if we'd done so without first considering the current state of the feature, we would've lost all those hours without any significant benefit that warranted rewriting the feature.
Don't ignore the 'unknown unknowns'
Legacy projects require context, and lots of it. All the little features that were added over the years, the small changes and tweaks made at the request of users, the minor functionality that's never mentioned—those things are likely undocumented, but if they're missed or forgotten while modernizing, it can be significantly damaging to your application's user experience.
We were able to 'dig up' many of these areas by asking this question:
What does the project do, and how does it do it?
What we ended up with was a list of features and references to how it specifically accomplished that task. Along the way, we found many minor features that would've been missed while modernizing, and likely would have remained broken until the issue was found by a user.
Legacy applications are complex, scary things—doubly so if your team hasn't been involved since the beginning. But don't let the age of your project discourage you from modernizing your project; work around the black boxes, note issues/ideas as you find them, and you'll come out on the other side with a better product that enables your developers to work faster (and easier), and a list of ideas and tasks you found to make it even better.