|Perl: the Markov chain saw|
A Porting Horror Storyby stephen (Priest)
|on Apr 09, 2002 at 22:10 UTC||Need Help??|
Once upon a time there was a small company that had a great deal of legacy code written in Perl. The new engineering manager and the new CTO wanted to move to a Java-based solution. They had several reasons for doing this:
They hired several Java programmers (none of whom knew Perl) and began to rewrite the code from the original specs. They estimated that it would take them four months. However, the specs were not detailed enough, and the resulting product was rejected by quality assurance, since it would not meet existing customer needs. All told, it took a year to complete the rewrite, during which time features needed to be added to the legacy code to support customer needs.
This experience changed my opinion on porting and rewriting. At the onset of working on this project, I believed that after a certain point code needs to be rewritten from scratch. I believed that if a design is flawed, there's no way to patch it to make it work.
My new rule is "first refactor, then port." I base this rule on the fact that no specification is detailed enough to specify all of the operations of a piece of software-- and if it is, it'll be outdated once the program enters maintenance mode. To port software from one language to another, it's necessary to make the code comprehensible in the existing language through refactoring. If the design of the original software is bad, you can use refactoring to fix the original design. Once the refactoring is completed, you can (and should) reevaluate the necessity of porting.
Let me go over a few of my problems with the reasons for making the decision to port in the first place:
Neither the CTO nor the engineering manager knew Perl.
This disturbs me a great deal in retrospect. Certainly implementation is not the job of the CTO. Nor should it necessarily be the job of the engineering manager. Even if a company were so resource-strapped as to be unable to hire Perl programmers, it takes far less time to learn a new language than it takes to rewrite a complex program from scratch in a different language without reference to the original code.
They wanted to impress their investors with the "Java" buzzword.
I think Time has proven that investors are more impressed with the "profit" keyword.
They felt the code was so horribly-written that it needed a ground-up rewrite before they could add features.
This is the objection with the most validity, but even it rings hollow. Refactoring techniques have become more and more widely accepted. Plus, refactoring has the virtue of keeping the code running while one improves it and adds a battery of automated self-tests. Refactoring the existing solution concentrates the effort onto the current code, rather than splitting it between maintaining the current code and writing the new code. This lack of concentration was a major problem at our company, where a skeleton crew had to maintain the existing code while the bulk of Engineering staff worked on the new Java code.
They believed that Java was more 'scalable' than Perl.
One hears the 'scalable' buzzword more and more often these days (well, these days I more frequently hear 'downsize' and 'pay cut', but hey). 'Scalability' is one of Java's perceived attributes. However, when one tries to get a meaning for 'scalability', one learns that it means many different things to many people. My original understanding of 'scalability' was that scalable software did not suffer from hardware bottlenecks-- that as demand increased, that one could purchase additional hardware to handle the stress, and that the software could benefit from this. Such a characteristic is a design feature, though, not a language feature-- one could write such software equally well in Java and Perl.
Another meaning that I hear for 'scalable' is simple efficiency-- that Java runs more quickly than Perl on the same hardware. However, even if that's true, what sort of logic leads to porting to Java for efficiency reasons? If you're going to port for efficiency, port to C. Better yet, refactor the Perl code, then take the most frequently executed module in that code and port *it* to C, then link it back into the Perl code as an XS module. That way you get a much faster gain for far less effort. (Porting a Perl module to C is definitely not a trivial undertaking, and may not gain much efficiency. But a possible failure here is much less risky than the nearly guaranteed failure of a large-scale porting project.)
The small company that I describe eventually managed to complete their porting project. It finished more than a year behind schedule. They had worked frantically for more than a year just trying to get the Java code to operate to the Perl code's spec-- while at the same time customer demand was forcing changes in the running Perl code. At the same time, the speed at which they were trying to port this code forced them to cut corners. Their Java code wound up just as difficult to understand as the original Perl code.
The lesson I have taken from this escapade is that it's rarely a good idea to do something twice-- even in a different language. I believe that the lessons here would apply equally well if the arrow pointed the other way, from Java to Perl. It even applies for many ground-up rewrite projects that remain in the same language.
Finally, there are many good reasons for porting. If your software simply cannot run on its intended platform, you don't have a choice. However, even in that case, you will do well to refactor your existing software as much as possible before porting.