This article is a revised version. It was previously published at refactoring-legacy-code.net published.
What is the biggest challenge when dealing with legacy code?
I recently asked this question about legacy code on Twitter:
Now, Twitter is notoriously designed to be short on answers. However, since more than a dozen responses were received, I want to report here where developers see challenges in dealing with legacy code. The "survey" is far from representative. Nevertheless, I believe the responses point to the typical legacy code challenges.
If your personal challenge is not mentioned, I look forward to your comment!
Automated tests
The following answers relate to the topic Tests:
- Lack of test coverage
- Regression bugs
- That he does exactly what he did before.
- definitely not destroying the existing functionality
- No/hardly any tests
- Usually with the missing tests. I often think that it is a huge effort. It seems too unsafe without it.
- Apply missing tests for legacy code.
- Tests virtually impossible (technical, time)
Few integration tests
many unit tests
Automated tests is a challenge for many developers. I experience this time and again in my training courses. In particular Dependencies of the functional unit under test to other functional units make testing more difficult. Small, isolated and focused tests are therefore often not possible. In relation to the entire software project, the "ice cream cone" (see below) is created as a Antipattern.
The number of automated tests from the two categories Integration tests and Unit tests should actually be distributed as shown in the following pyramid. At the base many unit testswhich are used to check the details of the domain logic. On the surface Few integration testswhich ensure that the functional units tested in isolation work together as planned.
many integration tests
few unit tests
However, the situation is often reversed in legacy systems: Many integration tests, few unit tests.
This anti-pattern means that the tests are not very meaningful overall. If an error occurs due to a change to the code, several integration tests often fail. As there are hardly any unit tests, the few that do exist often remain green. This makes it clear that something has broken, but it is time-consuming to find the actual cause. With the recommended distribution of the number of tests, a single unit test would indicate exactly where the problem lies in the event of an error.
On the green meadow help recommendations such as, avoid dependencies, implement test-first, Separate aspectsusually further. In the Brownfieldalso known as legacy code, the references to principles are just as correct, only the implementation is much more difficult. I will refer to refactoring-legacy-code.net will deal with the topic in the near future and Tips as in Legacy Code Automated tests supplemented can be used.
Understanding the code and building a model
Teams still separate the phases Draft and Implementation too little. After the Analysis of the requirements is coded straight away instead of first designing a solution to the problem. This results in software systems in which the model, a more abstract form of the solution, only exists in the code. Extracting the original ideas from the code is like the work of an archaeologist. The answers to the question on Twitter, where the biggest challenge lies with legacy code:
- Target functionality unknown
- Understanding the impl. idea, restoring the impl. thought model, assigning methods to the correct levels of abstraction
- Finding someone who understands the problem domain with the edge cases you have developed over the years.
- Downward comp.
Due to the lack of a design, only the code remains as a source of information to derive what the solution to the problem actually looks like. If the original requirements are not documented anywhere, only the code remains for this part. This makes it difficult to introduce new requirements into the code base, as it is always necessary to find out how the solution actually works. Subsequently, an addition has to be made to an opaque solution.
Every time you deal with the code, read and analyze it, it in the debugger you gain important insights into the code. How do you secure these findings? Laborious execute the code step by stepto find out how a particular feature is implemented. Once you have researched this and created the Bug fixed you are probably glad that you can now turn your attention to other tasks. The laboriously acquired knowledge via a small section of the code base are lostas they only exist in your head. Remedy can be Refactorings create. And here I don't mean the so-called complex refactoringsbut the simple refactoringswhich you can do completely with a refactoring tool like Visual Studio or JetBrains ReSharper. I have some blog posts written.
Organizational challenges
One answer relates to challenges within the organization of a software development project:
- Convince the person(s) responsible of the necessity.
The Product Owner expects that we as developers changeable code write. He quite rightly assumes that we according to the rules of the art (this could be, for example, the values, principles and practices of the Clean Code Developer initiative). For the client, changeability means Investment protection is a good example. Someone spends a lot of money and wants a code base that can be changed and expanded in the long term. In order to create changeability Principles are complied with:
- Aspects must be clear separate become
- Dependencies must be considered as a separate aspect and isolated become
If these two principles are observed, a module structure is created that is easy to test and understand. This makes the Changeability of the software. The product owner can then fulfill new feature requests for years to come without the associated effort suddenly increasing dramatically.
However, the reality is that the changeability of the code base is not a given. This should actually be restored through regular additional work. If this effort is repeatedly postponed, the problem becomes bigger and bigger. The following applies here, the scout rule and to constantly improve the code instead of just churning out features.
Doing without convertibility means neglecting investment protection. As with a loan, this results in the piling up of a Guilt that needs to be cleared. If this is not done, new features, changes and bug fixes become increasingly expensive.
Psychological hurdles
- "Overcoming" 😉
- to start
- Frustration
In many cases, developers have long since realized that the code base needs to be cleaned up. If they are not given time to do this, or if the developers do not manage to take this time, frustration arises. Acting against better judgment does not feel good. It is often a lack of knowledge that prevents the situation from improving quickly. Anyone who has not learned to write tests "on a greenfield site" will certainly not be able to do so in the "muddy field" of legacy code. The point here is not to find someone to blame, but to recognize the situation and work out where the problems lie through joint reflection.
Technical challenges
- Reflection-related sources of error
- Migration
There are technical challenges in some code bases more than in others. Software that controls machines usually has Time-critical areaswhere high performance is required. The readability of the code may have to take second place. Or perhaps the software system is very flexible and customizable by the customer, in which case there may be many places where Reflection are used. As a rule, these special features, which in essence constitute the unique selling point of the software, are not implemented in isolation and separately from other features, but are wildly distributed across the code base. This creates technical challenges that make redevelopment time-consuming.
Conclusion
Refactoring legacy code to clean code is a major challenge for many teams. In the long term, developers have no choice but to face up to this challenge. If this does not happen, the company may ultimately go under. The adaptability of the software must be maintained or established. This represents investment protection for the client.