Strategies for ensuring project success and
reducing technical debt, Part 1
Legacy code. There’s no other words that scare software engineers as much as these two. In fact,
most of them probably stopped reading when they saw the word ‘legacy’. However, working with
legacy code is a large portion of what software engineers do throughout their career, and if they are
not working with legacy code then they are creating it for another engineer in the future. And,
unfortunately, many legacy applications and architectures were either not properly implemented or
maintained well as time went on. Code passes hands from the original developers to contractors to
new application developers and each day the two words every executive hates to hear becomes
more apparent— technical debt.
Just like financial debt, technical debt can begin to grow and accumulate “interest”,
draining precious resources from businesses. Often it can feel like you’re drowning in debt and
unable to modernize your system because of it. The good news is that by implementing some best
practices technical debt will be reduced over time and new projects will have a better chance of
success. Here are some strategies the engineers at ImagineX use to accomplish this goal.
“If you don’t know where you’re going, any road will take you there.”
-Lewis Carroll, Alice in Wonderland
The first step we always take on any project of any size at ImagineX is a full technical assessment.
By getting a full picture of the current state of an enterprise ecosystem we can then develop
strategies about where the system can go in the future as well as the effort required to make it
happen. The assessment is crucial because this will eliminate additional future technical debt by
avoiding it altogether, and it will define the constraints of time and money to invest in the system.
We assess where current technical debt is, how it can be reduced, and how to mitigate it
given the budget and expectations of the client. Once assessed, we can then develop strategies to
meet a customer’s goals and expectations. Some applications can be refactored and moved into
the cloud while others may need replacing altogether and others are best left as is. Our aim is to
maximize the return on investment by getting the most benefit for the cost. With a good strategy
and plan in place it’s time to move to the next step.
“Quality is not act. It is a habit.”
Once we have made an assessment, have a strategy, then we just need to start making changes
to the code, right? WRONG. Changing legacy code is risky—-very risky. One little change in a
brittle system could bring the whole thing to a halt. This inevitably leads to someone asking, “Why
didn’t anyone test this!?!”, probably in a very angry, irritated voice. It’s always important when
dealing with legacy code to start regression testing even if and especially if it was never done in the
A LOT of technical debt is due to untested code. This is simply due to the fact that
engineers cannot comfortably make changes knowing that they are not going to break something
else. And when changes do occur, as they always must, engineers spend a large portion of their
time debugging and fixing defects due to unforeseen effects of those changes. This can lead to the
most dreaded of development practices, Defect Driven Development.
Defect Driven Development, or DDD, is an anti-practice that goes like this: An application or
system created that does something and is then released into production for end-users to use. The
end-user discovers that the system is not behaving the way they would like or is not working
altogether. A defect is logged for the application and sent to the developer and sees it and says
“Oh, I didn’t know it was supposed to do that.” The change is then made and released to the enduser
in production who finds that the change is not exactly what they were expecting or that it
broke something else. A defect is logged….you get the point.
Avoid this painful development process by creating a full testing environment separate and
identical to the current production. This testing environment is then dedicated to Quality Assurance
(QA) team to test every part of the system before moving into the production environment.
Implement automated regression tests so any change to existing features that breaks something
else is found in QA before moving to your production environment. The biggest challenge here with
legacy code is that requirements are not always clear since it could be a piece of existing software
created years, even decades, ago.
Creating a test suite for legacy systems can be a huge undertaking, so careful planning
must take place to prioritize and create tests where appropriate. For example, if you know the
refactoring of an application will only affect certain parts of a system then the test coverage should
be limited to those areas initially. As time and budget allows, continue testing other areas of the
system. Defects will still arise because of unknown requirements and unknown effects of changes,
but, as additional testing is implemented to cover these defects, engineers can grow increasingly
confident their changes will not cause critical damage.
Part 2 Coming Soon – In the next post we’ll look at Continuous
Integration and Delivery, Refactor vs. Replace, and Agile Methods