Recently at work, I was voluntold to update an application to include a feature needed to support a new business offering. It was a fairly simple app that ran as a Windows service and essentially managed other applications so that they could be treated as services without having to be such. It also allowed for communications with a manager application which could get status updates from the service and interact with the applications it managed. There were other aspects to the app, but they aren’t relevant to this story.
What is relevant is that the app was written in C initially, over a decade ago, and had some small enhancements/bugfixes added in C++ since. But no one had even looked at the code in more than five years, and I don’t think there were any changes in it for the last seven or so (we’ve changed version control systems in the meantime, so I’m not completely sure I have the full history).
And of course, this was supposed to be an as-brief-as-possible interruption in other time-sensitive work I had to do.
So I dug in, tried to remember my college C/C++, and worked to understand what was going on. I found a unit testing framework supported within Visual Studio and was even able to start writing some tests against it. In the end, I was able to add the features that were needed, fix some existing bugs, and set the stage to bring the app to a point of maintainability (maybe even porting to a language someone in the group knows!).
That code is was the first time since AppleBASIC in high school that I’d seen GOTO used unironically.
I was lucky. One of the people who had worked on the app was still with the company. Even better, he was completely willing to say the app had issues and supported fixing them. It was kinda fun, and we got everything implemented in a very short timeline.
Then the team I was on started asking a couple of questions on how to get this integrated into our deployment process (the enhancements would require a monitoring application to be deployed alongside it where one did not use to be needed), and that’s when the bottom fell out.
It turns out this app is the lynchpin to how our administrators manage practically every custom application on every server in our network. And the last time there was a change (five years ago), something broke their ability to do that. So they were very leery of any future changes. To the point where they’d taken a snapshot of the last version of the executable they liked and had that installed outside the normal deployment process, so it couldn’t be broken again. Like I said, very leery.
They had a good point; I was changing code to support a specific business program, but impacting a core administration utility. That’s not a small thing.
Especially when there’s no unit or functional tests for the app, and I don’t have certainty of which version of the code was used to build the executable our administrators have been using for years, so I can’t rebuild it or write tests against it to verify my changes don’t break anything.
Over time, we were able to smooth ruffled feathers and accommodate the concerns of all parties, and I think we’ll still be able to get to an actually-maintainable app. But it was a reminder to me:
- Code that’s objectively bad and not-ready-for-prime-time may not only be in production, it can be mission-critical.
- Don’t get distracted because it’s old and not been touched for years. All the same sensitivity to any environmental changes you have for new work applies. In fact, it’s probably worse, because odds are better that what you’re touching is being used by people who have no idea they’re using it or why, so asking the right questions may not give you the right answers.
- If they think you fixed it, you own it. So you’d better actually fix it. More importantly, you’d better fix it in a way you can build on later. Test suites are your friend, again.
(Don’t get me started on updating the Java monitor application that also needed to be enhanced and hadn’t been touched in over a decade…)