Best practices in code transformation for modernization
by John Browne, on Feb 1, 2017 3:05:22 PM
Today for your listening and dining pleasure, we want to shed a little light on the risks and rewards of code transformation as a path to legacy application modernization. As has been widely reported in these pages, legacy code is a ticking time bomb and organizations have about four reasonable ways to deal with them:
- Do nothing (aka kicking the can down the road). Given the half-life of CTOs these days, this might be a politically-savvy strategy but does squat to solve the root problem.
- Replace with off the shelf software: chances are that Microsoft Access kludge Harry in Human Resources wrote back in '04 to track the company bowling league scores can be tossed and something more--shall we say modern?--used instead. If I have to give you a list of candidates then you might be reading the wrong blog.
- Scrap and rewrite from scratch: the most popular choice after can kicking (see first bullet point). I've never--and I mean never--met the developer yet who didn't want to throw out someone else's old code and start over. "The code is crap," they always say, forgetting momentarily Browne's Rule ("All code is s__t") as though they've seen actual legacy code that didn't resemble skin eruptions on a 15-year-old's face. Fat chance.
- Transform the code using tools. And that's the subject of this post.
Approaches to automated code transformation abound and to pursue that avenue is to recognize the perils therein. Frankly when I first heard about Mobilize.Net, my instinctual response was "yeah, people have been talking about that for years but it never works."
Is that the case?
Syntactic vs semantic transformation
Code transformation can be based on syntactic or semantic algorithms. My experience prior to Mobilize.Net was with syntactic transformations. Those kind of transformation tools do a sort of super GREP to convert from one language to another. Some rely on runtimes to map functionality or libs/classes to the new language or platform.
Syntactic transformation is like cramming all the dirty dishes in the oven before a visitor arrives. Things might look better, but you still have a big job ahead of you and it's going to start to smell pretty soon.
Semantic transformation, on the other hand, is like doing the dishes the way my Dad wanted them done (which included never using detergent on his precious cast iron cookware and mopping the floor after all the dishes were put away). It's a lot more work to build these kinds of tools, but they result in much better code. According to Gartner, semantic transformation "involves the replication of the application function...in a new language and a new runtime environment."* Compared to syntactic transformation, semantic approaches should create "more maintainable and expandable code" as well as several other improvements:
- Elimination or reduction in dead code in original system
- Elimination of programs with no entry path (more dead code)
- Elimination of redundant or "copy and paste" code to a single instance
- Refactoring one- or two-tier architectures into patterns like MVC or MVVM.
Best practices in vendor selection
Let's further turn to Gartner to get some guidance on selecting vendors for code transformation. Their recommendations include the following:
Define coding standards up front
Automated transformation can include building in implementation of standards for naming, coding, patterns, and so forth, depending on the vendor's capabilities. One example that a customer requested, for instance, was to add a logging step to every exception that was caught. Using automation tools this becomes relatively trivial. But those requests should be agreed on before the start of work. Don't assume the vendor can read your mind about using or not using Hungarian notation.
Get a proof of concept
To completely understand the coverage and quality of the resulting post-transformation code, start with a proof of concept (POC). Using your actual application code, get the vendor to migrate some small chunk, perhaps a couple of screens and the associated code for the objects on that screen. Then any disparities between what you expect and what they will deliver will be apparent immediately on review.
Define functional equivalence
A migration project is unique in software development in that it has a perfect specification: the existing legacy application. In short, the transformed (modernized) application should be functionally equivalent to the original. The test of this is that the new app should be able to pass any test the original app can pass. Now whether this includes any bugs in the original app is open to discussion--just be careful that you don't assume the original code didn't rely on those bugs being there. That's certainly not unheard of.
Understand the new environment
Part of modernization can include a complete lift and shift from one deployment/operating environment to another. For example, customers using our WebMAP product move their apps from the desktop to the web. That moves the business logic from the desktop to a server environment. Deployment no longer consists of burning copies of bits that have been proven; instead you have to load a new, correct version of the software onto the server while the existing version is running. It's like rewiring the airplane while it's in the air. Having a strong DevOps team can improve your chances of success; talk to your vendor about assistance in moving to the new paradigm before you go solo.
Understand vendor deliverables and limitations
How often do you revise the legacy application? This question goes to the heart of the modernization methodology. Code that is rarely or never touched can be packaged up with little regard to the maintainability of the transformed application. It may rely on a proprietary runtime that emulates unique aspects of the source language--without the runtime the application cannot run correctly. Code that is frequently revised--or that you anticipate needing to revise in future--needs to be transformed into readable code with no artifacts from the original language (although some helper classes to smooth over the learning curve can be useful). All transformed code should be native and not rely on third-party runtimes. As recent events have demonstrated, transformed applications that require custom runtime solutions can be orphaned if the vendor drops support for those runtimes.
* Vecchio, Dale The Risks of Code Transformation as a Modernization Option Feb. 2015.