Thursday, September 9, 2010

Rock Hopping

The river is wide, its waters treacherous. On the bank stands a man -- a rock-hopper -- who wants to get over to the other side. In the river, scattered randomly, are a huge number of flat-topped boulders, spaced just close enough to each other that the rock-hopper knows he can leap from one to another.

He starts out, leaping from rock to rock, focusing his full might on the effort. Going left, and right, he manages to get from rock to rock without falling into the currents. In the end, he leaps off the last rock squarely onto the bank and proclaims victory; only to realize a moment later that he has landed right back onto the same bank from which he started.

Leaping from rock to rock is a tactical challenge. It is a short-term effort focused squarely on getting to the next rock. Getting to the other bank however, is a strategic challenge, it involves the longer term effort of picking the right path through the rocks. It often requires picking harder leaps, since the easier path may just lead back to the same bank.

What I often see with people is that they become so hyper-focused on the tactical challenges, that they completely ignore the strategic ones. It happens in every profession, we hear plenty of stories about how business people for example, walk away with huge performance bonuses only to have the company die from neglect shortly after. It is far easier to concentrate on the short term, and it is far easier to proclaim success.

But software development is not entirely about writing lots and lots of code. Sure that is the tactical side, but the strategic side is getting the right code to the right people, release after release. Its not just getting it started, but also keeping it going. All software projects, even the small ones, span years and they need continual effort to keep them working and viable. Pointed in the right direction. Winning a tactical battle doesn’t help if the overall strategy loses the war. Short term wins help, but real success comes from the long term.

In software development, we see this in several places. The first is in many people’s belief that the project will work, if and only if they can write enough code. Code is nice, but as it builds up, if it is sloppy and redundant it becomes harder and harder to manage. It’s not how much code we have, it’s how easily we can leverage it that really matters. Development projects should get easier as time rolls on. The momentum should speed up, not down. Rewriting “nearly” the same code again and again, a hundred times over, is wasted effort.

Often though, the reasons why we have so much redundancy in our code, is that people frequently make the tactical choice to not leverage what they have out of fear that it will slow them down. If the first version is somewhat independent of the second version, and you’ve written it once already, many choose to just re-write another version. They hop to the closest rock, without consideration for their final destination. Too many of these hops, and they wind up on the wrong bank.

Another place we see this is with functionality. A hundred quirky little cloned applications spreads more misery than assistance. A fractured, convoluted app that needs months of training is no better. At the user level, the things we build need to be integrated, and they need to have enough of a common philosophy that using them doesn’t require any more than a basic intuitive understanding. All the functionality in the world doesn’t matter if it’s hard to find, or not easy to use.

Still, we see programmer after programmer get the task of adding in some new feature, only to ignore what is already there in their rush to get it done quickly. It may initially look good that they only spent a few months on the effort, but when it hits the users and the complaints start rolling in, it gets harder and harder to justify the cut corners. What seems like a successful new feature, can often leave the developers back on the bank where they started.

Another instance of this comes directly from analysis. I’ve heard so many programmers over the years complain about how the requirements keep changing. A software tool automates something for the users, and often supplies data for management, but it generally does little else. The tasks being automated, in most domains have a long history. Normally there were users doing their work long before computers came onto the scene. Computer systems do cause change, but more often accidentally than by deliberate thought. So, most often, the changes in the requirements are not coming from changes in the domain; sure there are always some, but they do not account for the vast majority. The changes in the requirements more often come from rushing forward too quickly, before the full scope of the problem or technology is understood. They come from the lack of analysis into the real underlying problems that need to be solved. They come from short-cuts. They come from both technical debt, and from analysis debt.

Software developers, in our senior roles, like architects, designers and team leads are the experts in building software systems. We can’t expect the users to fully grasp the technical problems, or the complexities. We can’t leave it up to them to set the engineering schedules, or map out the most reasonable order to implement the code. Sure, we need to value what they say, but they hired us to be the experts, and it is our responsibility to insure that the system is up and functioning properly. That it is usable. Frequently changes in the requirements, particularly urgent ones that have not been noticed previously, are our fault, not theirs. It’s not their fault if they can’t express what they need in our lingo, using our methodologies. It is our fault that we didn’t ask the right questions, that instead we accepted the easy answers in a rush to move forward. Developers become so focused on hoping off the analysis rock that they often forget to head in a strategic direction. If the code is ready before the problem is understood, then it is unlikely to work properly.

This leads to the most significant problem of all. Software development isn’t about code or technical problems. It’s really all about people, and making their lives better in some way. Inexperienced programmers often want to hide out from their users, and hyper-focus only on the code. That is OK, but if they choose that option, then they need someone on the bank helping them with direction. And they need to listen. Someone has to look after the strategic direction, and learning to do that properly comes only from experience. Lots of experience. It doesn’t come from a couple of years of writing neat algorithms, nor does it come from a decade of constructing pretty screens. It only comes from getting down off the chair, and taking responsibility for the scope and direction of the project. From fighting it out, time and again. It’s a long and slow process. Computers are nice, polite, happy machines, people aren’t. But the real problems in software -- the ones that often mean the difference between success and failure -- are not technical. And managing those problems isn’t something that is learned overnight.

Our industry grossly over-values rock-hoppers, particularly the hyper-focused ones. There is too much emphasis on getting it done as soon as possible, and not enough on getting to the other bank. If we have an obscenely high failure rate, it is mostly because we still haven’t learned how to identify the necessary strategic skills needed for success. Anyone can build code. Literally anyone. It’s not a pile of code that matters, it’s what people can do with it that is the key. Returning to the same bank after an exhaustive effort is not only frustrating, but also a waste of time.

We’re faced with wide rivers everyday. It doesn’t matter how many rocks we hop, or how elegantly we do it, if we can’t get to the other bank.  Real success comes from the long term.