When dealing with legacy software, it is important to understand what can be done with the software. Legacy software often consists of software that has been left to run for a long time without too many inherent changes, the “don’t fix what isn’t broken” strategy. As compilers in languages such as Fortran are backwards compatible, it is often possible to compile and run these old programs. Yet at some point it becomes necessary to deal with the old code. So how to is this achieved? Is the code to be re-engineered or refactored?
Re-engineering means making fundamental changes to the code. Here are three core methods of reengineering:
- Porting – programs are modified to work on a new hardware platform.
- Translation – programs are translated from legacy language to contemporary one.
- Migration – programs are converted from a legacy language to a newer dialect.
In essence this is no different to the work that would be done to an old building. It might be moved in its entirety to a new location, it might be completely rebuilt, or it might be made new, incorporating only the facade of the original building.
Refactoring on the other hand, leaves things more intact. Refactoring involves changing a piece of software in such a manner that the external behaviour of the code remains unchanged, but it’s internal structure and architecture are enhanced. This is akin to modernizing the plumbing and electrical system of an old building. It still functions and looks the same way, but the infrastructure has been improved. Refactoring takes control of decaying code, improving the readability and maintainability of existing code. Refactoring is done to fix short-cuts, eliminate duplication and dead code, and to make the design and logic clear. To make better and clearer use of the programming language. It does not necessarily imply that the code is migrated to a new dialect of the language. Refactoring is often a part of the life-cycle of software, and may not be targeted specifically at legacy code.
Reengineering and refactoring look very similar, and there are likely areas, such as migration, where they overlap. In reality the process of dealing with legacy code often begins with refactoring, and progresses to reengineering. In situations where the code base is too complex, it might be worthwhile trying to improve efficiency first by improving algorithms. If this doesn’t work however, reengineering might be in the cards.
Here’s an example of the possibilities when dealing with a legacy, say Fortran IV, piece of code. The refactoring may involve processes such as:
- eliminating equivalence statements: specifies that two or more variables or arrays in a program unit share the same memory.
- elimination of common blocks: shared, common storage for Fortran programs prior to F90.
- removing dead code: code that is never accessed.
Reengineering on the other hand could involve a port to a new platform, a translation to C, or a migration to Fortran 95.