Technical Debt Always Comes Due Red Pill or Blue Pill? Your Legacy System Won't Wait for You to Decide

By Dean L. Reyburn

In December, 2022, Southwest Airlines provided a $825 million lesson in what happens when you don't maintain critical legacy systems. Their crew scheduling software—built in the 1990s and starved of investment for decades—collapsed under a winter storm that other airlines handled routinely. The system couldn't match pilots and flight attendants to planes, forcing dispatchers to coordinate manually by phone. Southwest canceled 16,900 flights in ten days, stranded over 2 million passengers, and became a national punchline.

Does your business / government agency / organization depend on software that was written decades ago and never updated? Maybe a genius employee set up a system that works so well that nobody wants to touch it. That’s great, but with the speed technology changes, sooner or later something will cause that system to need updating. For instance, that old hardware will wear out, or the operating system will fail, or the software will simply become incompatible with modern systems or the internet. When that happens, your organization will be in dire straits and desperate to fix that older system.

Many organizations go years running on a system that was designed so long ago, few if anyone remember who built it, or how to fix it. It’s even possible the source code to the software is lost.

I’ve written about the Southwest story before, and some readers may have even experienced this disaster first hand.

The cruel irony: their pilots' union had warned a month earlier that they were "one thunderstorm away from a complete meltdown." The flight attendants' union had prioritized IT upgrades over pay raises. Management knew. They just didn't act. Whatever Southwest would have spent to modernize that scheduling system—$10 million? $50 million?—it would have been a mere rounding error compared to the $825 million they lost in a single week, plus the incalculable damage to their reputation.

Legacy systems don't care about your budget constraints. They fail on their own schedule, usually at the worst possible moment. The question isn't whether you can afford to modernize—it's whether you can afford not to.

If your organization depends on software written a long time ago, and its mission critical, do you have an engineer responsible for maintaining that system? If so, are your managers listening to his/her pleas for more funding?

My contention is that there is a certain “technical debt” to pay for using technology. That debt has to be paid every year, or at least regularly, otherwise your organization can end up in a Southwest Airlines type situation.

So your managers say “well everything works, why should we shovel money into a system that’s working?”. My answer is, you will pay a small amount now, or a large amount later, your choice. The technology gods will have their due in either case.

This “technical debt” isn’t like a bank debt. It’s a debt that builds up every year if you don’t pay it down. And there are a number of ways to pay it down.

Technical debt pay down methods. You *will* pay the debt with one of these methods, there’s no choice or doubt in the matter.

1.     A little at a time, every year, updating and maintaining the software that’s mission critical for your business.

2.     Once every few years there’s a technology change and your system starts giving warning signs. This isn’t as optimal as method 1, but better than letting the system go without maintenance long term.

3.     Crash and burn. This is the Southwest scenario. You’ll pay 10 or maybe 100 times as much as you would have to maintain the tech.  Fixing on an emergency basis is always more expensive, and sometimes an emergency fix may not even be possible.

4.     Simply go out of business (product/service, division, or organization). This is certainly a way to pay the technical debt. Nobody owes it anymore. Your business or organization will have lost value for the shareholders or citizens.

Does any of this sound familiar?

· The system that "just works" so nobody dares touch it

·       The original developer retired five years ago—or twenty

·       Documentation that exists only in someone's head

·       Source code on a backup tape nobody's tested

·       A language or platform that hasn't been taught in universities for a decade

The specific technology almost doesn't matter. It could be COBOL on an IBM mainframe, Visual Basic 6 running a manufacturing line, a Windows Mobile, iOS or Android app, a Perl script that generates all your invoices, or a FileMaker database that somehow became mission-critical. The pattern is identical.

Banks, manufacturers, government agencies—organizations of every size depend on software written 30 to 50+ years ago. Many still run on mainframes, executing millions of transactions daily in obsolete languages that haven't been taught in decades. So, who will maintain those systems? Within the next decade or two, all the COBOL engineers will be retired or passed on to the great coding jobs in the sky. 

The time to fix these systems is now or soon. Why? The stars are aligning with the emergence of real AI (LLM) tools to write and port software, and the optimal window is closing. The AIs still need humans who understand obsolete programming languages and the intent of the software, and who can manage the conversion process. Those humans are disappearing fast—just as fast as AI appeared.

What does modernization actually look like?

The approach is systematic: assess scope, isolate testable modules, port incrementally, verify ruthlessly. We port to C/C++—not Java, not Python—because C compiles everywhere, depends on no corporation, will exist in 50 years, and does exactly what you tell it. For audit-proof financial code, that transparency matters.

Let's make this concrete with COBOL—the canonical example, with billions of lines still running the world's financial infrastructure. Consider a 50,000-line program that runs a nightly batch process...

An example project:

1.     Assess the number of lines of code and modules.

2.     Find a small portion of the code that can be separated out, and tested directly, outside of the larger codebase.

3.     Run a pilot program where that module is ported to a modern, widely used language such as C or C++.

4.     Verify penny-accurate equivalence between old and new before proceeding to the next module.

Here's what step 3 looks like in practice.

Consider a COBOL program, say 50k lines that runs a nightly batch process that calculates interest on savings accounts—handling account lookups, tiered rate calculations, and transaction logging. These systems often date to the 1970s-80s and run on IBM mainframes.

Some example COBOL code:

01  ACCOUNT-RECORD.

           05  ACCT-BALANCE      PIC 9(9)V99.

           05  INTEREST-RATE     PIC 9V9(4).

           05  INTEREST-AMT      PIC 9(7)V99.

       MOVE 12345.67 TO ACCT-BALANCE.

       MOVE 0.0425 TO INTEREST-RATE.

       COMPUTE INTEREST-AMT ROUNDED = ACCT-BALANCE * INTEREST-RATE / 365.

       ADD INTEREST-AMT TO ACCT-BALANCE ROUNDED.

 An example of the same code ported to C:

The optimal porting method is to keep closely matched variable/function names.

Line for line, enter the COBOL as a comment:

#include <stdint.h> 

/* 01  ACCOUNT-RECORD. */

struct ACCOUNT_RECORD {

    /* 05  ACCT-BALANCE      PIC 9(9)V99.  */

    int64_t ACCT_BALANCE;   /* scaled by 100 (cents) */

    /* 05  INTEREST-RATE     PIC 9V9(4).   */

    int32_t INTEREST_RATE;  /* scaled by 10000 */

    /* 05  INTEREST-AMT      PIC 9(7)V99.  */

    int64_t INTEREST_AMT;   /* scaled by 100 (cents) */

};

// Usage example:

struct ACCOUNT_RECORD ACCOUNT_RECORD;

ACCOUNT_RECORD.ACCT_BALANCE = 1234567;   /* $12,345.67 */

ACCOUNT_RECORD.INTEREST_RATE = 425;     /* 0.0425 = 4.25% */

/* COMPUTE INTEREST-AMT ROUNDED = ACCT-BALANCE * INTEREST-RATE / 365. */

/* ADD INTEREST-AMT TO ACCT-BALANCE ROUNDED. */

COMPUTE_INTEREST(&ACCOUNT_RECORD);

/* Result: INTEREST_AMT and ACCT_BALANCE updated, penny-accurate */

// Helper functions from Reyburn Engineering's cobol2c porting library:

 static int64_t ROUNDED_DIV(int64_t numer, int64_t denom);

void COMPUTE_INTEREST(struct ACCOUNT_RECORD *rec);

In the example above, we’ve kept the variable and function names as close as possible to the original COBOL to make debugging and understanding the code as straightforward as possible.

 For larger migrations, C++ can encapsulate COBOL’s domain-specific features—condition names, scaled decimals, record structures—into reusable classes that preserve the original code’s readability.“​​​​​​​​​​​​​

Portability advantage. The ported C compiles on any modern computer with a C/C++ compiler. Which is all of them. The original COBOL likely runs only on aging IBM iron or expensive mainframe emulators.

Verification is tractable. Because variable names and structure match, you can run both programs against identical test datasets and diff the outputs programmatically, even train an AI to do comparisons, or thousands of comparisons. Discrepancies jump out immediately. This kind of disciplined approach gives results which can be directly tested and relied on.

Our ports don't just work. They're audit-proof.

COBOL's business-oriented features—scaled decimals, condition names, record structures—aren't magic. They're library functionality. C/C++ can reproduce them with penny-perfect accuracy; the proof is in the test suite.

Rewriting a legacy language program is just a matter of understanding the original language and its idioms, and translating those quirks and abilities into a C/C++ library which exactly duplicates the COBOL results.

 C/C++ serves as a universal target language for legacy migrations—whether business-oriented COBOL, RPG, VB6, etc.—because these languages' specialized features are ultimately library functionality, not fundamental capabilities that C lacks.

A 50,000-line port is a serious undertaking—but it's a bounded problem with a defined endpoint, unlike the unbounded risk of doing nothing.

Testing: For mission-critical applications such as banks, airlines, defense,  etc… there are a number of ways to test that the new system has exactly the same output for given input:

1.        Black Box testing. With this method the tester has hundreds, or better yet thousands of example cases of input and output. Feed these into the newly ported system and fix the errors until every output matches the old system’s output.

2.        Mirror Testing: Run the newly ported system (after as much Black Box testing as possible), in a real situation, with a computer feeding both the old and new systems the same live data, and software at the output comparing the results. Run for hours, days, weeks, months, or year, whatever is needed to match the level of comfort of the stakeholders. The old system is live, the new system is just in “demo” mode.

3.        Reverse Mirror Testing: Install the newly ported system, but continue the Mirror Test the two systems, with the same monitoring of output to confirm matching. At this point, 100% matching should be guaranteed, but stakeholders often trust the old system, so this state is really for comfort and confirmation.

When stakeholders are satisfied that the new system is perfect, retire the old system.

With the advent of modern AI coding tools, projects which were practically impossible, or simply impractical are now not only possible but economical. We use the latest AI assistants such as Anthropic’s Claude Opus to help port and test new systems.

The window for orderly modernization is open now. It won't stay open forever. The red pill is a phone call. The blue pill is waiting for your own Southwest moment.

Reyburn Engineering, Inc. can handle the full spectrum of legacy infrastructure, not just banking. We’ve ported code for 30 years across 5 platforms.

reyburnengineering.com 

Legacy Application Modernization, Weidman, Michigan 

Dean Reyburn, CTO, co-founder of Reyburn Engineering, Inc., holds four patents, and is creator of CyberTuner, a professional piano tuning application.  It has survived: Mac Classic → Windows → Windows Mobile → Mac OS X → iOS—plus multiple major transitions within those platforms. Five operating systems. Thirty years.  

Noah Reyburn, EETBS/CS, co-founder, has 15 years of electrical, software and hardware computer engineering experience. Noah taught at Ferris State University for three years, is the named inventor on a patent, and has worked on cloud license servers and embedded systems.