Incremental software modernization minimizes risk, reduces costsStory
September 14, 2010
In practical terms, software modernization consists of the gradual process of replacing the bad with the better. And the choice to focus on software portability versus conditional compilation is integral to modernization.
Consider the efforts associated with modernizing a deployment platform. Suppose an application originally developed with the C++ language on Windows now needs integration into a modern Smartphone running a proprietary OS and an ARM processor. The porting activity needs to identify and replace all dependencies on the Microsoft Foundation classes. It also has to analyze and address all dependencies on the Microsoft compiler and the underlying thread scheduling model as implemented by Microsoft Windows. While some of these porting issues are identified by diagnostic message output from the phone vendor’s compilers and linkers, subtle differences between the code generation approaches of the Microsoft and Smartphone compilers can only be detected by extensive testing and/or careful review and analysis of the respective technologies. Similarly, differences between the Microsoft and Smartphone OSs’ treatments of thread scheduling queues, mutual exclusion locks, and priority inversion avoidance strategies must depend on extensive testing and/or careful review and analysis of the respective OSs and of the application source code and any available application design documents.
Note that the ability to build new applications by modular composition of independently developed reusable software components depends on the portability of those components. Thus, achieving software portability is critical to developing new systems and maintaining existing systems.
Conditional compilation adds complexity
With a typical C++ porting effort, the amount of code that must change to support a new platform is relatively small, typically less than 10 percent of the total code. Finding which 10 percent of lines has to change is one of the biggest hurdles of any porting effort. As various porting hurdles are identified and addressed, conscientious software engineers modernize the application by inserting conditionally compiled blocks of code and creating documentation to help clarify the additional effort that might be needed to port this code to yet another platform, such as Linux, INTEGRITY, or VxWorks. There is no guarantee, of course, that the port from Windows to the Smartphone identifies all problems that might arise with a subsequent port to yet another OS or processor. But the lessons learned with the first port provide valuable guidance for additional ports.
A conflicting objective of software modernization is to reduce the effort needed to correct bugs, address performance shortcomings, or add incremental new functionality as system requirements evolve. Applications made portable by inserting conditional compilation directives and documented lists of issues to be considered with each new port are difficult to evolve. If changes to the original application impact conditionally compiled code, then the changes must be propagated into all the conditionally compiled blocks of code that represent support for every relevant platform. Further, every incremental change must be tested with every combination of legal conditional compilation options. This adds significantly to the effort associated with common software maintenance activities.
Portable languages avoid conditional compilation
A popular alternative to using conditional compilation directives is to implement software in a more portable programming language. Java is often the preference, and many use the phrase “software modernization” to describe the process of migrating Ada, C, or C++ software into the Java language. Java, including certain real-time versions of Java, addresses portability issues within the Java runtime environment (the so-called virtual machine) itself, rather than requiring conditional compilation directives within the application. The Java language even offers special control structures for addressing multiprocessing issues, including syntax to identify mutually exclusive code regions and coherency between individual processor caches. By abstracting these portability considerations, the Java language offers tremendous cost savings in typical software maintenance activities. One development team reported a savings of 20-fold compared to the C language in a project that consisted of assembling independently developed off-the-shelf software components for deployment on a new embedded platform.
Rarely is it economically feasible to rewrite an entire legacy application into the Java language in a single monolithic effort. Today’s typical applications consist of hundreds of thousands or millions of lines of code; thus, it is much more common for legacy applications to be modernized in incremental steps. With each functionality addition, new features are implemented in Java and bolted onto the existing legacy system. If maintenance activities reveal that a specific aspect of the legacy application is difficult to port or evolve, then that part of the application is replaced with a more modern Java implementation.
Dr. Kelvin Nilsen is CTO for Java at Atego and a participating member of the Java JSR 282 and JSR 302 expert groups. He can be contacted at [email protected].