In our practice as scientific software engineers at VORtech, we work for organizations that have computational software as an essential part of their intellectual capital. If successful, such a computational software package can exist for many years and even decades. Over time, it evolves. At the same time however, the code base grows and becomes more and more difficult to manage. The efforts required to maintain and extend this legacy code become extensive. This could go up even to the point that, despite the enormous investments, a from-scratch replacement seems the only way forward.
This is part 2 of a series of blogs in which we discuss how to deal with legacy code. How to keep it in a manageable state, and how to revive it if necessary. In the first part, we gave our vision on legacy software, consisting of respect for the value, understanding of the history and the present and a clear vision on the shortcomings of aged software. In this blog, we will discuss the characteristics of legacy code and their causes.
What do we come across?
Various aspects of legacy code degrade the code quality and deteriorate the code readability. This makes continued maintenance and development increasingly difficult. The following aspects we have often seen to occur:
- Entangled functionality: procedures perform multiple tasks that are intertwined throughout the code.
- Global variable scope and state: any variable can be modified from everywhere throughout the code, and the state of the variable can affect every operation.
- The Swiss army knife: the application is used as a multi-purpose tool, as it is being employed for multiple use modes or workflows. Some of those use modes may not even be relevant anymore, but they are still present throughout the code. The program flow is controlled by global control switches throughout the code. Alternatively, various locations present the developer with an intimidating list of complicated conditional branches for distinguishing between the different workflows.
- Insufficient testing facilities, limited testing coverage of the various program states and use modes, and/or inadequate testing methods.
- Low-quality technical documentation, no clear explanation of the background of the algorithms in the code and the underlying design choices.
- Self-made or obsolescent tooling for managing the code, compiling, building and deploying, for version control and issue tracking. Build environment requiring hidden environmental conditions or a complex manual process.
3. Causes of software aging
The typical downsides of legacy code are caused by two factors that are common in aging: evolution and decay:
- In principle, evolution of the software package is desirable because it expands the usefulness of the code and keeps it relevant for the current challenges. However, while the software evolves and matures, it is being deployed in ways that were not foreseen in its original design. The software outgrows its original application scope. This can cause a misfit between the original assumptions and constraints and today’s requirements. Software structures that were conceived for the original situation may be unfit for incorporating the new situation. Examples of evolution are:
- Growth of complexity: new algorithms, increased dimensionality and problem size, more and more use cases.
- Use of the application not only as a design support tool but also in an operational setting as a digital twin.
- A changing base of users and developers, in other roles, new generations, featuring external parties.
- Employment of the application on other platforms such as Linux/Windows, in a web/cloud-based setting, on an embedded system.
- Moving from a stand-alone application to a multi-client service.
Without a proper refactoring effort, the new situation is then ‘squeezed’ into the old format which gives rise to an inadequate organization of data and code. Over time, a seemingly workable situation easily develops into a maintenance nightmare.
- The deterioration of the code quality comes from a gradual buildup of inefficient code. This is also known as technical debt or postponed maintenance. Underlying causes of this deterioration in software quality are:
- The need for speed for critical operation or pressing timelines results in a quick fix or workaround that is never turned into a decently integrated solution.
- A lack of deep understanding of the code’s purpose by the developer results in sub-optimal code. This often results in unnecessary code duplication, encapsulation, and layering.
- A limited budget for basic code maintenance which is often caused by a project-driven development approach.
The last of this blog series about legacy code, we will address
- what approaches can be taken to improve the code sustainability, and
- our general strategy to make the legacy treasure shine and prosper again.
If you want to be notified when the final blogs in this series appears or if you want to get the full text as one, drop us an email at firstname.lastname@example.org.
Can we help you?
If you are dealing with a situation around legacy code, feel free to contact us. We can assist you with consultancy, project management and hands-on work. Contact us through email@example.com or +31(0)15 285 01 25 for an appointment with one of our experts.