The Debugging Tool

When Allan C's company, Initrode, got acquired by Initech a few years ago, it sounded like actually good news for the rank and file employees. Initech had a product in the same line of business as Allan's employer, and it was better in most ways, at least according to customer feedback. Allan's team had built some features into their product that Initech wanted, and Initech was also looking to grow rapidly, so there was no fear of layoffs. In fact everybody got a mild raise, and only a few middle managers were asked to leave the company.

That's about where the good news ended.

Initech built their product in JavaScript, but they had frozen their codebase on a version of the JavaScript runtime from the early 2000s. For Allan, who had been doing modern JavaScript for pretty much his entire career, this was like going back to stone tools. The code had few attempts at modularization- some of the code had the courtesy to create its local variables in an immediately invoked function expression, which was how one did modules before modules existed, but most of the code just slapped variables and functions into the global namespace and hoped for the best.

That made the code difficult to debug, as there were loads of unintended side effects- side effects that frequently resulted in exceptions. Fortunately, all the exceptions were caught… somewhere. Frequently they were caught, handled, then a new exception was thrown with a different error message.

Now, that might sound like it makes it difficult to understand the causes of exceptions, as if you're throwing entirely new exceptions, you're destroying the stack trace information. But you have to remember this was a JavaScript was an antique: exceptions didn't have stack trace information.

Also making things difficult to debug: there wasn't a debugger. Your solution to tracing through the code was putting a lot of print statements into it, and trying to understand the output.

One day, while bashing his head up against a particularly thorny bug and wishing for some sort of useful stack trace information, Allan had an idea. Since all the important functions were already in the global namespace, it wouldn't be hard to write some JavaScript that wrapped every function with some debugging and tracking behavior. Since the runtime didn't provide a stack trace, he could wrap every function and build a stack trace as they were invoked. And when an error happened, he could log it at the level where it happened, and not need to put print statements everywhere.

As solutions go, it was cumbersome and hacky, but it was better than anything else Allan had available to him. The thorny bug that Allan was fighting with became trivial to fix once he could see the stack trace and the source of the errors.

In coffee-maker and water-cooler conversations, Allan hinted at his great new tool, but no one else expressed any interest in what he was working on. So, he plotted out a demo. He created a simulated use case- he inserted a bug into a module that he thought would be difficult to find. He ran the code, and got an error message: "Found an error in the column module foo".

"Great," Allan said. "So how would we track this error down?" Allan was feeling pretty clever at this moment, as there were dozens of "column module" types, so tracking down the actual source would be rather difficult.

Gary, the original architect of the code base and resident curmudgeon said, "Just search through the code base for the error message."

Allan felt stupid- he hadn't planned for that specific solution. He hadn't considered that the error message might be unique enough to find a specific file. Unfortunately, the first result was the file he'd modified. "Uh, yeah, let's… um… check that."

Allan added a print statement to the file. If Gary had found the bug, it would print a "Found it!" message, and no one would ever want to use Allan's tool. Allan re-ran the program. The "Found it!" message didn't appear.

Everyone was shocked, especially Allan. Gary was wrong? But so was Allan? There was only one way to figure out what was really going on: use Allan's debugging tool. He loaded up the tool, re-ran the program, and within seconds was able to pinpoint exactly what was going on.

While their search had turned up the first instance of "Found an error in the column module foo", there were several more. As it turned out, the place where Allan had inserted the bug was actually in "Column Module Bar"- which itself was just a copy/paste of "Foo", with minor modifications.

Allan was overjoyed. For a moment, his demo teetered on the edge of catastrophe, and then his own errors highlighted how easy it was to make mistakes in this codebase, and how quickly his tool could help diagnose them. He highlighted the line containing the bug, and waited for the accolades from the team for being so very, incredibly clever.

"Maybe," Gary said, "instead of wasting time with your tool, we should just fix the error message." He typed for a few moments, and then said, "There. Pushed a fix. Can we get back to work now, or do you have more ways to waste our time?"

It was at that moment Allan realized the code wasn't accidentally terrible, it was intentionally terrible. It was the way it was because Gary wanted it that way, and Gary wasn't going to let it be any better than it was, no matter what Allan did.

Allan was the first of the Initrode team to abandon ship, but he wasn't the last. And once the first wave of experienced, senior talent started jumping ship, things quickly got worse for everyone remaining, and they jumped ship too. Within a year, everyone was gone except for Gary and a pile of junior developers too inexperienced to know how bad their working environment was.

Allan's debugging tool is likely still somewhere in their source control repository, collecting digital dust, and waiting for one of those junior developers to discover it.

[Advertisement] ProGet’s got you covered with security and access controls on your NuGet feeds. Learn more.

This post originally appeared on The Daily WTF.

Leave a Reply

Your email address will not be published. Required fields are marked *