Friday, August 07, 2009

The Invisible, Undocumented Hack Which Was Nearly My Undoing

- In which Curtis reverse-engineers the good intentions of someone very familiar
"The best underlings will skim a little. If they're not taking a little, they're taking a lot. And if they're not taking a lot, they've got an angle, and they're dangerous." - Mob saying

I am not the type to take psychological baggage from work home with me, but a particular project has been my bane now for a couple of months, and I have taken to rambling about it at home. I have been fretting about it so much lately, that my dear wife has taken to asking me how work was, which she was never previously inclined to do. The problem? A well-meaning programmer at a vendor put a few undocumented hacks into some code to help us a few years ago, and then left his company.

With names changed to protect the innocent, we'll say that I am the translator, the messaggero, if you will, between internal mafia bosses, and external contract killers. It's a dirty world we live in, friends. A dirty world. The mob system keeps its books in an internal database that we'll call "Corleone". The contract killers keep track of their info in a system we'll call "assassi-net".

When somebody doesn't pay up, or insults a boss, Corleone sends me an xml message with who to clip, where they are located, and a unique identifier for the request that, for lack of a better term, we'll call a "ticket number". I, in turn, take the request and reformat it to data that assassi-net can read, and then I open a "ticket" with assassi-net, and give the return info to Corleone, including their ticket number, and which hitman is assigned.

As the hit progresses, assassi-net can update me with changes in the target status ("tracking", "found", "killed", what have you) or send free-form comments ("target has diamonds in safe, are they spoken for?", "tight security, need funds for janitor costume", etc.) I take those comments and format them to Corleone-friendly data, and pass them off to the internal database.

I say "I" here out of habit, referring to what my code does, but in reality I had nothing to do with the original implementation of this project. I was brought on when assassi-net was being updated to a new version that made tracking easier on their side. We needed to change SOAP addresses slightly, modify the xml format to contain new fields, and split full names into first and last names. It seemed easy, so I dove in, caution to the wind, and started my month-long fight with another man's code. The problems I ran into can be summed up easily:

- The integration code I was responsible for was over-engineered to hell and back. It was more spaghetti than even a Capo di tutti capi could eat in a sitting.
- Mafia code doesn't log anything, presumably as a hedge against FBI raids, or general abidance of the omertá code.
- The old mob programmer is "sleeping with the fishes", and the new guy hadn't learned the system yet.
- Assassins do a lot of things under the table that they don't tell anyone about.

The integration code was, to put it mildly, a disaster of Highlander 2 proportions. That was nasty business that I won't go into detail about. I mentioned it in passing a couple times at home, assuming that would be the end of it. Soon thereafter, we entered testing.

Testing with the two end points brought to light some surprise issues, undocumented requirements, a couple instances where I guessed the wrong meaning of an ambiguous statement in the docs - that's all normal and expected, and it's why we test. Neither end point had a clear understanding of how the other system worked, or when joined, how the beast with two backs would behave - again, that's expected. The art of integrating systems is in getting the big picture, presenting the anomalies to both sides, and either waiting patiently while they duke it out, or proposing clever fixes for them, depending on your capabilities and temperament.

After testing and fixing everything we thought was broken, we deployed the new code to production. Immediately, an end-user noted a problem: we aren't getting the assissi-net ticket number back to Corleone like we used to. This is something the mob programmer should have caught during testing, but as I said, he was new. I looked at the old integration code, and if assassi-net said anything after a new ticket was entered, we ignored it. And yet, Corleone previously received the return ticket number instantly. We determined that the old version of assassi-net immediately called our status update service, a feature that was undocumented, and only performed for us, not for other assassi-net subscribers. So I coded a quick hack to simulate that under the new "skin". I took the return ticket number, and called my own update service with it. Easy fix, but I was irked that this requirement was never mentioned or tested for.

The next day, we found that the people identified as the "requester" and "contact" for the Corleone ticket were seemingly switched on the assassi-net side. After troubleshooting, we found that the tickets were created the same way as before, and those fields were sent the same way, but the hitmen had different definitions of what a requester and contact were than we did. The old version of assassi-net silently swapped those fields, and again, only for us, not for any other subscriber. So I coded another quick hack to switch those before we called the contract killers' service, imitating what they used to do.

And something similar happened two more times. Corleone tickets stopped being closed if they had large comments, and old assassi-net used to truncate the field, but no longer did. Corleone stopped receiving comments that weren't associated with a status change, and the previous version of assassi-net called both the status change and ticket update services before, but now only called one or the other.

And so we fixed, and re-tested, and moved the patch into production. For all four of these problems. I built a mental model of the assassi-net programmer, now long since wearing cement shoes, who thought he was being helpful. He was very familiar: he was me about 10 years ago. He fixed several small hurdles by coding patches into his system only for us, and not documenting them. It was much easier, I can only assume, for him to write code to fix an anomaly and deploy it under the table, than it would have been to bring both parties to a sit-down so the beef could be straightened out.

That's what they get for hiring crumbs, though, instead of men of honor. Freakin' hitmen. Vaffanculo, testa di cazzo!! ...ok, maybe that's a little unfair. I'm not really that upset at the whole ordeal, and the old coder that caused all my problems by not documenting what he was fixing, or why, or getting permission to do so - he's exactly like I used to be. Have I ever mentioned cprocess?

Back in the day, I worked at Sterling Commerce, and supported a piece of software called Gentran:Director. It was a Windows program that translated EDI data into printable documents, and displayed data entry forms that it turned into EDI data to be sent to other people. Nice idea, tolerably well executed, but it had problems with certain types of common data.

It required that each "segment" of data have a printable "terminator" character before it could translate it. And it could only create data with printable segment terminator, and could only format it to one segment per line. Different networks and EDI software create and expect data in slightly different formats, for example a linefeed every 80 characters, or one segment per line with no segment terminator.

To handle all these different requirements, Gentran had a feature called a "pre-processor" and a "post-processor" that would run a program on the data to reformat it to a few of the common data layouts. The program they created to be called by the pre/post-processors was called "xprocess". It was usable, but it was very slow if you had a lot of data, and there were a few common requirements it just couldn't handle, like multiple search and replaces, and building headers and trailers for a file. I attempted to parlay with the xprocess developers to get them to make their program better, but was alternately scoffed at and told that it wasn't broken. Not yet being good at making a case to developers or management, I let the issue drop.

Xprocess caused me a lot of support headaches, and I had just finished reading "Teach Yourself C in 21 Days", so I decided to write my own version, cprocess, or "Curtis's post-processor" as a coding experiment. To my surprise, it ran an order of magnitude faster than xprocess. It could handle more flexible search/replaces, multiple search/replaces on the same commandline, deletes, header/trailer creation, inserting linefeeds every so many characters, other features that I can't remember. After getting a working version I trusted, the next time I had an xprocess problem on a call, I emailed cprocess to a customer. And he used it. And he was happy.

Now, I wasn't a programmer then. I was a tech support guy. Creating cprocess was by no means sanctioned by Sterling, it was my brazen cockiness and desire to create a helpful solution to some tricky problems (and to show up the developers that dismissed me when I went to them for help) that brought cprocess into being. I didn't end up getting "found out" and disciplined (or fired, or sued), although management eventually learned of the program's existence. To enhance its legitimacy, I wrote a user's guide, trained other tech support people on its use, wrote in versioning so I could tell if a user had this or that enhancement. As I became a better programmer, I re-wrote it from scratch as "cpr2", faster, with more features, and continued mailing it out to any customer that ran into an xprocess hiccup. By the time I left Sterling, it was possibly on 100 customers' machines.

Anyway, I can't be too mad at the guy who caused me these current headaches, because he's exactly who I used to be. We eventually untangled all the Corleone/assassi-net problems, and now contract killing is operating smoothly and well-documented. And I've kept myself employed and looking competent and useful in the eyes of the bosses. That's my angle.

No comments:

Post a Comment