An ultra quick post this week, because I don’t have time to write a longer one.
It’s a bit of a blast from the past, so hold on to your socks, because I’m about to talk about Visual Basic 6.
A Necessary Evil
VB6 is the king (queen?) of legacy apps, at least in the desktop space.
It really does seem like no matter which company you’re working for, they probably have a chunk of VB6 somewhere, and its likely to be doing something critical to the business. It was originally written years and years ago, its been passed through many different hands and teams over time and for whatever reason, it was never successfully replaced with something more modern and sustainable. Maybe the replacement projects failed miserably, maybe there was just no motivation to touch it, who knows.
For us, that frequently encountered chunk of VB6 has taken the form of our most successful and most profitable piece of software, so we kind of have to care. Sure, we’re literally in the middle of replacing said software with a SaaS offering, but until every single client has moved to the new hotness, the old application has to keep on trucking.
As a result, sometimes my team has to write VB6. We don’t like it, but we’re pragmatists, and we don’t do it all the time, so no-one has tried to burn the office down. Yet.
Its mostly bug fixes at this point (because all new code in this particular app is written in .NET, executed via structured events over COM), but sometimes we do augment existing features as well.
With the prelude out of the way, its time to get to the meat. We hit a nasty issue recently where every time we tried to compile the source it would fail with an out of memory error.
This wasn’t something as simple as “oh, just give the machine more memory” either, this was “the machine has plenty of memory, but the VB6 compiler has no more addressable space because its a 32-bit app”.
Please Sir, No More
Our most recent change (which was still on a branch, because while we might be writing VB6, we’re not savages) was to fold in some reusable component libraries to the main project. We weren’t using them anywhere else (and had no plans to ever use them anywhere else) and the nature of the libraries was making it difficult to debug some of the many crashes afflicted on our users each day, so it seemed like a no brainer.
Of course, we didn’t know that folding those components in would tip us over into the land of “no compilation for you”.
All told we have something like 300K lines of VB6 code, spread across many different forms, modules and classes. That really doesn’t seem like enough to cause memory issues, until we release that that number only described how many lines of code are present in source control.
Something tricksy was afoot.
Hot Code Injection
It turns out that because error handling and reporting in VB6 ranges from “runtime error 13” to “hard crash with no explanation”, the application made use of a third party component to dynamically augment the code before the realcompilation.
Specifically, unless you tell it not to, it goes through every single function and injects a variety of things intended to give better error output, like stack traces (well function pointers at least) and high level error handling for unexpected crashes (which we used to send error reports to our ELK stack). Incredibly useful stuff, but it results in a ridiculous increase to the total lines of code in play.
This is why the compiler was running out of memory. That solid 300Klines in source control was quickly ballooning into some number that the compiler just could not handle.
The solution? Go find some pointless, unused code and cut it out like a cancerous tumour until the compilation worked again. Its win-win, the codebase gets smaller, you get to compile again, everyone is happy.
Of course, you have to be really careful that the code is actually unused and not just misunderstood, but the static analysis in VB6 is passable at finding unused module level functions, so we located a few of them, nuked them from orbit and moved on with our lives.
I’ll be honest, the situation (and solution) above doesn’t exactly leave me with a warm fuzzy feeling in my heart. I’m sure we’ll run into the exact same problem at some point in the future, especially if we fold in any other components, but I have to contrast that unsettling feeling with the fact that our path is more likely to result in lessVB6 over time (and more .NET), until eventually the application dies a good death.
More generally, its a shame that the VB6 code you tend to find in the wild is a bit……special. Its not a terrible language (for its time), and its certainly not impossible to write good VB6 (well factored, following at least some modern software development practices), its just so easy to do it badly. With its low barrier to entry and how easy it was to create a desktop application, it was the perfect hotbed for all sorts of crazy, long lasting insanity.