One of the specialties of my consulting company, Northern HCI Solutions, is to take old software and modernize it. Often companies have programs that work perfectly well, but because their code is aging, it’s hard to find people to maintain those systems.
One of our most recent projects involved modernizing a Delphi app written in the late 1990’s. This app is an amazing piece of kit. It runs scientific simulations on a precise timescale. Our client wanted to keep the functionality they had and present it to users as a web app.
We took this existing code and essentially recompiled it into a modern .NET Standard/C# library. Thanks to good architecture by the original programmer, it was fairly easy to chisel out the Delphi-specific code (e.g. DBTables) and leave just the core engine.
Now that we have the code in a modern language and a suite of regression tests to validate its correctness, our client can add new features. They’ll also benefit from modern language features too.
In this case, I was curious to see what kinds of performance boosts we could achieve using only language and library features. Could we boost the performance without touching the core engine code?
As I reviewed our team’s code, I noticed something about the core engine. Each simulation in this engine is made up of sub-simulations, sometimes as many as 70. Each simulation is run between a 0.1 – 1.0 hour time scale for as much as one year. That’s potentially 6,132,000 data points!
In the old software, this sample case took around 1m 54s to complete.
Each sub-simulation is independent. All we had to do was make sure when we returned the final collection of results that we kept one list synchronized. This meant we could potentially replace the for() loop with a Parallel.ForEach and achieve the same result.
Aside: List<>.Add() is NOT thread-safe in C#. I’ve been bitten by not locking collections by encountering weird null-reference exceptions in production. Let that be a lesson.
That’s what we tried. The results?
Old Library: 1 minute, 54 seconds
New Library, for-loop: 44 seconds
New Library, Parallel.ForEach: 7.7 seconds. (14x)
Whoa. A 14x speed-up over the old library. Plus regression tests confirm that the results are exactly the same. We didn’t have to modify the core at all to get this performance boost. We’re just using tools that are available because we’re now using modern tools and modern languages.
That’s the potential of investing in modernizing your old apps. Will every app see a 14x performance boost? Probably not. But, we got a 2.6x performance boost just by modernizing the app. With a small tweak we increased that gain to 14x.
How would your business be transformed if you could reduce the time it took to run something by half? What about if you could hire modern developers instead of expensive specialty programmers?
A quick search on indeed reveals that depending on your level of expertise, you could easily walk into a $75,000/year gig doing COBOL programming. I’ll bet you could negotiate that higher. Unfortunately these legacy systems are only going to get more expensive to maintain. It’s basic supply and demand. Companies demand coders who know these older languages. The supply of those coders is decreasing.
Modernizing your old apps lets you hire modern developers, keep your software maintainable, and potentially boost productivity for your users. Why hold your business back because of unmaintainable software?
Shameless plug: we modernize software at Northern HCI Solutions.