Lessons from Maps and Old Code

Taking over someone else’s code is hard. There is probably no better look at how a person thinks than looking at their code. It can be tempting to trash their code and start from scratch. This temptation often runs into conflict with a sunk-cost fallacy that says “The previous person spent so much time on this that they had to understand the problem far better than me and maybe my time would be best spent learning from their code.” The really tough part about this is that it’s not always a fallacy.

My own encounter with this dilemma came early in my career – early enough that the code in question was written in AML. The company I worked for at the time had just transferred me to the offices of a large water utility to take over the development of their cartographic production system from a developer who had recently moved on. I had never met this developer and he was already gone, so I only had his code to work from.

For the most part, the system he’d built worked well. It used ARC/INFO form menus around ArcEdit in ArcPlot mode to provide a fairly workable GUI for the GIS analysts who were slowly converting the utility from manual cartography to digital. There was a decent framework for exposing new functions to the analysts. They had two main problems. The first was that they still needed to go to the ArcEdit command-line to perform tasks that were not exposed through the GUI. The customer (their boss) viewed the command-line as a Wild West scenario that analysts should never be allowed to access.

The solution in this case was simple. I gave them access to a white-listed command-line that only allowed functions that weren’t already available through the GUI. We logged everything they did at the command-line and, each week, promoted the most common ones to the GUI and updated the white-list.

The second problem was more vexing. The utility used a lot of custom symbols and their system maps were not technically as-builts, so they digitized water mains down the street centerline. Where there were hyrdants, the hydrant symbol was to be rotated to be perpendicular to the water main line segment, pointing to the side of the street on which it could be found.

In order to speed digitizing, the analysts captured two points for each hydrant. The first was the actual location of the hydrant, snapped to the water line. The second was a reference point that indicated the correct side of the street. Analysts were instructed to “just click” on the correct side of the street. As a result, we had thousands of these reference points at random orientation to the hydrants that showed the correct side of the street – but the symbols still needed to be perpendicular to the segments which, obviously, were not all neatly West-East horizontal.

The previous developer, who had proven his chops with the rest of this elegant system I had taken over, had been in the middle of an implementation that attempted to overlay a quadrant and use the position of the reference point in the quadrant relative to the hydrant feature to determine the correct rotation and angle. It got it right exactly 50% of the time – the same as a RANDOM function would achieve. As a result, the utility was sinking hundreds of hours into painstakingly rotating the symbols by hand.

I spent about two weeks in the “quadrant” rabbit hole. Through AML, I knew the angle of orientation of the specific polyline segment to which the hydrant was snapped. I knew the bearing of each reference point from the hydrant feature. I had all the pieces, but I could not fine-tune the quadrant method beyond 50%.

A couple of weeks into wrestling with this, I was at lunch with the analysts, who were strenuously making the point about how much this issue was slowing their production. I was shaking my head and then I said “I know, I know. If all of the line segments had an orientation of zero, this would be so easy.”

I stared at them for a few seconds.

“I need to go.”

I spent the next hour ripping out the quadrant logic and replacing it with basic algebra. I wrote a formula that calculated the difference between the lines angle and horizontal axis, applied that difference to the reference point’s bearing and calculated the slope of the new bearing to the horizontal axis. Positive slope was the left side of the street, negative was the right side. Rotate the symbol to 90 or 270 and then apply the original offset.

By the end of the day the tests runs were flawless. The only gap was, if the reference point happened to start out at 90 or 270, the logic would fall through and those edge cases would be correct 50% of the time. This was deemed acceptable risk.

I learned a couple of things during this episode. First, the previous developer was extremely talented. The framework he had put in place was elegant and I would have set the utility back months if I had opted not to learn it and chosen instead to start over. In this case, the sunk cost was not a fallacy.

Second, the previous developer, like me and everyone else, was a fallible human. The quadrant logic was always a dead end. Because of his obvious talent, I had opted not to completely re-examine the previous developer’s approach and start over. Once I did, the solution was simple and fast.

I don’t write a lot of code anymore, but I’ve been thinking about this episode as I’ve spent a lot of time lately reading a lot of books on management, leadership, productivity, and related concepts. They were part of my recently-completed MBA and I have continued in order to be more familiar with many of the technology industry’s in-vogue management tropes.

It can be tempting to treat them each as a rinse-and-repeat template. “This is what I did to get to get my company to a giant exit and you should, too.” All of the books and stories (and the books are mostly collections of war stories) have value in the macro sense. We should certainly learn from others who have gone before, but we should not turn off our own critical thinking and seek to create a perfect fit for a template where there is not one.

The value of whatever we are attempting lies in the places where the templates don’t fit and it’s important to be able to tailor – or walk away – from someone else’s approach when it’s no longer working.