It's Alive! The Frankenapp Runs Amok!

Talking Points

  • Frankenapps are legacy apps that are so heavily customized they’ve become unwieldy and require frequent maintenance and support.
  • Almost everyone agrees the best way to keep a good application from going bad is to periodically retool it.
  • The older an application is, the more programmers must become agile to support it.

Frankenapplications. You all have them. They’re the things that make your pagers go beep in the night. They disturb your sleep with nightmarish scenes peopled with belligerent users and irate, pointy-headed managers. Franken-apps are legacy applications that are so heavily customized that they’ve become unwieldy and require frequent maintenance and support.

In many cases, Frankenapps are neglected, not made. They’re the culmination of years of management indifference, departmental buck-passing, and company-wide cost-cutting measures—sometimes it’s all three.

Theodore Woo, a programmer with a global technology services provider, knows a thing or two about Frankenapps. He’s got one, in particular, which frequently disrupts his sleep. And like a true Frankenapp of questionable parentage, it does so with malicious irony. “We do not actually own the systems this application is running on. The customer does. So we do not have root access [to these systems]. The problem is that someone with root access needs to [log on to the system] to reset the application,” he explains.

At 3 A.M., Woo acknowledges, anyone with any common sense, root access or no, is home and asleep, which is where Woo would be if his Frankenapp didn’t automatically generate a trouble ticket in his employer’s help-desk management system.

Woo cannot disclose the nature of the application, which is written in Forte, a language that isn’t likely to ever be resuscitated. Because the application has been modified with new features or customer requirements on countless occasions, it totters on the brink of availability, he says. In fact, the client company for which Woo maintains it now realizes that something must be done, too.

“There is a project out there—it has not been approved—to stabilize this application,” Woo says. “Something similar was approved in 2001 to stabilize another application, but after we did the work, we shut it down, because nobody wanted to pay for it,” he reveals.

When to rule out a rewrite
Woo doesn’t think the same fate will befall his own Frankenapp, which he says is too critical to too many people to throw dirt over.

At the same time, however, Woo is far from confident his Frankenapp will ever be stabilized. “Everybody realizes the best thing would be to rewrite [the app] from scratch, but the number that was put forward just to attempt to convert this application into a more modern programming language was something like 9,000 or 10,000 developer hours. Five people working for a year could do it. Nobody’s going to approve that,” he says.

In any case, programming experts typically discourage lock, stock, and smoking GCC compiler rewrites, unless they’re absolutely necessary. “I generally lean away from [rewriting], unless it’s a wholesale architectural change, where it’s often a necessity,” says Michael Feathers, a consultant with Object Mentor and author of Working Effectively With Legacy Code. “I apply a selective rewrite, where you say, ‘Here’s some small portion of functionality we’re interested in making cleaner, and writing tests for that and rewriting the original portion.’”

Why the bias against rewriting? For starters, Feathers says, it’s risky: You have no way of knowing just what impact a rewrite will have. It’s also anathema to bottom line-focused managers, like those in Woo’s organization.

“As a general rule, managers don’t really care to rewrite all that much because of the costs,” Feathers confirms. There was more enthusiasm for rewriting during the late 1990s, until a spate of failed experiments soured management on the approach, he adds. “There was a period of time when people viewed software very competitively. So, when they saw their competitors rewriting, they would basically throw money at similar efforts.

Tony Nassar, a programming consultant with the services arm of a prominent database vendor, agrees. Nassar—who says he turned down better job offers so he could work in an environment where he wouldn’t have to deal with runaway Frankenapps—says he views rewriting as a last, almost hopeless, resort.

“I do not rewrite code,” he asserts. “It’s far too risky. I don’t want to have to guarantee code I’m writing will work in the future. I want everything I write to work now.”

Of course, almost no one is willing to rule out rewriting altogether. Take Peter Scott, president of programming consultancy Pacific Systems Design Technology and author of Perl Medic: Transforming Legacy Code. “I would want to figure out the cost and benefit of doing it each way,” Scott explains. “Certainly some of the factors that can make me lean toward rewriting are the age of the application, whether the people who wrote it are still around, how much the requirements have shifted, and how much the environment operating it has changed.”

But even if all of these factors scream for a rewrite, Scott acknowledges, it’s often hard to fire that particular puck past the corporate accounting goalies.

Test drive early and often
To really get your Frankenapps under control, you might have to change the way you develop your software. A Frankenapp is a Frankenapp for a reason: Maybe it wasn’t really what the business customer was looking for in the first place, even though it satisfied all of the requirements enumerated in the contract; perhaps it was “improved” or “enhanced” whenever a customer, line of business rep or exec requested a new feature or function; or maybe it was written in a language, or using methods, that are onerously difficult to maintain.

There’s one constant in all of these scenarios, of course: The software development methodology isn’t getting the job done. And when this happens, you need to fix it, or, at the very least, tweak it.

Feathers, for example, champions a test-driven approach for tackling most, if not all, legacy code problems. For starters, he says, frequent testing lets you quickly assess the impact of the changes you’ve made to an application. And if you couple frequent testing with regular feedback from customers or line-of-business reps, you can ensure your finished application addresses the customer’s requirements. “What they should do is get tests in place around the areas where they’re going to be making their changes, and use them to verify they aren’t changing things in unexpected ways, and then go ahead and make the changes,” he argues.

If it sounds like agile and smells like agile, chances are, it is agile. Test-driven development is a core feature of most agile methods, after all, and Feather’s Rx for Frankenapps amounts to nothing less than test-driven refactoring. But Feathers—who consults almost entirely with organizations that are trying to revive many-headed Frankenapps—says the agile folks are right on this one. The more legacy a legacy application, the more agile programmers must become to effectively support it. “I think in a sense you’re going to come to be agile no matter what you do, if you have a long-lived app,” he confirms. (See sidebar “It takes agility to mash monster apps.”)

That’s the view adopted by veteran programmer Nassar, who uses a test-driven approach to mitigate his own Frankenapplication woes.

In this respect, he confirms, he often gets as much resistance from other programmers, who dislike the idea of changing the way they code their software, as he does from business managers. “I can’t usually get the team that’s already in place to buy into my methodology, but I find that it guides me in my efforts to find the least intrusive solution,” Nassar says, noting that Feathers’ book is an excellent companion in this regard. “I often have to retrofit tests to existing code that I’m not authorized to change, but if tests fail, then I can often persuade others to fix that code, which is a nice bonus.”

Though he’s not an agile practitioner by trade, PSDT’s Scott also emphasizes the importance of frequent testing. But just as important, says Scott, is to make sure to use a component-based architecture when you first build the application. That way, you’re not locked in to a monolithic application structure, and can swap in components where it makes sense to do so.

“In any language, they should design with the expectation that it’s going to need substantial refactoring within a couple of years or less, so design with a component-based architecture, or whatever that translates into, so as far as possible they can do a piece-wise upgrade,” he says.

Like Feathers, Scott believes that practitioners of traditional waterfall project management have their work cut out for them in the refactoring arena. “It’s far more necessary [to use a component architecture] in the waterfall model than anywhere else,” he stresses. “Because there is no process on earth where the requirements don’t change, and if you’re in a waterfall process, they probably change by the time you get to implementation. So you pretty much need to start refactoring as soon as you finish.”

Elsewhere, says Scott, programmers should always hew to a best practice that’s often overlooked during the original design process. “Simplify as much as possible. People cut corners all of the time during software development; they skip brain work because they think, ‘It’s a little thing, it’s not going to add much,’ but you know thousands of those little things make a big difference,” he points out. “My legacy application problems are drowning in thousands of things where someone said, ‘It’s too hard to automate that, let an operator handle that,’” he concludes.

Finally, says Losse Koskela, a programmer with the Finnish division of a U.S.-based management consultancy and global outsourcing giant, there’s no substitute for what he calls “evolutionary” refactoring. “An evolutionary design done right is about the best service you can do for a system’s maintenance costs over its lifetime,” he asserts. “When I say ‘done right,’ I mean that the design really evolves and doesn’t just get dragged along. Evolutionary design is certainly more work than an up-front design. That’s the price you have to pay for a good design and lowered maintenance costs.”

Factoring in refactoring
In an ideal world, organizations would not treat software development as a one-and-done-type deal. Instead, line-of-business managers and C-level executives would recognize that successful software projects have to make assumptions about an application’s lifecycle and that these assumptions must include provisions for periodic, test-driven refactoring.

Like Voltaire’s Candide, few code jockeys would say we live in an ideal world. And fewer still believe that such a world even exists.

“My best technical solution for [dealing with] this problem is to use some form of test-first development and a disciplined uncompromising attention to eliminating code duplication,” says Bill Pyritz, a programming veteran with a large manufacturer of networking and telecommunications solutions. “But this being a technical solution is unrelated to the real problem. If management does not see it as a problem, then no matter how good and effective the technical solutions are, they will never be implemented and we will carry on building our Frankenapplications. My guess is that that will be the case.”

Nevertheless, programmers who’ve successfully fused solid “evolutionary” design principles with test-driven refactoring report success in defusing Frankenapplications ready to terrorize the unsuspecting.

“It’s simply amazing how fast you can make progress with disciplined refactoring and test-driven development, even on systems that have been in production for several years already,” Koskela concludes. (See sidebar “The Dilbert dilemma.”)


Sidebar: It takes agility to mash monster apps
Sidebar: The Dilbert dilemma